STM32实时时钟RTC按键修改时间
User文件夹下main.c
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdg.h"
#include "timerx.h"
#include "adc.h"
#include "rtc.h"
#include "12864.h"
#include "ov7670.h"
#include "usmart.h"
#include "enc28j60.h"
#include "uip.h"
#include "uip_arp.h"
#include "tapdev.h"
#include "timer.h"
#include "math.h"
#include "string.h"
#include "syn.h"
//Mini STM32开发板扩展实验21
//ENC28J60网络模块实验
//正点原子@ALIENTEK
//技术论坛:https://www.360docs.net/doc/a41753121.html,
//广州市星翼电子科技有限公司
void uip_polling(void);
void Display_Time(void);
void received_date(u8 *str);
u16 Process_date(u8 q,u8 b,u8 s,u8 g);
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
u8 t,Addres_1=10,Addres_2=1,Addres_3=168,Addres_4=192;
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
//usart_init(72,9600); //串口初始化为9600
USART3_Init(36,9600);
USART2_Init(36,9600);
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口LCD12864_InitPort(); //初始化LCD
LCD12864_Init();
//KEY_Init(); //初始化按键
RTC_Init(); //初始化RTC
// usmart_dev.init(72); //初始化USMART
EXTIX_Init();
while(tapdev_init()) //初始化ENC28J60错误
{
LCD_ShowString(3,0,"28J60 InitError!");
delay_ms(200);
LCD12864_Clr();//清除之前显示
};
uip_init(); //uIP初始化
uip_ipaddr(ipaddr, 192,168,1,10); //设置本地设置IP地址
uip_sethostaddr(ipaddr);
uip_ipaddr(ipaddr, 192,168,1,1); //设置网关IP地址(其实就是你路由器的IP地址) uip_setdraddr(ipaddr);
uip_ipaddr(ipaddr, 255,255,254,0); //设置网络掩码
uip_setnetmask(ipaddr);
uip_listen(HTONS(1200)); //监听1200端口,用于TCP Server
uip_listen(HTONS(80)); //监听80端口,用于Web Server
tcp_client_reconnect(); //尝试连接到TCP Server端,用于TCP Client while (1)
{ Display_Time();
uip_polling(); //处理uip事件,必须插入到用户程序的循环体中// key=KEY_Scan();
if(tcp_client_tsta!=tcp_client_sta)//TCP Client状态改变
{
if(tcp_client_sta&(1<<7))
{
LCD_ShowString(3,0,"接收数据:");
disp_IP();
}
else
{ LCD_ShowString(3,0,"已断开! ");
disp_IP();
}
if(tcp_client_sta&(1<<6)) //收到新数据
{
//LCD12864_Clr(); //清除之前显示
received_date(tcp_client_databuf);
tcp_client_sta&=~(1<<6);
}
tcp_client_tsta=tcp_client_sta;
}
delay_ms(1);
usart3_Receive_Process();
}
}
//uip事件处理函数
//必须将该函数插入用户主循环,循环调用.
void uip_polling(void)
{
u8 i;
static struct timer periodic_timer, arp_timer;
static u8 timer_ok=0;
if(timer_ok==0)//仅初始化一次
{
timer_ok = 1;
timer_set(&periodic_timer,CLOCK_SECOND/2); //创建1个0.5秒的定时器
timer_set(&arp_timer,CLOCK_SECOND*10); //创建1个10秒的定时器}
uip_len=tapdev_read(); //从网络设备读取一个IP包,得到数据长度.uip_len在uip.c中定义
if(uip_len>0) //有数据
{
//处理IP数据包(只有校验通过的IP包才会被接收)
if(BUF->type == htons(UIP_ETHTYPE_IP))//是否是IP包?
{
uip_arp_ipin(); //去除以太网头结构,更新ARP表
uip_input(); //IP包处理
//当上面的函数执行后,如果需要发送数据,则全局变量uip_len > 0
//需要发送的数据在uip_buf, 长度是uip_len (这是2个全局变量)
if(uip_len>0)//需要回应数据
{
uip_arp_out();//加以太网头结构,在主动连接时可能要构造ARP请求
tapdev_send();//发送数据到以太网
}
}else if (BUF->type==htons(UIP_ETHTYPE_ARP))//处理arp报文,是否是ARP请求包?
{
uip_arp_arpin();
//当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0
//需要发送的数据在uip_buf, 长度是uip_len(这是2个全局变量)
if(uip_len>0)tapdev_send();//需要发送数据,则通过tapdev_send发送}
}else if(timer_expired(&periodic_timer)) //0.5秒定时器超时
{
timer_reset(&periodic_timer); //复位0.5秒定时器
//轮流处理每个TCP连接, UIP_CONNS缺省是40个
for(i=0;i { uip_periodic(i); //处理TCP通信事件 //当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0 //需要发送的数据在uip_buf, 长度是uip_len (这是2个全局变量) if(uip_len>0) { uip_arp_out();//加以太网头结构,在主动连接时可能要构造ARP请求 tapdev_send();//发送数据到以太网 } } #if UIP_UDP //UIP_UDP //轮流处理每个UDP连接, UIP_UDP_CONNS缺省是10个 for(i=0;i { uip_udp_periodic(i); //处理UDP通信事件 //当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0 //需要发送的数据在uip_buf, 长度是uip_len (这是2个全局变量) if(uip_len > 0) { uip_arp_out();//加以太网头结构,在主动连接时可能要构造ARP请求 tapdev_send();//发送数据到以太网 } } #endif //每隔10秒调用1次ARP定时器函数用于定期ARP处理,ARP表10秒更新一次,旧的条目会被抛弃 if(timer_expired(&arp_timer)) { timer_reset(&arp_timer); uip_arp_timer(); } } } void Display_Time(void) { if(t!=timer.sec) { t=timer.sec; LCD_ShowString(1,5,"星期"); LCD_ShowString(0,3,"20"); LCD_Shownum(0,4,(timer.w_year%100)); LCD12684_Wdat(0x2d); LCD_Shownum1(timer.w_month); LCD12684_Wdat(0x2d); LCD_Shownum1(timer.w_date); switch(timer.week) { case 0:LCD_ShowString(1,7,"日");break; case 1:LCD_ShowString(1,7,"一");break; case 2:LCD_ShowString(1,7,"二");break; case 3:LCD_ShowString(1,7,"三");break; case 4:LCD_ShowString(1,7,"四");break; case 5:LCD_ShowString(1,7,"五");break; case 6:LCD_ShowString(1,7,"六");break; } LCD_Shownum(1,0,timer.hour); LCD12684_Wdat(0x3a); LCD_Shownum1(timer.min); LCD12684_Wdat(0x3a); LCD_Shownum1(timer.sec); } } void received_date(u8 *str) { u8 len; len=(u8)strlen(str); switch(len) { case 13: Addres_4= (u8)Process_date(0,(str[0]-0x30),str[1],str[2]); Addres_3= (u8)Process_date(0,(str[4]-0x30),str[5],str[6]); Addres_2=(u8)Process_date(0,0,str[8],str[9]); Addres_1=(u8)Process_date(0,0,str[11],str[12]); uip_ipaddr(ipaddr, Addres_4,Addres_3,Addres_2,Addres_1); //设置本地设置IP地址 uip_sethostaddr(ipaddr); tcp_client_reconnect(); disp_IP(); break; case 19:RTC->CRH&=~(0X01); while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成 timer.w_year=(s16)Process_date(str[0]-0x30,str[1]-0x30,str[2],str[3]); timer.w_month=(s8)Process_date(0,0,str[5],str[6]); timer.w_date=(s8)Process_date(0,0,str[8],str[9]); timer.hour=(s8)Process_date(0,0,str[11],str[12]); timer.min=(s8)Process_date(0,0,str[14],str[15]); timer.sec=(s8)Process_date(0,0,str[17],str[18]); RTC_Set(timer.w_year,timer.w_month,timer.w_date,timer.hour,timer.min,timer.sec); //设置时间 RTC->CRH|=0X01; while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成 break; case 6: case 7: case 8: case 9: case 10 : case 11 : LCD_ShowString(3,5,str); Speech(str);break; default : break; } } u16 Process_date(u8 q,u8 b,u8 s,u8 g) { u16 temp; temp=q*1000+b*100+(s-0x30)*10+(g-0x30); return temp ; } HARDW ARE文件夹下rtc。C文件 #include "sys.h" #include "rtc.h" #include "delay.h" #include "usart.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //Mini STM32开发板 //RTC实时时钟驱动代码 //正点原子@ALIENTEK //技术论坛:https://www.360docs.net/doc/a41753121.html, //修改日期:2010/12/30 //版本:V1.1 //版权所有,盗版必究。 //Copyright(C) 正点原子2009-2019 //All rights reserved //***************************************************************************** *** //V1.1修改说明 //修改了RTC_Init函数分频设置无效的bug //修改了RTC_Get函数的一个bug ////////////////////////////////////////////////////////////////////////////////// //Mini STM32开发板 //RTC实时时钟驱动代码 //正点原子@ALIENTEK //2010/6/6 tm timer;//时钟结构体 //实时时钟配置 //初始化RTC时钟,同时检测时钟是否工作正常 //BKP->DR1用于保存是否第一次配置的设置 //返回0:正常 //其他:错误代码 u8 RTC_Init(void) { //检查是不是第一次配置时钟 u8 temp=0; if(BKP->DR1!=0X5050)//第一次配置 { RCC->APB1ENR|=1<<28; //使能电源时钟 RCC->APB1ENR|=1<<27; //使能备份时钟 PWR->CR|=1<<8; //取消备份区写保护 RCC->BDCR|=1<<16; //备份区域软复位 RCC->BDCR&=~(1<<16); //备份区域软复位结束 RCC->BDCR|=1<<0; //开启外部低速振荡器 while((!(RCC->BDCR&0X02))&&temp<250)//等待外部时钟就绪 { temp++; delay_ms(10); }; if(temp>=250)return 1;//初始化时钟失败,晶振有问题 RCC->BDCR|=1<<8; //LSI作为RTC时钟 RCC->BDCR|=1<<15;//RTC时钟使能 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 RTC->CRH|=0X01; //允许秒中断 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 RTC->CRL|=1<<4; //允许配置 RTC->PRLH=0X0000; RTC->PRLL=32767; //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767 Auto_Time_Set(); //RTC_Set(2009,12,2,10,0,55); //设置时间 RTC->CRL&=~(1<<4); //配置更新 while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成 BKP->DR1=0X5050; //BKP_Write(1,0X5050);;//在寄存器1标记已经开启了 //printf("FIRST TIME\n"); }else//系统继续计时 { while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 RTC->CRH|=0x01; //允许秒中断 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 //printf("OK\n"); } MY_NVIC_Init(0,0,RTC_IRQChannel,2);//RTC,G2,P2,S2.优先级最低 RTC_Get();//更新时间 return 0; //ok } //RTC中断服务函数 //const u8* Week[2][7]= //{ //{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}, //{"日","一","二","三","四","五","六"} //}; //RTC时钟中断 //每秒触发一次 void RTC_IRQHandler(void) { if(RTC->CRL&0x0001)//秒钟中断 { RTC_Get();//更新时间 //printf("CRL:%d\n",RTC->CRL); } if(RTC->CRL&0x0002)//闹钟中断 { //printf("Alarm!\n"); RTC->CRL&=~(0x0002);//清闹钟中断 //闹钟处理 } RTC->CRL&=0X0FFA; //清除溢出,秒钟中断标志 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 } //判断是否是闰年函数 //月份 1 2 3 4 5 6 7 8 9 10 11 12 //闰年31 29 31 30 31 30 31 31 30 31 30 31 //非闰年31 28 31 30 31 30 31 31 30 31 30 31 //输入:年份 //输出:该年份是不是闰年.1,是.0,不是 u8 Is_Leap_Year(u16 year) { if(year%4==0) //必须能被4整除 { if(year%100==0) { if(year%400==0)return 1;//如果以00结尾,还要能被400整除 else return 0; }else return 1; }else return 0; } //设置时钟 //把输入的时钟转换为秒钟 //以1970年1月1日为基准 //1970~2099年为合法年份 //返回值:0,成功;其他:错误代码. //月份数据表 u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表 //平年的月份日期表 const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31}; u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec) { u16 t; u32 seccount=0; if(syear<1970||syear>2099)return 1; for(t=1970;t { if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数 else seccount+=31536000; //平年的秒钟数} smon-=1; for(t=0;t { seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加 if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数 } seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 seccount+=(u32)hour*3600;//小时秒钟数 seccount+=(u32)min*60; //分钟秒钟数 seccount+=sec;//最后的秒钟加上去 //设置时钟 RCC->APB1ENR|=1<<28; //使能电源时钟 RCC->APB1ENR|=1<<27; //使能备份时钟 PWR->CR|=1<<8; //取消备份区写保护 //上面三步是必须的! RTC->CRL|=1<<4; //允许配置 RTC->CNTL=seccount&0xffff; RTC->CNTH=seccount>>16; RTC->CRL&=~(1<<4);//配置更新 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 return 0; } //得到当前的时间 //返回值:0,成功;其他:错误代码. u8 RTC_Get(void) { static u16 daycnt=0; u32 timecount=0; u32 temp=0; u16 temp1=0; timecount=RTC->CNTH;//得到计数器中的值(秒钟数) timecount<<=16; timecount+=RTC->CNTL; temp=timecount/86400; //得到天数(秒钟数对应的) if(daycnt!=temp)//超过一天了 { daycnt=temp; temp1=1970; //从1970年开始 while(temp>=365) { if(Is_Leap_Year(temp1))//是闰年 { if(temp>=366)temp-=366;//闰年的秒钟数 else break; } else temp-=365; //平年 temp1++; } timer.w_year=temp1;//得到年份 temp1=0; while(temp>=28)//超过了一个月 { if(Is_Leap_Year(timer.w_year)&&temp1==1)//当年是不是闰年/2月份 { if(temp>=29)temp-=29;//闰年的秒钟数 else break; } else { if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年 else break; } temp1++; } timer.w_month=temp1+1;//得到月份 timer.w_date=temp+1; //得到日期 } temp=timecount%86400; //得到秒钟数 timer.hour=temp/3600; //小时 timer.min=(temp%3600)/60; //分钟 timer.sec=(temp%3600)%60; //秒钟 timer.week=RTC_Get_Week(timer.w_year,timer.w_month,timer.w_date);//获取星期return 0; } //获得现在是星期几 //功能描述:输入公历日期得到星期(只允许1901-2099年) //输入参数:公历年月日 //返回值:星期号 u8 RTC_Get_Week(u16 year,u8 month,u8 day) { u16 temp2; u8 yearH,yearL; yearH=year/100; yearL=year%100; // 如果为21世纪,年份数加100 if (yearH>19)yearL+=100; // 所过闰年数只算1900年之后的 temp2=yearL+yearL/4; temp2=temp2%7; temp2=temp2+day+table_week[month-1]; if (yearL%4==0&&month<3)temp2--; return(temp2%7); } //比较两个字符串指定长度的内容是否相等 //参数:s1,s2要比较的两个字符串;len,比较长度 //返回值:1,相等;0,不相等 u8 str_cmpx(u8*s1,u8*s2,u8 len) { u8 i; for(i=0;i return 1; } extern const u8 *COMPILED_DA TE;//获得编译日期 extern const u8 *COMPILED_TIME;//获得编译时间 const u8 Month_Tab[12][3]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; //自动设置时间为编译器时间 void Auto_Time_Set(void) { u8 temp[3]; u8 i; u8 mon,date; u16 year; u8 sec,min,hour; for(i=0;i<3;i++)temp[i]=COMPILED_DATE[i]; for(i=0;i<12;i++)if(str_cmpx((u8*)Month_Tab[i],temp,3))break; mon=i+1;//得到月份 if(COMPILED_DATE[4]==' ')date=COMPILED_DA TE[5]-'0'; else date=10*(COMPILED_DA TE[4]-'0')+COMPILED_DATE[5]-'0'; year=1000*(COMPILED_DATE[7]-'0')+100*(COMPILED_DATE[8]-'0')+10*(COMPILED _DATE[9]-'0')+COMPILED_DATE[10]-'0'; hour=10*(COMPILED_TIME[0]-'0')+COMPILED_TIME[1]-'0'; min=10*(COMPILED_TIME[3]-'0')+COMPILED_TIME[4]-'0'; sec=10*(COMPILED_TIME[6]-'0')+COMPILED_TIME[7]-'0'; RTC_Set(year,mon,date,hour,min,sec) ; //printf("%d-%d-%d %d:%d:%d\n",year,mon,date,hour,min,sec); } Hardware文件夹下exit。C #include "exti.h" #include "led.h" #include "key.h" #include "delay.h" #include "usart.h" #include "12864.h" #include "rtc.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //Mini STM32开发板 //外部中断驱动代码 //正点原子@ALIENTEK //技术论坛:https://www.360docs.net/doc/a41753121.html, //修改日期:2010/12/01 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 正点原子2009-2019 //All rights reserved ////////////////////////////////////////////////////////////////////////////////// //外部中断0服务程序 void EXTI0_IRQHandler(void) { delay_ms(100);//消抖 if(KEY2==1) //按键2 { count++; if(count<7) { while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 RTC->CRH&=~(0X01); //允许秒中断 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 } switch(count) { case 1 : LCD_ShowString(2,4,"设置秒");break; case 2 : LCD_ShowString(2,4,"设置分");break; case 3 : LCD_ShowString(2,4,"设置时");break; case 4 : LCD_ShowString(2,4,"设置日");break; case 5 : LCD_ShowString(2,4,"设置月");break; case 6 : LCD_ShowString(2,4,"设置年");break; case 7 : { RTC_Set(timer.w_year,timer.w_month,timer.w_date,timer.hour,timer.min,timer.sec); while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 RTC->CRH|=0X01; //允许秒中断 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 LCD_ShowString(2,4,"设置IP ");LCD_ShowString(3,0,">");disp_IP(); }break; case 8 : LCD_ShowString(3,0,">>");break; case 9 : LCD_ShowString(3,0,">>>");break; case 10 : LCD_ShowString(3,0,">>>>");break; case 11 : count=0;LCD_ShowString(3,0," ");LCD_ShowString(2,4," ");break; } } EXTI->PR=1<<0; //清除LINE0上的中断标志位 } //外部中断15~10服务程序 void EXTI15_10_IRQHandler(void) { delay_ms(100); //消抖 if(KEY0==0) //按键0 { LED1=!LED1; switch(count) { case 1 : timer.sec--;if(timer.sec==0)timer.sec=59;LCD_Shownum(1,4,timer.sec);LCD_ShowString(2,7,"-") ;break; case 2 : timer.min--;if(timer.min==0)timer.min=59;LCD_Shownum(1,2,timer.min);LCD_ShowString(2,7, "-");break; case 3 : timer.hour--;if(timer.hour==0)timer.hour=12;LCD_Shownum(1,0,timer.hour);LCD_ShowString(2, 7,"-");break; case 4 : timer.w_date--;if(timer.w_date==0)timer.w_date=31;LCD_Shownum(0,4,timer.w_date);LCD_Sho wString(2,7,"-");break; case 5 : timer.w_month--;if(timer.w_month==0)timer.w_month=12;LCD_Shownum(0,2,timer.w_month); LCD_ShowString(2,7,"-");break; case 6 : timer.w_year--;if(timer.w_year==0)timer.w_year=2099;LCD_Shownum(0,0,(timer.w_year%100)) ;LCD_ShowString(2,7,"-");break; case 7 : Addres_1--;if(Addres_1==0) Addres_1=99;disp_IP();break; case 8 : Addres_2--;if(Addres_2==0) Addres_2=9;disp_IP();break; case 9 : Addres_3--;if(Addres_3==0)Addres_3=200;disp_IP();break; case 10 : Addres_4--;if(Addres_4==0)Addres_4=200;disp_IP();break; } }else if(KEY1==0)//按键1 {LED0=!LED0; switch(count) { case 1 : timer.sec++;if(timer.sec==60)timer.sec=0;LCD_Shownum(1,4,timer.sec);LCD_ShowString(2,7,"+ ");break; case 2 : timer.min++;if(timer.min==60)timer.min=0;LCD_Shownum(1,2,timer.min);LCD_ShowString(2,7 ,"+"); break; case 3 : timer.hour++;if(timer.hour==12)timer.hour=0;LCD_Shownum(1,0,timer.hour);LCD_ShowString( 2,7,"+");break; case 4 : timer.w_date++;if(timer.w_date==32)timer.w_date=0;LCD_Shownum(0,4,timer.w_date);LCD_Sh owString(2,7,"+");break; case 5 : timer.w_month++;if(timer.w_month==32)timer.w_month=0;LCD_Shownum(0,2,timer.w_month); LCD_ShowString(2,7,"+"); break; case 6 : timer.w_year++;if(timer.w_year==2099)timer.w_year=2014;LCD_Shownum(0,0,(timer.w_year% 100));LCD_ShowString(2,7,"+");break; case 7 : Addres_1++;if(Addres_1==100)Addres_1=0;disp_IP();break; case 8 : Addres_2++;if(Addres_2==10)Addres_2=0;disp_IP();break; case 9 : Addres_3++;if(Addres_3==1000)Addres_3=0;disp_IP();break; case 10: Addres_4++;if(Addres_4==1000)Addres_4=0;disp_IP();break; } } EXTI->PR=1<<13; //清除LINE13上的中断标志位 EXTI->PR=1<<15; //清除LINE15上的中断标志位 } //外部中断初始化程序 //初始化PA0,PA13,PA15为中断输入. void EXTIX_Init(void) { RCC->APB2ENR|=1<<2; //使能PORTA时钟 JTAG_Set(JTAG_SWD_DISABLE);//关闭JTAG和SWD GPIOA->CRL&=0XFFFFFFF0;//PA0设置成输入 GPIOA->CRL|=0X00000008; GPIOA->CRH&=0X0F0FFFFF;//PA13,15设置成输入 GPIOA->CRH|=0X80800000; GPIOA->ODR|=1<<13; //PA13上拉,PA0默认下拉 GPIOA->ODR|=1<<15; //PA15上拉 Ex_NVIC_Config(GPIO_A,0,RTIR); //上升沿触发 Ex_NVIC_Config(GPIO_A,13,FTIR);//下降沿触发 Ex_NVIC_Config(GPIO_A,15,FTIR);//下降沿触发 MY_NVIC_Init(2,2,EXTI0_IRQChannel,2); //抢占2,子优先级2,组2 MY_NVIC_Init(2,1,EXTI15_10_IRQChannel,2);//抢占2,子优先级1,组2 } void disp_IP(void) { LCD12864_Pos(3,2); LCD12684_Wdat(Addres_4/100+0x30); LCD12684_Wdat((Addres_4%100)/10+0x30); LCD12684_Wdat((Addres_4%100)%10+0x30); LCD12684_Wdat(0x2e); LCD12864_Pos(3,4); LCD12684_Wdat(Addres_3/100+0x30); LCD12684_Wdat((Addres_3%100)/10+0x30); LCD12684_Wdat((Addres_3%100)%10+0x30); LCD12684_Wdat(0x2e); LCD12864_Pos(3,6); LCD12684_Wdat(Addres_2+0x30); LCD12684_Wdat(0x2e); LCD12864_Pos(3,7); LCD12684_Wdat(Addres_1/10+0x30); LCD12684_Wdat(Addres_1%10+0x30); } 其他文件用原子rtc时钟的程序就行 实验报告 源代码: #pragma sfr //使用特殊功能寄存器 #pragma EI //开中断 #pragma DI //关中断 #pragma access //使用绝对地址指令 #pragma interrupt INTTM000 Time //定义时间中断函数为Time #pragma interrupt INTKR OnKeyPress //定义按键中断为OnKeyPress #pragma interrupt INTP5 OnKeyOver //定义INT中断为OnKeyOver void Init_Led(); void InitKey_INTKR(); void Init_Lcd(); void Init_Inter(); void LightOneLed(unsigned char ucNum); void LightOff(); int Count_Day(int month); char i=0; //定义变量i,是切换时间的标志 int key=0; //定义key=0 int temp=1; //用于存放当前月的天数 int temp1=1; int second=0; //默认的秒second=0 int minute=0; //默认的分minute=0 int hour=12; //默认的时hour=12 int day=1; //默认的天day=1 int month=5; //默认的月month=5 int year=2014; //默认的年year=2014 int c_hour=1; //默认的闹钟时=1 int c_minute=1; //默认的闹钟分=1 int buffs[2]; //秒的数码显示缓存区 int buffm[2]; //分的数码显示缓存区 int buffh[2]; //时的数码显示缓存区 int buffday[2]; //天的数码显示缓存区 int buffmonth[2]; //月的数码显示缓存区 int buffyear[4]; //年的数码显示缓存区 int buffmd[4]; //月,天的数码显示缓存区 int buffhm[4]; //时,分的数码显示缓存区 int buffms[4]; //分,秒的数码显示缓存区 int buffch[2]; //闹钟时的数码显示缓存区 int buffcm[2]; //闹钟分的数码显示缓存区 unsigned char Que = 0; //INT中断中间变量 int LCD_num[10]={0X070d,0x0600,0x030e,0x070a,0x0603,0x050b,0x050f,0x0700,0x070f,0x070b};// 数字0~~9的显示码 unsigned char Scond; //…………………………延时函数1……………………// void Delay(int k){ i nt i,j; f or(i=0;i #include TH0 = 0x4C; //?????? EA=1; ET0=1; TR0=1; //???0???? } void Delay2ms() //@11.0592MHz { unsigned char i, j; _nop_(); i = 4; j = 146; do { while (--j); } while (--i); } void Delay100us() //@11.0592MHz { unsigned char i, j; i = 2; j = 109; do { while (--j); } while (--i); void Delay50ms() //@11.0592MHz { unsigned char i, j, k; i = 3; j = 207; k = 28; do { do { while (--k); } while (--j); } while (--i); } void write_12864com(uchar com) { rs=0; rw=0; Delay100us(); P0=com; e=1; Delay100us(); e=0; Delay100us(); } 嵌入式系统开发实验报告 实验四:实时时钟实验 班级:应电112 姓名:张志可 学号: 110415151 指导教师:李静 实验日期: 2013年9月25日 实验四:实时时钟实验 一、实验目的 1. 了解实时时钟的硬件控制原理及设计方法。 2. 掌握 S3C2410X 处理器的 RTC 模块程序设计方法。 二、实验设备 硬件:Embest ARM 教学实验系统,ULINK USB-JTAG 仿真器套件,PC 机。 软件:MDK 集成开发环境,Windows 98/2000/NT/XP。 三、实验原理 1. 实时时钟(RTC) 实时时钟(RTC)器件是一种能提供日历/时钟、数据存储等功能的专用集成电路,常用作各种计算机系统的时钟信号源和参数设置存储电路。RTC 具有计时准确、耗电低和体积小等特点,特别是在各种嵌入式系统中用于记录事件发生的时间和相关信息,如通信工程、电力自动化、工业控制等自动化程度高的领域的无人值守环境。随着集成电路技术的不断发展,RTC 器件的新品也不断推出,这些新品不仅具有准确的 RTC,还有大容量的存储器、温度传感器和 A/D 数据采集通道等,已成为集 RTC、数据采集和存储于一体的综合功能器件,特别适用于以微控制器为核心的嵌入式系统。 RTC 器件与微控制器之间的接口大都采用连线简单的串行接口,诸如 I2C、SPI、MICROWIRE 和CAN 等串行总线接口。这些串口由2~3 根线连接,分为同步和异步。 2. S3C2410X 实时时钟(RTC)单元 S3C2410X 实时时钟(RTC)单元是处理器集成的片内外设。由开发板上的后备电池供电,可以在系统电源关闭的情况下运行。RTC 发送8 位BCD 码数据到CPU。传送的数据包括秒、分、小时、星期、日期、月份和年份。RTC 单元时钟源由外部32.768KHz 晶振提供,可以实现闹钟(报警)功能。 四、实验内容 学习和掌握 Embest ARM 教学实验平台中 RTC 模块的使用,编写应用程序,修改时钟日期及时间的设置,以及使用 EMBEST ARM 教学系统的串口,在超级终端显示当前系统时间。 RTC实时时钟 什么是RTC实时时钟 在一个嵌入式系统中,通常采用RTC 来提供可靠的系统时间,包括时分秒和年月日等;而且要求在系统处于关机状态下它也能够正常工作(通常采用后备电池供电),它的外围也不需要太多的辅助电路,典型的就是只需要一个高精度的32.768KHz 晶体和电阻电容等。 S3C2410实时时钟的基本特性 实时时钟(RTC)单元可以通过备用电池供电,因此,即使系统电源关闭,它也可以继续工作。RTC 可以通过STRB/LDRB 指令将8 位BCD 码数据送至CPU。这些BCD 数据包括秒,分,时,日期,星期,月和年。RTC 单元通过一个外部的32.768KHz晶振提供时钟。RTC具有定时报警的功能。RTC 控制器功能说明: ●时钟数据采用BCD 编码 ●能够对闰年的年月日进行自动处理 ●具有告警功能,当系统处于关机状态时,能产生告警中断; ●具有独立的电源输入 ●提供毫秒级时钟中断,该中断可用于作为嵌入式操作系统的内核时钟 RTC实时时钟的结构框图 RTC模块构成 ●闰年产生器 这个模块可以根据BCDDATA,BCDMON,以及BCDYEAR的数据决定每个月的最后日期是28,29,30 还是31。一个8位的计数器只能显示两个BCD码,因此它不能判断00 年究竟是不是闰年。例如它不能够判断1900 年和2000 的差别。。为了解决这个问题,S3C2410内的RTC 模块中有一个固定的逻辑,用来支持2000 年为闰年。请注意虽然2000 年是闰年,但1900 年不是闰年。因此,S3C2410 中00 代表2000 年,而不是1900 年。 ●读/写寄存器 要求置高RTCON 寄存器的0 位来表示读和写RTC 模块中的寄存器。。为了显示秒,分,小时,日期,月和年,CPU 会从BCDSEC,BCDMIN,BCDHOUR,BCDDAY,BCDDATE,BCDMON,和BCDYEAR 寄存器读取数据。但是由于多个寄存器的读取,可能产生1 秒钟的偏离。例如,如果用户读取寄存器BCDYEAR 到BCDMIN,假设结果为1959 年,12 月,31 日,23 点,59 分。在用户读取BCDSEC 寄存器时,但如果结果是0,那么很有可能年,月,日,时,分已经变成了1960 年1 月1 日0 时0 分了。解决的方法是,当读取到的BCDSEC 等于0 时,用户应该在读取一次BCDYEAR到BCDSEC 的值。 ●备用电池 RTC可被备用电池驱动,备用电池通过RTCVDD引脚向RTC提供电压。当系统掉电时,RTC与CPU 之间的接口被阻塞,备用电池仅仅驱动振荡电路以及BCD计数器,这样可减少能量损耗。 。 ==================主程序================= #include 。#include "ds1302.h" #include "LCD1602.h" void change(); uchar times[9]; uchar date[9]; main() {LCD_init();//LCD初始化 init_1302(time_1302); gotoxy(1,1); LCD_display("Time:"); gotoxy(1,2); LCD_display("Date:"); times[8]='\0';// date[8]='\0'; while(1) {get_1302(time_1302); change(); gotoxy(7,1); LCD_display(times); gotoxy(7,2); LCD_display(date); } } /*=========================== 转换子程序 ===========================*/ void change() { // 时间的转换 times[0]=time_1302[2]/10+'0'; times[1]=time_1302[2]%10+'0'; times[2]=':'; times[3]=time_1302[1]/10+'0'; times[4]=time_1302[1]%10+'0'; times[5]=':'; times[6]=time_1302[0]/10+'0'; times[7]=time_1302[0]%10+'0'; // 日期的转换 date[0]=time_1302[6]/10+'0'; date[1]=time_1302[6]%10+'0'; date[2]='-'; 微机原理及应用课程设计任务书 20 xx -20 xx 学年第 x 学期第 xx 周- xx 周 题目实时日历时钟显示系统的设计 内容及要求 内容:实时日历时钟显示系统 要求:设计一个实时日历时钟显示系统的程序。用“年/月/日”,“时:分:秒”(都是两位)的形式连续显示系统时间 进度安排 课程设计内容时间分配 方案论证1天 分析、设计、调试、运行3天 检查、整理、写设计报告、小结1天 合计5天 学生姓名: xx 指导时间: xxxx 指导地点: xxxx 任务下达任务完成 考核方式 1.评阅√ 2.答辩√ 3.实际操作□ 4.其它□指导教师系(部)主任 注:1、此表一组一表二份,课程设计小组组长一份;任课教师授课时自带一份备查。 2、课程设计结束后与“课程设计小结”、“学生成绩单”一并交院教务存档。 此次微机原理课程设计要求设计一个实时日历时钟显示系统。 本程序利用DOS中断2AH号功能调用取系统年月日,再逐个显示各数据,利用2CH号功能调用取系统时间,逐个显示各数据。用“时:分:秒”(都是两位)的形式连续显示系统时间,并利用计算机提供的软件调试工具对所编写程序进行调试,记录下整个调试分析的过程与运行结果。 任务安排: 主程序: xx:主体程序和流程设计 xx:日历调用显示系统 xx:时间调用显示系统 子程序: xx:显示两位数字的子程序 一、课程名称 (2) 二、课程内容及要求 (2) 三、小组组成 (2) 四、设计思路 (3) 五、程序流程图及介绍 (4) 六、调试 (5) 七、总结 (7) 八、参考资料 (9) 附录 (9) 一、课程名称:实时日历时钟显示系统的设计 二、课程内容及要求 课程内容:实时日历时钟显示系统 要求:设计一个实时日历时钟显示系统的程序。用“年/月/日”,“时:分:秒”(都是两位)的形式连续显示系统时间 三、小组组成: 成员: xx, xx, xx, xx 任务安排: 主程序: xx:主体程序和流程设计 xx:日历系统 xx:时间系统 子程序: xx:显示两位数字的子程序 #include 1 课程设计内容 本文将利用ALIENTEK 2.8寸TFTLCD模块来显示日期时间,实现一个简单的时钟。 2 STM32芯片简介 2006年ARM公司推出了基于ARMv7架构的Cortex系列的标准体系结构,以满足各种技术的不同性能要求,包含A、R、M三个分工明确的系列[1]。其中,A系列面向复杂的尖端应用程序,用于运行开放式的复杂操作系统;R系列适合实时系统;M系列则专门针对低成本的微控制领域。Cortex-M3是首款基于ARMv7-M体系结构的32位标准处理器,具有低功耗、少门数、短中断延迟、低调试成本等众多优点。它是专门为在微控制系统、汽车车身系统、工业控制系统和无线网络等对功耗和成本敏感的嵌入式应用领域实现高系统性能而设计的,它大大简化了编程的复杂性,集高性能、低功耗、低成本于一体[2]。半导体制造厂商意法半导体ST公司是ARM公司Cortex-M3内核开发项目一个主要合作方,2007年6月11日ST公司率先推出了基于Cortex-M3内核的STM32系列MCU。本章将简要介绍STM32系列处理器的分类、内部结构及特点,并对本设计中重点应用的通用定时器做进一步分析。 2.1 STM32 RTC时钟简介 STM32 的实时时钟(RTC)是一个独立的定时器。STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前,先要取消备份区域(BKP)写保护。 RTC 的简化框图,如图 20.1.1 所示: /****************************************************************************** * * 标题: 试验数码管显示时钟* * * * 通过本例程了解DS1302时钟芯片的基本原理和使用,理解并掌握DS1302时钟芯片 * * 驱动程序的编写以及实现数字字符在数码管中的显示。 * * 注意:JP1302跳线冒要短接。* * 请学员认真消化本例程,懂DS1302在C语言中的操作* ******************************************************************************* */ #include 5.6 实时时钟实验 5.6.1 实验目的 1. 了解实时时钟在嵌入式系统中的作用; 2. 掌握实时时钟的使用。 5.6.2 实验内容 1. 编程实现实时时钟功能,每秒显示实时时钟; 2. 编程实现实时时钟告警功能。 5.6.3 预备知识 1. 了解ADT集成开发环境的基本功能; 2. 学习S3C24X0的实时时钟模块的使用。 5.6.4 实验设备 1. 硬件:JXARM9-2440教学实验箱、PC机; 2. 软件:PC机操作系统 Windows 98(2000、XP) + ADT IDE开发环境。 5.6.5 基础知识 1. 实时时钟在嵌入式系统中的作用 在一个嵌入式系统中,实时时钟单元可以提供可靠的时钟,包括时、分、秒和年、月、日;即使在系统处于关机状态下它也能够正常工作(通常采用后备电池供电),它的外围也不需要太多的辅助电路,典型的就是只需要一个高精度的晶振。 2. S3C24X0的实时时钟单元 下图为S3C24X0的实时时钟框图。它具有以下特点: 图5-12 S3C24X0的实时时钟框图 1)时钟数据采用BCD编码; 2)能够对闰年的年月日进行自动处理; 3)具有告警功能,当系统处于关机状态时,能产生告警中断; 4)具有独立的电源输入; 5)提供毫秒级时钟中断,该中断可以用于作为嵌入式操作系统的内核时钟。 3. S3C24X0的实时时钟寄存器 1) 控制寄存器 表5-16 控制寄存器 寄存器地址读/写状态描述复位值 RTCCON 0x57000040 R/W 实时时钟控制寄存器0x0 RTCCON 位描述复位值CLKRST [3] 实时时钟计数器复位 0-不复位 1-复位 CNTSEL [2] BCD计数选择,将计数器设置为BCD模式 0-选择BCD模式 1-保留 CLKSEL [1] BCD时钟选择 0-将输入时钟进行1/215分频 1-保留 RTCEN [0] RTC读写使能 0-禁止 1-使能 2) 告警控制寄存器 汇编语言实现实时时钟显示 data segment msg db 'Current time is: ' hours db ?,? db ':' minutes db ?,? db ':' seconds db ?,?,0 oldint1c dd ? ;旧的入口参数 position dw 0 ;时间显示位置 color db 07h data ends code segment ;代码段 assume cs:code,ds:code start: mov ax,data mov ds,ax jmp run newint1c: push ax push bx push cx push dx push si push di push es mov ax,data mov ds,ax mov ax,0200h ;获取系统时间,ch→hours cl→minutes DH→seconds,均为BCD码格式 int 1ah ;时钟服务 mov al,ch lea si,hours ;时 call BCD mov al,cl lea si,minutes ;分 call BCD mov al,dh lea si,seconds ;秒 call BCD mov ax,0b800h ;显存地址,采用直接写显存的方法输出字符 mov es,ax ;es:di 指向显存地址 lea si,position ;设置时间显示位置 mov di,[si] lea si,msg disp: mov al,[si] inc si or al,al jz exit cld stosb inc di jmp disp exit: pop es pop di pop si pop dx pop cx pop bx pop ax jmp ds:oldint1c ;执行旧的中断服务程序 BCD proc push ax ;用于将BCD码转换为ASCII码入口al-BCD码 mov ah,al ;出口 shr ah,1 shr ah,1 shr ah,1 shr ah,1 and al,0fh add ax,'00' ;加上0的ASCII码 xchg ah,al mov [si],ax pop ax ret (用数码管显示实时日历时钟的应用设计) 摘要 本课题通过MCS-51单片机来设计电子时钟,采用汇编语言进行编程,可以实现以下一些功能:小时,分,秒和年,月,日的显示。本次设计的电子时钟系统由时钟电路,LED显示电路三部分组成。51单片机通过软件编程,在LED数码管上实现小时,分,秒和年,月,日的显示;利用时钟芯片DS1302来实现计时。本文详细介绍了DS1302 芯片的基本工作原理及其软件设计过程,运用PROTEUS软件进行电路连接和仿真,同时还介绍了74LS164,通过它来实现I|O 口的扩展。 关键词:时钟芯片,仿真软件,74LS164 目录 前言 0.1设计思路 (8) 0.2研究意义 (8) 一、时钟芯片 1.1 了解时钟芯片……………………………………………….8-9 1.2 掌握时钟芯片的工作原理………………………………….10-11二、74LS164 2.1 了解74LS164........................................................11-12 2.2 掌握的74LS164工作原理. (12) 三、数码管 3.1 熟悉常用的LED数码管...........................................12-13 3.2 了解动态显示与静态显示. (13) 四、程序设计 4.0 程序流程图 (14) 4.1 DS1392的驱动.......................................................15-16 4.2 PROTUES实现电路连接. (17) 4.3 数码管的显示:小时;分;秒 (18) 4.4 数码管显示:年;月;日 (19) 五、总结…………………………………………………………………..20-21 六、附页程序………………………………………………………………22-31 RTC实时时钟芯片 RTC实时时钟芯片是一种计时器,可以由硬件集成电路来完成,也可以由单片机加程序来完成。实时时钟可以对秒、分、时、星期、日、月和年进行准确计时,具有闰年补偿功能,能够计时到2100年。 消费类电子(机顶盒、VCR),手持式装置(GPS、POS终端),医疗设备,办公设备,电信(路由器、交换机、服务器),电器设备,汽车,消费类电子,嵌入式时标,工业,电表。 DS3231集成了温度补偿晶体振荡器(TCXO)和晶体,电池备份输入用于支持连续计时,可编程方波输出,低电平有效复位输出。关键参数: 工作温度商业级:0°C至+70°C,具有2ppm精度; 工业级:40°C至+85°C,具有3.5pmm精度。 DS3231M是业内首款内置MEMS、带温度补偿的RTC,允许器件用于强烈震动的场合,不会由于晶体失效而导致产品故障。 DS3232相比较于DS3231将32kHz输出驱动器更改为推挽输出,省去一个外部上拉电阻,节省空间,够加快时钟的边沿速度,降低器件功耗。电池切换时,可通过32kHz位选择使能/禁止32kHz输出。DS3232的32kHz输出在关闭状态下驱动至低电平,DS3231的32kHz输出在关闭状态下为高阻输出。DS3232内部可通过2个CRATE位控制温度转换速率,这些位用于控制器件的采样率。采样率决定了对温度传感器进行数字转换的频率,以及补偿振荡器的时间间隔。降低采样率则降低了温度传感器的工作频率,从而降低整体功耗。此外,DS3232具有236字节的SRAM。 压检测功能和振荡停止检测功能,内置定时器可以产生周期性的定时中断信号,警报器用于定时报警,可设定天、日期、小时、分钟。工作电压范围:1.70V-5.5V。计时保持电压:1.15V-5.5V。此外,采用IIC接口,支持低功耗模式。 RX6110 频率输出功能:能选择输出频率,有32.768kHz, 1024Hz, 1Hz。 接口类型:IIC总线接口和SPI总线接口。 自动电源切换功能:当VDD低于1.6V失效时,内部电源自动切换到VBAT. 内置128位的RAM。 定时器功能:当事件出现时,定时器可以自动记录到TF-bit,并能通过/IRQ1 或/IRQ2引脚输出。 报警功能:当事件出现时,定时器可以自动记录到AF-bit,并能通过/IRQ1引脚输出。 工作电压范围:1.6V-5.5V。 计时保持电压:1.1V-5.5V。 RTC (实时时钟) 晶振设计指南(适用于FM31系列,FM3808,FM30C256) 总体概述 FM31系列,FM3808,FM30C256集成了处理器外围器件,它集成了FRAM非易失性存储器和实时时钟于一体。实时时钟在VDD掉电以后自动切换到后备电源。在使用后备电源的情况下,实时时钟耗电量很少以便其可以长期工作。 本应用笔记提醒系统设计者在使用实时时钟时应注意的问题。 振荡器和晶体 任何实时时钟的核心都是晶振,它为分频计数器提供精确的与低功耗的时基信号,它可以用于产生秒、分、时、日等信息。为了确保时钟长期的准确性,晶振必须工作正常,不能受到干扰。 Figure 1. Crystal Hookup to RTC 除了晶体之外,所有必须的元件都被集成在器件之内。如果有额外的诸如电容和电阻等元件被连接到X1和X2引脚,晶振将不能正常工作。这种情况下,直流工作点将发生偏移,晶振频率也会偏移,甚至在上电时,晶振不能正常起振。具有10pF电容和10M阻抗的被动示波器探针也会影响晶振正常工作。 所有的32.768KHZ晶体都有等效电容。市场上最为普遍的32KHZ晶体有两种类型:6pF和12.5pF。在操作时,晶体必须符合推荐的容性特性。那就是说,X1/X2引脚的容性负载必须为6pF。所有的FRAM 实时时钟都设计使用6pF类型的晶体。 Figure 2. Simplified Oscillator Circuit 以上简化的晶振示意图显示了穿孔晶振与芯片内的C1和C2的连接。芯片内的这两个电容值为 12pF,它们和晶体一起工作。因此CLOAD值为 C1*C2/(C1+C2)或6pF.。两个电阻每个为1千欧,它可以调整相位以提高晶振的工作稳定性。 所有带有实时时钟的Ramtron外围器件都选择6pF晶体以在使用后备电源时实现最低功耗。一个12pF的晶体晶振的功耗是6pF晶体晶振的两倍。值得注意的是:晶振内的150nA电流源为电路提供一个低值的直流偏置电流。晶振可能由于噪音和X1/X2引脚上额外负载的影响而引起工作异常。 晶振频率测量 晶振32.768KHZ频率不能被直接监控。不能在X1和X2引脚上增加电容,也不可以用探头直接接触。以下推荐几种检测晶振频率的方法: 1、上电后将OSCEN位设为0。 2、在实时时钟控制寄存器中,(在FM30C256和FM3808中为Flages寄存器),将CAL位设置为1。这一操作将CAL:引脚(FM3808中的INT)变为512Hz的监控器。512Hz是晶振频率的64分频。 3、可使用频率计数器或其他精确频率测量仪器测量晶振频率(可使用数码示波器观察十个周期以上,而不是只观察一个周期)。你希望读到512Hz这一精确频率值,但只要测量值在511.975-512.025Hz之间,我们就可以认为晶振工作正常。CAL(4:0)寄存器位能够使实时时钟误差率小于2ppm。0.025Hz晶振误差大约引起50ppm 的时钟误差。. 成绩: 课程设计报告书 所属课程名称单片机原理与接口技术 题目用LCD显示实时日历时钟的应用 分院机电学院 专业、班级机械设计制造及其自动化B0902 2012 年7 月15 日 目录 1课程设计任务书 (2) 2总体设计 (3) 3硬件系统设计 (4) 4程序设计 (12) 5程序调试及结果分析 (19) 6总结 (20) 7参考文献 (21) 用LCD显示实时日历时钟应用说明书 一.课程设计任务书 课程设计题目:用LCD显示实时日历时钟的应用 课程设计时间:自2012 年7 月 2 日起至2012年7 月15 日。 课程设计要求: 1.利用DS1302年月日时分秒,并用LCD显示。 2.硬件部分,根据设计的任务选定合适的单片机,根据控制对象设计接口电路。设计的单 元电路必须有工作原理,器件的作用,分析和计算过程; 3.软件设计部分,根据电路工作过程,画出软件流程图,根据流程图编写相应的程序,进 行调试并打印程序清单; 4.原理图设计部分别,根据所确定的设计电路,利用Protel工具软件绘制电路原理图,提 供元器件清单。 5.将程序运行并做记录,完成报告。 2012 年7 月15日 课程设计评阅意见 评阅教师: 2012年月日 二.总体设计 实现数字电子钟的设计有以下两种基本方案,现就两种基本方案的优劣进行具体论证,从而说明选择方案二的理由。 方案一:直接用单片机的内部定时器来实现时间。该方案以MCS-51单片机为主控芯片,以MCS-51的内部定时器产生的1s中断作为时钟的驱动,然后再通LCD液晶显示器来组成数字钟电路。但是此方案最大的缺点在于单片机89C51产生的1s中断存在误差,如果工作时间长的话,数字时钟显示的时间将会出现严重的偏差,不够精确。 方案二:使用串行接口时钟芯片DS1302设计时钟电路。该设计方案以MCS-51单片机为主控芯片,以串行时钟芯片DS1302为核心计时芯片,然后再通过一个LCD液晶显示器组成数字时钟电路。更重要的是,DS1302时钟芯片的加入大大提高了数字钟时间的准确性,而且该电路在断电后不丢失时间和数据信息时也使得该方案的研究与提升更具有开发的意义。 本次设计的电路由主控部分(单片机MCS-51)、计时部分(实时时钟芯片DS1302)、显示部分(LM044L)3个部分组成。各部分之间相互协作,构成一个统一的有机整体,实现数字时钟的计时功能。现就各部分的硬件电路设计作出如下分析: 1. 主控部分(单片机MCS-51) MCS-51单片机作为主控芯片,控制整个电路的运行。通过分析我们发现要想显示时间,必须先把DS1302中的时间信息通过单片机获取,存放到40H到46H等RAM单元。并且是实时存放,刷新时间。 2. 计时部分(实时时钟芯片DS1302) 时钟芯片DS1302能够准确的记录当前的时间,所以,通过单片机向其写入命令来获取相应的时间,而且一个命令字节控制读一个时间。 3. 显示部分 LM044L能够显示简单的汉字及数字,功能十分强大,而且属于动态显示,所以将单片机中存的时间信息传送到LM044L中。另外还需要循环赋值。 DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用SPI三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能。 下面是一段12864液晶显示实时时钟的程序: /****************************************************************************** ********* 时间:2012.11.30 晶振:11.0592MHz 芯片:STC89C52RC 功能描述:在12864上显示年、月、日、星期、时、分和秒等时间信息 ******************************************************************************* ********/ #include 实验二实时时钟实验 一、实验目的 1)数码管动态显示技术 2)定时器的应用 3)按键功能定义 二、实验实现的功能 1)通过按键可以设定定时时间,启动定时器,定时时间到,让12个发光二极管闪烁,完成定时器功能。 2)实时时钟,可以设定当前时间,完成钟表功能(四位数码管分别显示分钟和秒)。 三、系统硬件设计 四、系统软件设计 #include } void main() { uchar i=5; TMOD=0x01; TH0=(65535-45872)/256; TL0=(65535-45872)%256; EA=1; ET0=1; TR0=1; while(1) { wela=0; P1=tab[i]; if(num==20) { num=0; if(i==0) Break; i--; } } while(1) { P2=0x00; P3=0xc3; delay(1000); P2=0xff; P3=0xff; delay(1000); } } void time() interrupt 1 { TH0=(65535-45872)/256; TL0=(65535-45872)%256; num++; }五、实验过程中遇到的问题及解决方法问题1:如何显示分钟和秒的十位和个位? 解决:先进行位选选定数码管,再选择字型码。问题2:如何控制时钟的启停? 解决:运用定时器TR0=0或TR0=1控制启停。问题3:如何用数码管实现倒计时? u8 RTC_Init(void) { //启用PWR和BKP的时钟(from APB1) RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //后备域解锁 PWR_BackupAccessCmd(ENABLE); //备份寄存器模块复位 BKP_DeInit(); //外部32.768K其哟偶那个 //内部低速rc震荡器 RCC_LSICmd(ENABLE); /* Wait till LSE is ready */ /* Select LSE as RTC Clock Source */ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //RTC开启 RCC_RTCCLKCmd(ENABLE); //开启后需要等待APB1时钟与RTC时钟同步,才能读写寄存器 RTC_WaitForSynchro(); //读写寄存器前,要确定上一个操作已经结束 RTC_WaitForLastTask(); //设置RTC分频器,使RTC时钟为1Hz //RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) RTC_SetPrescaler(32767); //等待寄存器写入完成 RTC_WaitForLastTask(); //使能秒中断 RTC_ITConfig(RTC_IT_SEC, ENABLE); //等待写入完成 RTC_WaitForLastTask(); return 0; } 基于c8051f020单片机最小系统的实时时钟显示程序 2009-08-25 08:35 // 关键字:c8051f020 FYD12864-0402B LCD显示按键电子时钟// #include 实时时钟设计实验报告
51定时器和lcd12864做的实时时钟显示(附图)
实时时钟实验报告
RTC
基于ds1302的51单片机简易实时时钟-1602显示-源程序
实时日历时钟显示系统的设计
RTC实时时钟
基于STM32-RTC实时时钟
51单片机1302实时时钟1602显示程序
实时时钟参考程序
汇编语言实现实时时钟显示
用数码管显示实时日历时钟的应用设计
RTC实时时钟芯片
RTC (实时时钟) 晶振设计指南
用LCD显示实时日历时钟单片机课程设计
LCD12864显示实时时钟例程可运行
实时时钟实验报告
stm32 实时时钟rtc配置
实时时钟显示程序