基于STC89C52的DS1302应用

来源:互联网 发布:js属于什么语言 编辑:程序博客网 时间:2024/04/20 09:34

/*******************************基于DS1302时钟芯片万年历***************************/
/******************************************************************************
*  Copyright (c) 2009,雲塘隱士東瓜电子工作室

*            All rights reserved.

* 摘 要:    万年历:前两位显示分钟,后两位显示秒,
           硬件连接:
                     1.P0口连接到4位数码管的数据端
                     2.四个数码管的位码口定义
                       小时:        sbit P10 = P1^0;      
                                     sbit P11 = P1^1;
                       分钟:        sbit P12 = P1^2;
                                     sbit P13 = P1^3;
                     3.功能按键
                       模式选择键:   sbit Mode = P2^0;     
                       上调键:       sbit UP   = P2^1;     
                       下调键:       sbit DN   = P2^2;     
                     4.显示调节时按键指示 
                       调时显示:    sbit led1 = P2^3;      
                       调分显示:    sbit led2 = P2^4;
                       调闹钟时显示:sbit led3 = P2^5;
                       调闹钟分显示:sbit led4 = P2^6;
                     5.DS1302与MCU连接
                       DS1302时钟信号: sbit SCLK = P3^5;                                       7脚
                       DS1302数据信号: sbit DIO  = P3^6;                                        6脚
                       DS1302片选:       sbit CE   = P3^7;                                         5脚
    
           操作描述:按M键一次,进入修改小时模式,led1亮
                     按M键二次,进入修改分钟模式,led2亮
                     按M键三次,进入修改闹钟小时模式,led3亮
                     按M键四次,进入修改闹钟分钟模式,led4亮
                     按M键五次,退出修改模式
                     按UP或DN键可对小时或分钟进行修改(加或减)
           程序要点:
                    

* 文件名称: main.c
* CPU芯片:  STC89C52RC
* 主频:     11.0592MHZ

* 当前版本: 1.0
* 作 者:  云塘东瓜
* 完成日期: 2009年6月1日
* 修改时间: 2009年6月4日
* 备注:     可以修改显示数据,可以显示年月日、周、时分秒
*******************************************************************************/
#include <reg52.h>

/********************************宏定义DS1302寄存器读写地址*************************/
#define WRITE_SECOND              0x80
#define WRITE_MINUTE               0x82
#define WRITE_HOUR                  0x84
#define WRITE_DAY                     0x86
#define WRITE_MONTH                0x88
#define WRITE_WEEK                  0x8A
#define WRITE_YEAR                   0x8C
#define WRITE_TIMER_FLAG        0xC0

#define READ_SECOND                0x81
#define READ_MINUTE                0x83
#define READ_HOUR                   0x85
#define READ_DAY                      0x87
#define READ_MONTH                0x89
#define READ_WEEK                  0x8B
#define READ_YEAR                    0x8D
#define READ_TIMER_FLAG        0xC1
#define WRITE_PROTECT          0x8E
/******************************************************************************/

/*********************************宏定义定时计数器初值******************************/
#define THCO   0xee                 //定时值5us
#define TLCO   0x00
/*****************************************************************************/
 
/*********************DS1302与MCU连接脚及驱动程序中用到的累加器定义*****************/
//位寻址寄存器定义
sbit ACC_7 = ACC^7;
//管脚定义
sbit SCLK = P3^5;                   // DS1302时钟信号         7脚
sbit DIO  = P3^6;                   // DS1302数据信号         6脚
sbit CE   = P3^7;                   // DS1302片选             5脚
/****************************************************************************/

