微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 基于ATMEGA16的DS1302可调万年历程序

基于ATMEGA16的DS1302可调万年历程序

时间:08-06 来源:互联网 点击:


程序:main函数:/*程序功能:DS1302实时时钟显示作者:朱波时间:2012年2月3日通信方式:3线串行通信使用说明:本程序模仿家用万年历,能够进行时间的设定时间设定方法:1.按下设置键进入设置模式2.按选择键对要设置的项进行选择3.按加一键对选择项加一4.完成全部选择后出现"please check OK!"此时按下确定键就回到时间模式备注:可以通过主函数中的宏定义进行时间设置*/#include iom16v.h>#include macros.h>#include "delay.h" #include "display.h"#include "ds1302.h"#include "key.h"#define  uchar unsigned char#define  uint  unsigned int//用于校准时间#define year 12//年份#define week 4//星期#define month 12//月#define daytime 23//日#define hour  12//小时#define minute 59//分钟#define seconds 55//秒uint time_data[7]={year,week,month,daytime,hour,minute,seconds};
//年星期月日时分秒(设置初始时间)void  main(){ int_init();//中断初始化SEI();//开启总中断LCD_init();//1602液晶初始化SCK_OUT;//对时钟进行操作将SCK设置成输出RST_OUT;//对时钟进行操作将RST设置成输出set_rtc();//设置时间hour_mode(24);//时间显示模式设定,12小时显示没有做好处理//只是注意此函数的写法while(1){read_rtc();//读取时间time_pro();//时间处理display();//显示时间}}delay.c:#include"delay.h"void delay(unsigned int ms){unsigned int i,j;for(i=0;ims;i++){for(j=0;j1141;j++);}}delay.h:#ifndef delay_h#define delay_hextern void delay(unsigned int ms);#endifds1302.c:#include iom16v.h>#include macros.h>#include "key.h"#include "display.h"#define  uchar unsigned char#define  uint  unsigned int#define SCK_CLR PORTA=~BIT(6)#define SCK_SET PORTA|=BIT(6)#define SCK_OUT DDRA|=BIT(6)#define RST_CLR PORTC=~BIT(7)#define RST_SET PORTC|=BIT(7)#define RST_OUT DDRC|=BIT(7)#define IO_CLR PORTA=~BIT(7)//IO引脚输出低电平#define IO_SET PORTA|=BIT(7)//IO引脚输出高电平#define IO_OUT DDRA|=BIT(7)//IO引脚设置为输出#define IO_IN DDRA=~BIT(7)//IO引脚设置为输入#define IO_R PINABIT(7)//IO引脚进行读取操作extern int time_data[7];uchar write_add[7]={0X8C,0X8A,0X88,0X86,0X84,0X82,0X80};//写地址(最低位为0)uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};//读地址(最低位为1)uchar table[];//用于计算void write_ds1302_byte(uchar dat)//在ds1302中写指令字节{uint i;IO_OUT;for(i=0;i8;i++)//一位一位往里写,共写8位{SCK_CLR;//开始时时序为0//先准备好数据,在给上升沿if(dat0x01)//如果数据位为1{IO_SET;//IO为1}else//如果数据位为0{IO_CLR;//IO为0}SCK_SET;//SCLK拉高开始传输数据dat=dat>>1;//移位进行下一个字节的传输(写的时候放到后面)}}uchar read_ds1302(uchar add)//单字节读{uchar i,value;//定义变量RST_CLR;SCK_CLR;//开始RET和SCLK时序为低RST_SET;//根据时序要传输命令write_ds1302_byte(add);//执行完此句后,SCLK时序到下降沿处开始读数据IO_IN;//IO设置成输入for(i=0;i8;i++)//一个字节为8位,一位一位的读{SCK_CLR;//时钟拉低开始传输value=value>>1;//读的时候放到前面if(IO_R)//读的结果如果为1{value=value|0X80;//从低位开始读取}SCK_SET;//时钟拉高结束传输}//循环结束后SCLK时序到了最后,将RST拉低RST_CLR;return value;//将数据返回  }void write_ds1302(uchar add,uchar dat)//单字节写(传递两个参数一个是地址一个是数据){RST_CLR;NOP();SCK_CLR;//开始RET和SCLK时序为低RST_SET;//根据时序开始写入东西时将RST拉高write_ds1302_byte(add);//写入地址write_ds1302_byte(dat);//写入数据RST_CLR;//根据时序,当写完东西时RST拉低} void set_rtc(void)//设置时间(初始化时间){uchar i,k;for(i=0;i7;i++)//将十进制转换为16进制{k=time_data[i]/10;//得到十位time_data[i]=time_data[i]%10;//得到个位time_data[i]=time_data[i]+k*16;//变成BCD码}write_ds1302(0x8e,0x00);//去除写保护(control寄存器)for(i=0;i7;i++)//对时{write_ds1302(write_add[i],time_data[i]);}write_ds1302(0x8e,0x80);//(wp位置1)加入写保护}void read_rtc(void)//读时钟{uchar i;for(i=0;i7;i++){time_data[i]=read_ds1302(read_add[i]);//把时钟放到数组里}}void time_pro(void)//时间处理函数(16进制转换为十进制){table[0]=time_data[6]%16;//显示秒个位table[1]=time_data[6]/16;//显示秒十位table[2]=time_data[5]%16;//显示分个位table[3]=time_data[5]/16;//显示分十位table[4]=time_data[4]%16;//显示小时个位table[5]=time_data[4]/16;//显示小时十位table[6]=time_data[3]%16;//显示日个位table[7]=time_data[3]/16;//显示日十位table[8]=time_data[2]%16;//显示月个位table[9]=time_data[2]/16;//显示月十位table[10]=time_data[1]%16;//显示星期table[12]=time_data[0]%16;//显示年个位table[13]=time_data[0]/16;//显示年十位}void hour_mode(uchar mode)//mode为12时为12小时格式,为24时为24小时格式{uint value;write_ds1302(0x8e,0x00);//去除写保护(control寄存器)if(mode==12){value=read_ds1302(0x85);//读取小时当前值value=value|0x80;       //将小时数据最高位置1write_ds1302(0x84,value);//将置1后的小时数据写入小时寄存器//变为12小时格式}if(mode==24){value=read_ds1302(0x85);//读取小时当前值value=value0x7F;       //将小时数据最高位置0write_ds1302(0x84,value);//将置1后的小时数据写入小时寄存器//变为24小时格式}}void int_init(void){MCUCR |= 0x00;MCUCSR|= 0x00;GICR  |= 0x40;}#pragma interrupt_handler int0_isr:2void int0_isr(void)//在外部中断中进行时间设置{uchar i=0,num=0,n=0,m=0,u=0,k=0,j=0,h=0;CLI();//进制中断LCD_init();//清屏showprompt();//显示提示信息write_ds1302(0x80,0x80);//时钟停止write_ds1302(0x8e,0x00);//去除写保护(control寄存器)while(!(num==4)) //num含义:1(加一),2(选择),3(设置),4(确定){  if(key_press())    //检测是否有按键按下{num=key_scan();   //扫描并返回翻译后的键码if(num==2)//进入选择状态{i++;switch(i){ case 1://设置年LCD_init();//清屏nbs设置年LCD_init();//清屏while(!(n==2))//再次按选择键就进入下个项目的设置{if(key_press()){n=key_scan();   //扫描并返回翻译后的键码if(n==1)time_data[0]++;//按一下年加一}//以下是时间微调,因为在DS1302中写入的是BCD码,所以在实际中//可以用下面的调整方式,以下只处理到60年if(time_data[0]==0x0a){time_data[0]=0x10;}if(time_data[0]==0x1a){time_data[0]=0x20;}if(time_data[0]==0x2a){time_data[0]=0x30;}if(time_data[0]==0x3a){time_data[0]=0x40;}if(time_data[0]==0x4a){time_data[0]=0x50;}write_ds1302(write_add[0],time_data[0]);//写入地址和数据time_pro();//时间处理showyear();//显示年}// break;不用终止程序,当程序跳出上边循环时,会进入下边程序case 2://月设置LCD_init();//清屏while(!(m==2))//再次按选择键就进入下个项目的设置{if(key_press()){m=key_scan();   //扫描并返回翻译后的键码if(m==1)time_data[2]++;//按一下月加一if(time_data[2]==0x13)//一年有12个月time_data[2]=1;}//BCD码处理if(time_data[2]==0x0a){time_data[2]=0x10;}if(time_data[2]==0x1a){time_data[2]=0x20;}       write_ds1302(write_add[2],time_data[2]);time_pro();//时间处理showmonth();//显示月}//break;case 3: //日设置LCD_init();//清屏while(!(u==2))//再次按选择键就进入下个项目的设置{if(key_press()){u=key_scan();   //扫描并返回翻译后的键码if(u==1)time_data[3]++;//按一下日加一if(time_data[3]==0x32)//一个月最多有31天time_data[3]=1;}//BCD码处理if(time_data[3]==0x0a){time_data[3]=0x10;}if(time_data[3]==0x1a){time_data[3]=0x20;} if(time_data[3]==0x2a){time_data[3]=0x30;}          write_ds1302(write_add[3],time_data[3]);time_pro();//时间处理showdaytime();//显示日}//break;case 4: //小时设置LCD_init();//清屏while(!(k==2))//再次按选择键就进入下个项目的设置{if(key_press()){k=key_scan();   //扫描并返回翻译后的键码if(k==1)time_data[4]++;//按一下小时加一if(time_data[4]==0x25)//一天24小时time_data[4]=1;}//BCD码处理if(time_data[4]==0x0a){time_data[4]=0x10;}if(time_data[4]==0x1a){time_data[4]=0x20;}          write_ds1302(write_add[4],time_data[4]);time_pro();//时间处理showhour();//显示小时} //break; case 5: //分钟设置LCD_init();//清屏while(!(j==2))//再次按选择键就进入下个项目的设置{if(key_press()){j=key_scan();   //扫描并返回翻译后的键码if(j==1)time_data[5]++;//按一下分钟加一if(time_data[5]==0x5a)//一小时60分钟time_data[5]=0x00;}//BCD码处理if(time_data[5]==0x0a){time_data[5]=0x10;}if(time_data[5]==0x1a){time_data[5]=0x20;}if(time_data[5]==0x2a){time_data[5]=0x30;}if(time_data[5]==0x3a){time_data[5]=0x40;}if(time_data[5]==0x4a){time_data[5]=0x50;}if(time_data[5]==0x5a){time_data[5]=0x60;}                   write_ds1302(write_add[5],time_data[5]);time_pro();//时间处理showminute();//显示分钟}  //break;case 6: //星期设置LCD_init();//清屏while(!(h==2))//再次按选择键就进入下个项目的设置{if(key_press()){h=key_scan();   //扫描并返回翻译后的键码if(h==1)time_data[1]++;//按一下小时加一if(time_data[1]==0x08)//一天24小时time_data[1]=1;}write_ds1302(write_add[2],time_data[2]);time_pro();//时间处理showweek();//显示星期} default:LCD_init();//清屏showmessage();break;} }}}write_ds1302(0x8e,0x80);//(wp位置1)加入写保护write_ds1302(0x80,0x00);//时钟开始LCD_init();//清屏SEI();}key.c:#include iom16v.h>#include macros.h>#include "delay.h"#define  uchar unsigned char#define  uintn月设置LCD_init();//清屏while(!(m==2))//再次按选择键就进入下个项目的设置{if(key_press()){m=key_scan();   //扫描并返回翻译后的键码if(m==1)time_data[2]++;//按一下月加一if(time_data[2]==0x13)//一年有12个月time_data[2]=1;}//BCD码处理if(time_data[2]==0x0a){time_data[2]=0x10;}if(time_data[2]==0x1a){time_data[2]=0x20;}       write_ds1302(write_add[2],time_data[2]);time_pro();//时间处理showmonth();//显示月}//break;case 3: //日设置LCD_init();//清屏while(!(u==2))//再次按选择键就进入下个项目的设置{if(key_press()){u=key_scan();   //扫描并返回翻译后的键码if(u==1)time_data[3]++;//按一下日加一if(time_data[3]==0x32)//一个月最多有31天time_data[3]=1;}//BCD码处理if(time_data[3]==0x0a){time_data[3]=0x10;}if(time_data[3]==0x1a){time_data[3]=0x20;} if(time_data[3]==0x2a){time_data[3]=0x30;}          write_ds1302(write_add[3],time_data[3]);time_pro();//时间处理showdaytime();//显示日}//break;case 4: //小时设置LCD_init();//清屏while(!(k==2))//再次按选择键就进入下个项目的设置{if(key_press()){k=key_scan();   //扫描并返回翻译后的键码if(k==1)time_data[4]++;//按一下小时加一if(time_data[4]==0x25)//一天24小时time_data[4]=1;}//BCD码处理if(time_data[4]==0x0a){time_data[4]=0x10;}if(time_data[4]==0x1a){time_data[4]=0x20;}          write_ds1302(write_add[4],time_data[4]);time_pro();//时间处理showhour();//显示小时} //break; case 5: //分钟设置LCD_init();//清屏while(!(j==2))//再次按选择键就进入下个项目的设置{if(key_press()){j=key_scan();   //扫描并返回翻译后的键码if(j==1)time_data[5]++;//按一下分钟加一if(time_data[5]==0x5a)//一小时60分钟time_data[5]=0x00;}//BCD码处理if(time_data[5]==0x0a){time_data[5]=0x10;}if(time_data[5]==0x1a){time_data[5]=0x20;}if(time_data[5]==0x2a){time_data[5]=0x30;}if(time_data[5]==0x3a){time_data[5]=0x40;}if(time_data[5]==0x4a){time_data[5]=0x50;}if(time_data[5]==0x5a){time_data[5]=0x60;}                   write_ds1302(write_add[5],time_data[5]);time_pro();//时间处理showminute();//显示分钟} //break;case 6: //星期设置LCD_init();//清屏while(!(h==2))//再次按选择键就进入下个项目的设置{if(key_press()){h=key_scan();   //扫描并返回翻译后的键码if(h==1)time_data[1]++;//按一下小时加一if(time_data[1]==0x08)//一天24小时time_data[1]=1;}write_ds1302(write_add[2],time_data[2]);time_pro();//时间处理showweek();//显示星期} default:LCD_init();//清屏showmessage();break;} }}}write_ds1302(0x8e,0x80);//(wp位置1)加入写保护write_ds1302(0x80,0x00);//时钟开始LCD_init();//清屏SEI();}key.c:#include iom16v.h>#include macros.h>#include "delay.h"#define  uchar unsigned char#define  uint  unsigned intuchar key_press()//判断按键是否被按下(按下返回1,没按下返回0){  uchar j;DDRD|=0X0F;//低四位为输出PORTD|=0X0F;//低四位输出低电平DDRD=0XF0;//低四位为输入j=PIND;//读一下输入寄存器j=0X0F;//屏蔽高四位if(j==0X0F)//如果j没变化,则返回0,否则返回1{return 0;}else{return 1;}}uchar key_scan()//按键扫描函数{    uchar key;delay(10);if(key_press())//有按键按下时key_press()的值为1{key=PIND;//读取PIND值key=0X0F;//去掉高4位switch(key)//开关语句,用于判断{case 0X0E://1110连接PD0的按键按下key=1;break;case 0X0D://1101连接PD1的按键按下key=2;break; case 0X0B://1011连接PD2的按键按下key=3;break;case 0X07://0111连接PD3的按键按下key=4;break;default://都不是时随便返回一个值key=16;       }while(key_press());//在按键按下时执行完上边的程序后就执行此循环//当按键松开时就跳出循环,目的是按一下就执行一次程序}else//没有按下时随便返回一个值{key=16;}return key;}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top