DS1302驱动程序分析图
C程序 C51例子- #include <reg51.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar count_10ms; //定义10ms计数器
- sbit K1 = P3^2; //定义K1键
- sbit K2 = P3^3; //定义K2键
- sbit K3 = P3^4; //定义K3键
- sbit K4 = P3^5; //定义K4键
- sbit BEEP=P3^7; //定义蜂鸣器
- sbit reset = P1^2;
- sbit sclk = P1^0;
- sbit io = P1^1;
- sbit LCD_RS=P2^0;
- sbit LCD_RW=P2^1 ;
- sbit LCD_EN=P2^2;
- bit K1_FLAG=0; //定义按键标志位,当按下K1键时,该位置1,K1键未按下时,该位为0。
- uchar code line1_data[] = {"---LCD Clcok---"}; //定义第1行显示的字符
- uchar code line2_data[] = {"****"}; //定义第2行显示的字符
- uchar disp_buf[8] ={0x00}; //定义显示缓冲区
- uchar time_buf[7] ={0,0,0x12,0,0,0,0}; //DS1302时间缓冲区,存放秒、分、时、日、月、星期、年
- uchar temp [2]={0}; //用来存放设置时的小时、分钟的中间值
- /********以下是函数声明********/
- void Delay_ms(uint xms) ;
- bit lcd_busy();
- void lcd_wcmd(uchar cmd);
- void lcd_wdat(uchar dat) ;
- void lcd_clr() ;
- void lcd_init() ;
- void write_byte(uchar inbyte); //写一字节数据函数声明
- uchar read_byte(); //读一字节数据函数声明
- void write_ds1302(uchar cmd,uchar indata); //写DS1302函数声明
- uchar read_ds1302(uchar addr); //读DS1302函数声明
- void set_ds1302(uchar addr,uchar *p,uchar n); //设置DS1302初始时间函数声明
- void get_ds1302(uchar addr,uchar *p,uchar n); //读当前时间函数声明
- void init_ds1302(); //DS1302初始化函数声明
- /********以下是延时函数********/
- void Delay_ms(uint xms)
- {
- uint i,j;
- for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
- for(j=110;j>0;j--);
- }
- /********以下是LCD忙碌检查函数********/
- bit lcd_busy()
- {
- bit result;
- LCD_RS = 0;
- LCD_RW = 1;
- LCD_EN = 1;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- result = (bit)(P0&0x80);
- LCD_EN = 0;
- return result;
- }
- /********以下是写指令寄存器IR函数********/
- void lcd_wcmd(uchar cmd)
- {
- while(lcd_busy());
- LCD_RS = 0;
- LCD_RW = 0;
- LCD_EN = 0;
- _nop_();
- _nop_();
- P0 = cmd;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCD_EN = 1;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCD_EN = 0;
- }
- /********以下是写寄存器DR函数********/
- void lcd_wdat(uchar dat)
- {
- while(lcd_busy());
- LCD_RS = 1;
- LCD_RW = 0;
- LCD_EN = 0;
- P0 = dat;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCD_EN = 1;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCD_EN = 0;
- }
- /********以下是LCD清屏函数********/
- void lcd_clr()
- {
- lcd_wcmd(0x01); //清除LCD的显示内容
- Delay_ms(5);
- }
- /********以下是LCD初始化函数********/
- void lcd_init()
- {
- Delay_ms(15); //等待LCD电源稳定
- lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据
- Delay_ms(5);
- lcd_wcmd(0x38);
- Delay_ms(5);
- lcd_wcmd(0x38);
- Delay_ms(5);
-
- lcd_wcmd(0x0c); //显示开,关光标
- Delay_ms(5);
- lcd_wcmd(0x06); //移动光标
- Delay_ms(5);
- lcd_wcmd(0x01); //清除LCD的显示内容
- Delay_ms(5);
- }
- /********以下是写一字节数据函数********/
- void write_byte(uchar inbyte)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- sclk=0; //写时低电平改变数据
- if(inbyte&0x01)
- io=1;
- else
- io=0;
- sclk=1; //高电平把数据写入DS1302
- _nop_();
- inbyte=inbyte>>1;
- }
- }
- /********以下是读一字节数据函数********/
- uchar read_byte()
- {
- uchar i,temp=0;
- io=1;
- for(i=0;i<7;i++)
- {
- sclk=0;
- if(io==1)
- temp=temp|0x80;
- else
- temp=temp&0x7f;
- sclk=1; //产生下跳沿
- temp=temp>>1;
- }
- return (temp);
- }
- /********写DS1302函数, 往DS1302的某个地址写入数据 ********/
- void write_ds1302(uchar cmd,uchar indata)
- {
- sclk=0;
- reset=1;
- write_byte(cmd);
- write_byte(indata);
- sclk=0;
- reset=0;
- }
- /********读DS1302函数,读DS1302某地址的的数据********/
- uchar read_ds1302(uchar addr)
- {
- uchar backdata;
- sclk=0;
- reset=1;
- write_byte(addr); //先写地址
- backdata=read_byte(); //然后读数据
- sclk=0;
- reset=0;
- return (backdata);
- }
- /********设置初始时间函数********
- void set_ds1302(uchar addr,uchar *p,uchar n)
- {
- write_ds1302(0x8e,0x00); //写控制字,允许写操作
- for(;n>0;n--)
- {
- write_ds1302(addr,*p);
- p++;
- addr=addr+2;
- }
- write_ds1302(0x8e,0x80); //写保护,不允许写
- }
- ********读取当前时间函数********
- void get_ds1302(uchar addr,uchar *p,uchar n)
- {
- for(;n>0;n--)
- {
- *p=read_ds1302(addr);
- p++;
- addr=addr+2;
- }
- }
- ********初始化DS1302函数********/
- void init_ds1302()
- {
- reset=0;
- sclk=0;
- write_ds1302(0x80,0x00); //写秒寄存器
- write_ds1302(0x90,0xab); //写充电器
- write_ds1302(0x8e,0x80); //写保护控制字,禁止写
- }
- /*********以下是蜂鸣器响一声函数********/
- void beep()
- {
- BEEP=0; //蜂鸣器响
- Delay_ms(100);
- BEEP=1; //关闭蜂鸣器
- Delay_ms(100);
- }
- /********以下是转换函数,负责将走时数据转换为适合LCD显示的数据********/
- void LCD_conv (uchar in1,in2,in3 )
- //形参in1、in2、in3接收实参time_buf[2]、time_buf[1]、time_buf[0]传来的小时、分钟、秒数据
- {
- disp_buf[0]=in1/10+0x30; //小时十位数据
- disp_buf[1]=in1%10+0x30; //小时个位数据
- disp_buf[2]=in2/10+0x30; //分钟十位数据
- disp_buf[3]=in2%10+0x30; //分钟个位数据
- disp_buf[4]=in3/10+0x30; //秒十位数据
- disp_buf[5]=in3%10+0x30; //秒个位数据
- }
- /********以下是LCD显示函数,负责将函数LCD_conv转换后的数据显示在LCD上********/
- void LCD_disp ()
- {
- lcd_wcmd(0x44 | 0x80); //从第2行第4列开始显示
- lcd_wdat(disp_buf[0]); //显示小时十位
- lcd_wdat(disp_buf[1]); //显示小时个位
- lcd_wdat(0x3a); //显示':'
- lcd_wdat(disp_buf[2]); //显示分钟十位
- lcd_wdat(disp_buf[3]); //显示分钟个位
- lcd_wdat(0x3a); //显示':'
- lcd_wdat(disp_buf[4]); //显示秒十位
- lcd_wdat(disp_buf[5]); //显示秒个位
- }
- /********以下是按键处理函数********/
- void KeyProcess()
- {
- uchar min16,hour16; //定义16进制的分钟和小时变量
- write_ds1302(0x8e,0x00); //DS1302写保护控制字,允许写
- write_ds1302(0x80,0x80); //时钟停止运行
- if(K2==0) //K2键用来对小时进行加1调整
- {
- Delay_ms(10); //延时去抖
- if(K2==0)
- {
- while(!K2); //等待K2键释放
- beep();
- time_buf[2]=time_buf[2]+1; //小时加1
- if(time_buf[2]==24) time_buf[2]=0; //当变成24时初始化为0
- hour16=time_buf[2]/10*16+time_buf[2]%10; //将所得的小时数据转变成16进制数据
- write_ds1302(0x84,hour16); //将调整后的小时数据写入DS1302
- }
- }
- if(K3==0) // K3键用来对分钟进行加1调整
- {
- Delay_ms(10); //延时去抖
- if(K3==0)
- {
- while(!K3); //等待K3键释放
- beep();
- time_buf[1]=time_buf[1]+1; //分钟加1
- if(time_buf[1]==60) time_buf[1]=0; //当分钟加到60时初始化为0
- min16=time_buf[1]/10*16+time_buf[1]%10; //将所得的分钟数据转变成16进制数据
- write_ds1302(0x82,min16); //将调整后的分钟数据写入DS1302
- }
- }
- if(K4==0) //K4键是确认键
- {
- Delay_ms(10); //延时去抖
- if(K4==0)
- {
- while(!K4); //等待K4键释放
- beep();
- write_ds1302(0x80,0x00); //调整完毕后,启动时钟运行
- write_ds1302(0x8e,0x80); //写保护控制字,禁止写
- K1_FLAG=0; //将K1键按下标志位清0
- }
- }
- }
- /********以下是读取时间函数,负责读取当前的时间,并将读取到的时间转换为10进制数********/
- void get_time()
- {
- uchar sec,min,hour; //定义秒、分和小时变量
- write_ds1302(0x8e,0x00); //控制命令,WP=0,允许写操作
- write_ds1302(0x90,0xab); //涓流充电控制
- sec=read_ds1302(0x81); //读取秒
- min=read_ds1302(0x83); //读取分
- hour=read_ds1302(0x85); //读取时
- time_buf[0]=sec/16*10+sec%16; //将读取到的16进制数转化为10进制
- time_buf[1]=min/16*10+min%16; //将读取到的16进制数转化为10进制
- time_buf[2]=hour/16*10+hour%16; //将读取到的16进制数转化为10进制
- }
- /********以下是主函数********/
- void main(void)
- {
- uchar i;
- P0 = 0xff;
- P2 = 0xff;
- lcd_init(); //LCD初始化函数(在LCD驱动程序软件包中)
- lcd_clr(); //清屏函数(在LCD驱动程序软件包中)
- lcd_wcmd(0x00|0x80); //设置显示位置为第1行第0列
- i = 0;
- while(line1_data[i] != '\0') //在第1行显示"---LCD Clcok---"
- {
- lcd_wdat(line1_data[i]); //显示第1行字符
- i++; //指向下一字符
- }
- lcd_wcmd(0x40|0x80); //设置显示位置为第2行第0列
- i = 0;
- while(line2_data[i] != '\0') //在第2行0~3列显示"****"
- {
- lcd_wdat(line2_data[i]); //显示第2行字符
- i++; //指向下一字符
- }
- lcd_wcmd(0x4c|0x80); //设置显示位置为第2行第12列
- i = 0;
- while(line2_data[i] != '\0') //在第2行12列之后显示"****"
- {
- lcd_wdat(line2_data[i]); //显示第2行字符
- i++; //指向下一字符
- }
- init_ds1302(); //DS1302初始化
- while(1)
- {
- get_time(); //读取当前时间
- if(K1==0) //若K1键按下
- {
- Delay_ms(10); //延时10ms去抖
- if(K1==0)
- {
- while(!K1); //等待K1键释放
- beep(); //蜂鸣器响一声
- K1_FLAG=1; //K1键标志位置1,以便进行时钟调整
- }
- }
- if(K1_FLAG==1)KeyProcess(); //若K1_FLAG为1,则进行走时调整
- LCD_conv(time_buf[2],time_buf[1],time_buf[0]); //将DS1302的小时/分/秒传送到转换函数
- LCD_disp(); //调LCD显示函数,显示小时、分和秒
- }
- }
复制代码 |