/*******************************4位数码管段码、片选及时钟变量定义*******************/
//共阴极数码管,0-9段码表
unsigned char  code Duan[]={0x3F, 0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
//四个数码管显示数值,数组变量定义
unsigned char  Data_Buffer[4]={0,0,0,0};
//秒分计时变量
unsigned char Sec = 40,Min=18,Hour=12,Day =1,Mon = 6,Week = 1,Year = 9;  
//闹铃设置变量
unsigned char Set_Sec = 5,Set_Min = 20, Set_Hour = 12,Set_Day =1,Set_Mon = 6,Set_Week = 1,Set_Year = 9;
/********************************************************************************/

/**********************************标志位定义***************************************/
//设置掉电走时标志(timer_flag_rom初始化时写入rom下次与timer_flag比较)
unsigned char timer_flag = 0x14,timer_flag_rom = 0x20;
//模式切换标志
unsigned char flag_mode = 1;
//显示时钟标志,为1时显示走时或显示调节值(与flag结合)
bit flag_timer = 1;
//设置状态标志
bit Set_flag=0;
//动态扫描时间到标志/显示走时标志位,为1时显示
bit flag=1;
//走时设定标志
bit set_timer=1;
//开启走时标志
bit timer=1;   
/****************************************************************************/

/*******************************led脚、数码管片选脚及功能设置脚定义*****************/
//四个数码管的位码口定义
sbit P10 = P1^0;  
sbit P11 = P1^1;
sbit P12 = P1^2;
sbit P13 = P1^3;
//功能按键
sbit Mode = P2^0;     
sbit UP   = P2^1;
sbit DN   = P2^2;
//led调节显示
sbit led1 = P2^3;
sbit led2 = P2^4;
sbit led3 = P2^5;
sbit led4 = P2^6;
//闹铃蜂鸣器
sbit P14  = P1^4;
/*******************************************************************************/
/**********************************十进制转换为十六进制子程序***************************/
/*****函数名称:unsigned char O_to_H(unsigned char n)
******功能:    十进制转换为十六进制
******参数传递:有,十进制数n
******返回值:  有,转换后的十六进制数
******创建时间:2009.6.1
******修改时间:
******/
/*******************************************************************************/
unsigned char O_to_H(unsigned char n)
{
    unsigned char temp1;

    temp1 =  n/10*16 + n%10;
   
    return(temp1);
}
/******************************************************************************/
/**********************************地址、数据发送子程序*****************************/
/*****函数名称:void Write1302 (unsigned char addr,dat)
******功能:    串行发送地址、数据,先发低位,且在上升沿发送
******参数传递:有,地址和数据
******返回值:  无
******创建时间:2009.6.1
******修改时间:
******/
/******************************************************************************/
void Write1302 (unsigned char addr,dat)    
{
       unsigned char i,temp;

       CE=0;                         //CE引脚为低,数据传送中止
       SCLK=0;                      //清零时钟总线
       CE = 1;                       //CE引脚为高,逻辑控制有效

       //发送地址
       for ( i=8; i>0; i-- ) //循环8次移位
       {
              SCLK = 0;
              temp = addr;
              DIO = (bit)(temp&0x01);          //每次传输低字节
              addr >>= 1;                //右移一位
              SCLK = 1;
       }
            

       //发送数据
       for ( i=8; i>0; i-- )
       {    
              SCLK = 0;
              temp = dat;
              DIO = (bit)(temp&0x01);
              dat >>= 1;
              SCLK = 1;
       }

       CE = 0;
}
/******************************************************************************/
 
/**********************************数据读取子程序*****************************/
/*****函数名称:unsigned char Read1302 ( unsigned char addr )
******功能:    串行读取数据,先发低位,且在下降沿发送
******参数传递:有,地址
******返回值:  有,读取的数据
******创建时间:2009.6.1
******修改时间:
******/
/*****************************************************************************/

unsigned char Read1302 ( unsigned char addr )

{
       unsigned char i,temp,dat1,dat2;

       CE=0;
       SCLK=0;
       CE = 1;
       //发送地址
       for ( i=8; i>0; i-- )                      //循环8次移位

       {    
              SCLK = 0;
              temp = addr;
              DIO = (bit)(temp&0x01);             //每次传输低字节
              addr >>= 1;                         //右移一位
              SCLK = 1;

       }

       //读取数据
       for ( i=8; i>0; i-- )
       {
              ACC_7=DIO;
              SCLK = 1;
              ACC>>=1;
              SCLK = 0;
       }
       CE=0;
       dat1=ACC;
       dat2=dat1/16;                           //数据进制转换
       dat1=dat1%16;                         //十六进制转十进制
       dat1=dat1+dat2*10;      

       return (dat1);
}
/*******************************************************************************/
 
/**********************************初始化DS1302子程序*****************************/
/*****函数名称:void Initial(void)
******功能:    DS1302初始化,时分秒,年月日,周,和RAM(0xC0)
******参数传递:无
******返回值:  无
******创建时间:2009.6.1
******修改时间:
******/
/******************************************************************************/
void Initial(void)
{
       Write1302 (WRITE_PROTECT,0x00);                //禁止写保护
       Write1302 (WRITE_SECOND,O_to_H(Sec));          //秒位初始化
       Write1302 (WRITE_MINUTE,O_to_H(Min));          //分钟初始化
       Write1302 (WRITE_HOUR,O_to_H(Hour));           //小时初始化
       Write1302 (WRITE_DAY,O_to_H(Day));             //日初始化
       Write1302 (WRITE_MONTH,O_to_H(Mon));           //月初始化
       Write1302 (WRITE_WEEK,O_to_H(Week));           //周初始化
       Write1302 (WRITE_YEAR,O_to_H(Year));           //年初始化

       Write1302 ( WRITE_TIMER_FLAG,timer_flag_rom);  //设置掉电走时标志

       Write1302 (WRITE_PROTECT,0x80);                //允许写保护

}
/**************************************************************/
/**********************************非走时初始化DS1302子程序************************/
/*****函数名称:void R_Initial(void)
******功能:    DS1302初始化,时分秒,年月日,周,和RAM(0xC0)
******参数传递:无
******返回值:  无
******创建时间:2009.6.1
******修改时间:2009.6.4
******/
/***************************************************************************/
void R_Initial(void)
{
       Write1302 (WRITE_PROTECT,0x00);                //禁止写保护
       Write1302 (WRITE_SECOND,0x80|O_to_H(Read1302(READ_SECOND)));          //秒位初始化
       Write1302 (WRITE_MINUTE,O_to_H(Min));          //分钟初始化
       Write1302 (WRITE_HOUR,O_to_H(Hour));           //小时初始化
       Write1302 (WRITE_DAY,O_to_H(Day));             //日初始化
       Write1302 (WRITE_MONTH,O_to_H(Mon));           //月初始化
       Write1302 (WRITE_WEEK,O_to_H(Week));           //周初始化
       Write1302 (WRITE_YEAR,O_to_H(Year));           //年初始化

       Write1302 ( WRITE_TIMER_FLAG,timer_flag_rom);  //设置掉电走时标志

       Write1302 (WRITE_PROTECT,0x80);                //允许写保护

}
/*****************************************************************************/

/**************************************主程序**********************************/
/*****函数名称:void main(void)
******功能:   
******参数传递:无
******返回值:  无
******创建时间:2009.6.1
******修改时间:
******/
/**************************************************************************/
void main(void)
{
   
    //定时器0初始化
    TMOD=0x10;                       //定时计数器1工作在方式1定时状态,5us,开中断  
  TH1=THCO;
  TL1=TLCO;
  TR1=1;
  ET1=1;
  EA=1;
    //掉电依然走时,通过DS1302中读取中ram,与设定值比较,若相同则是掉电后重启,不需再次初始化
    timer_flag = Read1302(READ_TIMER_FLAG);
    if(timer_flag==(timer_flag_rom/16*10+timer_flag_rom%16))
    {;}
    else
    Initial();   
   
    while(1)
    {
              
        if(flag==1&flag_timer==1)
        {
            flag = 0;
            if(set_timer==1)
            {  
                //显示走时
                Data_Buffer[0] = Read1302(READ_MINUTE)/10;
                Data_Buffer[1] = Read1302(READ_MINUTE)%10;  
                Data_Buffer[2] = Read1302(READ_SECOND)/10;  
                Data_Buffer[3] = Read1302(READ_SECOND)%10;
               
                if(Set_Min == Read1302(READ_MINUTE))
                    P14 = 0;
                else P14 = 1;
               
            }
            else
            {
                //显示调节时的值
                Data_Buffer[0] = Min/10;
                Data_Buffer[1] = Min%10;  
                Data_Buffer[2] = Sec/10;  
                Data_Buffer[3] = Sec%10;
            }
           
        }

        if(Set_flag==1)
        {
            //显示设定闹钟值
            Data_Buffer[0] = Set_Min/10;
            Data_Buffer[1] = Set_Min%10;  
            Data_Buffer[2] = Set_Sec/10;  
            Data_Buffer[3] = Set_Sec%10;
        }
    }
}
/****************************************************************************/

/**********************************定时计数器1定时5us溢出中断**********************/
/*****函数名称:void timer1(void) interrupt 3
******功能:  
******参数传递:无
******返回值:  无
******创建时间:2009.6.1
******修改时间:
******/
/***************************************************************************/
void timer1(void) interrupt 3
{
    //静态变量,退出程序后,值保留
    static unsigned char Bit=0;           //标记数码管片选位  
    static unsigned char count1=0;        //防抖程序计数标志
    //再次装入计数初值
    TH1=THCO;
    TL1=TLCO;

    //扫描显示控制部分
    Bit++; 
    if(Bit>=4)Bit=0;
    P1|=0x0f;     //先关位码
    P0=Duan[Data_Buffer[Bit]]; //开段码
    switch(Bit)    //送位码
    {
        case 0: P10=0;break;
        case 1: P11=0;break;
        case 2: P12=0;break;
        case 3: P13=0;break;
    }

    //功能调节按键控制部分
    if(Mode==0||UP==0||DN==0) 
    {
      count1++;
       if(count1>=30) //消抖处理
       {
         count1=0;
            //读取分与秒的值
            Min = Read1302(READ_MINUTE); 
            Sec = Read1302(READ_SECOND);
            //显示时钟标志,清零不显示走时或调节       
            flag_timer = 0;
            //开启走时标志,置1,进入调节状态,且不走时
            timer=1;
              
            if(timer==1)
            {
             
                if(Mode==0) 
          {
                    switch(flag_mode)
                    {
                        case 1: flag_mode = 2;
                                flag = 1;
                                flag_timer = 1;//显示时钟设置
                                Set_flag=0;    //不显示闹钟
                                set_timer=0;   //不显示走时
                                timer=1;       //且不走时
                                led1 = 0;
                                break;
                        case 2: flag_mode = 3;
                                flag = 1;
                                flag_timer = 1;//显示时钟设置
                                Set_flag=0;    //不显示闹钟
                                set_timer=0;   //不显示走时
                                timer=1;       //且不走时
                                led2 = 0;
                                break;
                        case 3: flag_mode = 4;
                                flag = 0;      //不显示时钟设置
                                Set_flag=1;    //显示闹钟
                                timer=1;       //不走时
                                led3 = 0;
                                break;
                        case 4: flag_mode = 5;
                                flag = 0;      //不显示时钟设置
                                Set_flag=1;    //显示闹钟
                                timer=1;       //不走时
                                led4 = 0;
                                break;
                        case 5: flag_mode = 1;
                                Set_flag=0;    //不显示闹钟
                                flag_timer = 1;
                                flag = 1;     
                                set_timer=1;    //显示走时
                                timer=0;        //不再是调节模式
                                Initial();
                                break;
                              
                        default: break;
                    }
          }
          else if(DN==0) //下调
           {
                        flag = 1;
                        flag_timer = 1;
                        Set_flag=0;
                        if(flag_mode==2)
                        {
                            flag = 1;
                            flag_timer = 1;
                           
                            Set_flag=0;
                            if(Min>0)
                                Min--;
                            else Min = 59;
                         R_Initial();
                    //禁止走时
                        }
                        else if(flag_mode==3)
                        {
                            flag = 1;
                            flag_timer = 1;
                            Set_flag=0;
                            if(Sec>0)
                                Sec--;
                            else Sec = 59;
                         R_Initial();
                    //禁止走时
                        }
                        else if(flag_mode==4)
                        {
                            flag = 0;
                            Set_flag=1;
                            if(Set_Min>0)
                                Set_Min--;
                            else Set_Min = 59;
                         R_Initial();
                    //禁止走时
                        }
                        else if(flag_mode==5)
                        {
                             flag = 0;
                             Set_flag=1;
                             if(Set_Sec>0)
                                Set_Sec--;
                            else Set_Sec = 59;
                          R_Initial();
                    //禁止走时
                         }
                          
              }
                else if(UP==0)        //上调
           {
                        flag = 1;
                        flag_timer = 1;
                        Set_flag=0;
                        if(flag_mode==2)
                        {   
                            if(Min<59)
                                Min++;
                            else Min = 0;
                            R_Initial();
                    //禁止走时
                        }
                        else if(flag_mode==3)
                        {    
                            flag = 1;
                            flag_timer = 1;
                            Set_flag=0;
                            if(Sec<59)
                                Sec++;
                            else Sec = 0;
                            R_Initial();
                    //禁止走时
                        }
                        else if(flag_mode==4)
                        {
                            flag = 0;
                            Set_flag=1;
                            if(Set_Min<59)
                                Set_Min++;
                            else Set_Min = 0;
                            R_Initial();
                    //禁止走时
                        }
                        else if(flag_mode==5)
                        {
                             flag = 0;
                             Set_flag=1;
                             if(Set_Sec<59)
                                Set_Sec++;
                            else Set_Sec = 0;
                            R_Initial();
                    //禁止走时
                        }  
          
                    }
            }
        }
    }
    else flag=1;         
}
/*****************************************************************************/

/**************************************end**********************************/