嵌入式软件开发基础实验报告 实时时钟
嵌入式实时时间显示

任务
OSStart();//启动系统
6
} //开始任务 void start_task(void *pdata) { OS_CPU_SR cpu_sr=0;
pdata = pdata; OS_ENTER_CRITICAL();//进入临界区(无法被中断打断) OSTaskCreate(led_task,(void *)0,(OS_STK*)&LED_TASK_STK[LED_STK_SIZE-1],LED_TASK_PRIO);// 创 建 LED 任务 OSTaskCreate(time_task,(void *)0,(OS_STK*)&TIME_TASK_STK[TIME_STK_SIZE-1],TIME_TASK_PRIO);// 创建时间任务 OSTaskSuspend(START_TASK_PRIO); //挂起开始任务. OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断) } //指示灯任务 void led_task(void *pdata) { pdata = pdat初始化 系统初始化 创建开始任务
启动系统
开始任务 创建指示灯任务 创建显示任务 挂起开始任务
指示灯任务
显示任务 获取时间、温度
LED 取反 延时进行任务切换
得到日期 显示数据 延时进行任务切换
2、主要程序
//开始任务
#define START_TASK_PRIO 10 //开始任务的优先级设置为最低
RTC 由两个主要部分组成,第一部分(APB1 接口)用来和 APB1 总线相连。此 单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。APB1 接口 由 APB1 总线时钟驱动,用来与 APB1 总线连接。另一部分(RTC 核心)由一组可编 程计数器组成,分成两个主要模块。第一个模块是 RTC 的预分频模块,它可编程 产生 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20 位的可编程 分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每 个 TR_CLK 周期中 RTC 产生一个中断(秒中断)。第二个模块是一个 32 位的可编程 计数器,可被初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算, 可以记录 4294967296 秒,约合 136 年左右,作为一般应用,这已经是足够了的。
实时时钟设计试验报告

实验报告5.按下Key4 Key3执行时,该按键执行加一操作,Led灯按照5秒顺时针一个一个亮。
6.按下Key5 Key3执行时,该按键执行减一操作,Led灯按照5秒顺时针一个一个亮。
7.按下Key6 Key3执行时,该按键执行确定操作,Led灯按照5秒顺时针一个一个亮。
8.按下INT 闹钟关闭。
5、实验总结本次实验是对课本上“电子日历钟设计”的加深。
通过本次试验我对led和led显示有了更加熟悉的认识,能熟练应用它们的功能。
同时我对时钟计数器也有了一定的认识,可以使用定时中断实现实时时钟,更重要的是我的实践能力有很大的提高。
程序设计中遇到的问题(1)、问题:初始完成程序后秒针走的时间很快,不是精确的一秒走一次。
原因:单片机只能用主系统时间,修改fprs后可以真确显示。
(2)、问题:时间切换函数与显示函数和设计的不一样,如只需要显示时,却多显示分。
原因:在仔细看代码后发现每次按键中断都在调用time1()函数,而seeond++在里面,所以每次都会加快秒的运行。
把seeond++移到外面放入time()函数后这个问题就解决了。
(3)、问题:运行时发现按键中断总会加快秒的运行,不是很精确。
原因:最后设置了一个虚拟的key7,当执行完时间指向ease7,然后调用Freshddisplaybuffer函数,这样就很好的解决了这个问题。
在程序调试过程中,设置断点并且在断点处增加一个LED灯,通过判断灯是否亮可以判断程序是否执行到该位置,对程序调试有很大的帮助。
开始WhileKey? 6 1 3 2 4 结束主程序流程图附件程序流程图:Yd_c_inter() Freshddisp laybuffer(); Set_D_T(); noise(); key=7; , 5 NDownNum() ; Freshddispl aybuffer(); Set_D_T(); noise(); key=7; FreshddisplaybufferTime1();Show_Time();Show_Time(); Time1() Freshddis playbuffer ();; Display_D ate(); noise(); 初始化蜂鸣器并关闭蜂鸣器BZOE = 0;初始化 INT 按键 Init_Inter();初始化 Lcd 和 Led; Init_Lcd(),Init_Led();UpNum(); Freshddis playbuffer (); Set_D_T(); noise(); key=7; key = 0; noise(); Time1(); Freshddis playbuffer (); Set_D_T(); noise();初始化按键中断InitKey_INTKR();Time1(); noise();关中断DI ()关中断EI()开中断EI();源代码:#pragma sfr#pragma EI#pragma DI#pragma access#pragma interrupt INTTM000 Time#pragma interrupt INTKR OnKeyPress#pragma interrupt INTP5 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);〃定义变量i,是切换时间的标志//定义 key=0 〃用于存放当前月的天数 〃默认的秒second=0 〃默认的分minute=0 〃默认的时hour=12 〃默认的天day=1 〃默认的月month=5 〃默认的年year=2014 〃默认的闹钟时=1 〃默认的闹钟分=1 〃秒的数码显示缓存区 〃分的数码显示缓存区 〃时的数码显示缓存区 〃天的数码显示缓存区 〃月的数码显示缓存区 〃年的数码显示缓存区 〃月,天的数码显示缓存区 〃时,分的数码显示缓存区 〃分,秒的数码显示缓存区 〃闹钟时的数码显示缓存区 〃闹钟分的数码显示缓存区 //INT 中断中间变量LCD_num[10]={0X070d,0x0600,0x030e,0x070a,0x0603,0x050b,0x050f,0x0700,0x070f,0x070b);//数字0〜〜9的显示码unsigned char Scond;// ......................................................... 延时函数1 .............................................. //void Delay(int k){int i,j;for(i=0;i<k;i++){for(j=0;j<k;j++){〃使用特殊功能寄存器 〃开中断 〃关中断 〃使用绝对地址指令 〃定义时间中断函数为Time 〃定义按键中断为OnKeyPress //定义INT 中断为OnKeyOverchar i=0;int key=0;int temp=1;int temp1 = 1;int second=0;int minute=0;int hour=12;int day=1;int month=5;int year=2014;int c_hour=1;int c_minute=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// .................................................. 初始化Led函数................ //void Init_Led(){PM13=0XF0; 〃端口13的第四位为输出模式PM14=0XF0; 〃端口14的第四位为输出模式PM15=0XF0; 〃端口15的第四位为输出模式)// ............................................................. 按键中断函数............... •//void InitKey_INTKR(){PM4 = 0x3F; //P4的六个端口设置为输入模式PU4 = 0x3F; 〃接通上拉电阻KRM = 0x3F; 〃允许六个按键中断KRMK = 0;PM3.0 = 1;PU3.0 = 1;EGP.5 = 1;PMK5 = 0;PPR5 = 0;KRPR = 1;)// ............................... 初始化lcd函数............... //void Init_Lcd(){ PFALL=0x0F; 〃所有接lcd引脚指定为lcd引脚LCDC0=0x34; 〃设置原时钟和时钟频率LCDMD=0x30; //设置lcd电压为3/5电压LCDM=0xC0; //4分时1/3偏压模式)// ............................... 初始化定时器Inter函数.............. 〃void Init_Inter(){ CRC00)=0; //CR000为比较寄存器PRM00=0X04; 〃计数时钟为fprs/2A8 CR000=0X7FFF;//时间间隔为1s TMMK010=1;//TMMK010 中断屏蔽TMMK000=0; //TMMK000 中断允许TMC00=0X0C; //TM00和CR000相等时进入清零&启动模式)void Time(){ second++;)// ............................................................. 按键中断函数............... •//void OnKeyPress(){DI();switch(P4&0x3F) 〃判断哪个按键按下{case 0x3e:key=1; //按键keyl按下break;case 0x3d:key=2; //按键key2按下break;case 0x3b:key=3; //按键key3按下break;case 0x37:key=4; //按键key4按下break;case 0x2f:key=5; //按键key5按下break;case 0x1f:key=7; //按键key6按下break;default:break;)EI();)// ............................................................... I NT按键中断函数............... //void OnKeyOver(){DI();Que = 0; //判断Que是否为0BZOE = 0; 〃蜂鸣器关闭EI();)// ................................................... Led小灯函数............... //void LightOneLed(unsigned char ucNum){switch(ucNum){ 〃检测变量ucNumcase 0:case 1:case 2:case 3:P13 |= (unsigned char) 1 << (ucNum);〃如果为0到3中的一个值则让LED1到LED4中的一个亮break;case 4:case 5:case 6:case 7:P14 |= (unsigned char) 1 << (ucNum - 4);〃如果为4到7中的一个值则让LED5到LED8中的一个亮break;case 8:case 9:case 10:case 11:P15 |= (unsigned char) 1 << (ucNum - 8);〃如果为8至U 11中的一个值则让LED9至U LED12中的一个亮break;default:break;))// ................................................... Led小灯熄灭函数............... 〃void LightOff(){P13 = 0;P14 = 0;P15 = 0;)// ............................................. 时间函数.............. 〃void Time1(){if((second % 5) == 0){ 〃秒大于 5 变为0Scond = second / 5 + 1;LightOff(); 〃调用小灯亮函数LightOneLed(Scond % 12);)if(second>=60){minute++; //秒大于60时分加1second=0;if(minute>=60){minute=0;hour++; //分大于60时时加1if(hour>=24){hour=0;day++; 〃时大于24时天加1temp=Count_Day(month);if(day>=temp){day=1;month++; 〃天大于当前月份的天数时月加1if(month>=13){month=1;year++; //月大于12时年加1))))))// ...................................... 计算当前月的天数.............. •//int Count_Day(int month){int day;if((month==4)||(month==6)||(month==9)||(month==11))//4,6,9,11 月为30 天day=30;else if(month==2){if((year%4==0&&year%100==0)||(year%400==0))day=29; 〃闰年2月29天elseday=28; //平年2月28天)elseday=31; //1,3,5,7,8,10,12 月为31 天return (day);)// ................................ 倒计时函数 ...... //void Show_Time(){ pokew(0xFA40,0x00); pokew(0xFA42,0x00); pokew(0XFA48,buffs[1]); pokew(0XFA4A,buffs[0]); pokew(0XFA44,buffm[1]); pokew(0XFA46,buffm[0]); pokew(0xFA4C,0x00); pokew(0xFA4E,0x00); Delay(100);) // ..................................................................... 日期显示函数 ................. •// void Display_Date(){buffm[0]|=0x0800;pokew(0xFA40,buffyear[3]);〃显示年 pokew(0xFA42,buffyear[2]);pokew(0xFA44,buffyear[1]);pokew(0xFA46,buffyear[0]);pokew(0xFA48,buffmonth[1]);〃显示月 pokew(0xFA4A,buffmonth[0]);pokew(0xFA4C,buffday[1]);〃显示日pokew(0xFA4E,buffday[0]);temp1=0;) // .................................................................... 时间显示函数 .............. •//void Display_Time(){ pokew(0xFA40,0x00);pokew(0xFA42,0x00);pokew(0xFA44,buffh[1]);〃显示时 pokew(0xFA46,buffh[0]);pokew(0xFA48,buffm[1]);〃显示分 pokew(0xFA4A,buffm[0]);pokew(0xFA4C,buffs[1]);〃显示秒 pokew(0xFA4E,buffs[0]);)// ..................................................................... 设定时间函数 .............. •//void Set_D_T(){int lcd_addr;lcd_addr = 0xFA40;switch(i){case 1:pokew(lcd_addr,buffyear[3]);〃时间年 pokew(lcd_addr+2,buffyear[2]);pokew(lcd_addr+4,buffyear[1]);pokew(lcd_addr+6,buffyear[0]);pokew(lcd_addr+8,0x00);pokew(lcd_addr+10,0x00);pokew(lcd_addr+12,0x00);pokew(lcd_addr+14,0x00);break;case 2:pokew(lcd_addr,0x00);pokew(lcd_addr+2,0x00);pokew(lcd_addr+4,0x00);pokew(lcd_addr+6,0x00);pokew(lcd_addr+8,buffmonth[1]);〃时间月 pokew(lcd_addr+10,buffmonth[0]);pokew(lcd_addr+12,0x00);pokew(lcd_addr+14,0x00);break;case 3:pokew(lcd_addr,0x00); //在lcd 右边显示1〃在lcd 右边显示0 〃在lcd 右边显示1 〃在lcd 右边显示0pokew(lcd_addr+2,0x00);pokew(lcd_addr+4,0x00);pokew(lcd_addr+6,0x00);pokew(lcd_addr+8,0x00);pokew(lcd_addr+10,0x00);pokew(lcd_addr+12,buffday[1]); 〃时间日pokew(lcd_addr+14,buffday[0]);break;case 4:pokew(lcd_addr,0x00);pokew(lcd_addr+2,0x00);pokew(lcd_addr+4,buffh[1]); 〃时间时pokew(lcd_addr+6,buffh[0]);pokew(lcd_addr+8,0x00);pokew(lcd_addr+10,0x00);pokew(lcd_addr+12,0x00);pokew(lcd_addr+14,0x00);break;case 5:pokew(0xFA40,0x00);pokew(0xFA42,0x00);pokew(0xFA44,0x00);pokew(0xFA46,0x00);pokew(0xFA48,buffm[1]); 〃时间分pokew(0xFA4A,buffm[0]);pokew(0xFA4C,0x00);pokew(0xFA4E,0x00);break;case 6:pokew(0xFA40,0xd1);pokew(0xFA42,0xd0);pokew(0xFA44,0xd7);pokew(0xFA46,0xd1);pokew(0xFA48,0x50);pokew(0xFA4A,0x56);pokew(0xFA4C,buffch[1]); 〃闹钟时pokew(0xFA4E,buffch[0]);break;case 7:pokew(0xFA40,0xd1);pokew(0xFA42,0xd0);pokew(0xFA44,0xd7);pokew(0xFA46,0xd1);pokew(0xFA48,0x50);pokew(0xFA4A,0x00);pokew(0xFA4C,buffcm[1]); 〃闹钟分pokew(0xFA4E,buffcm[0]);break;default:break;))// ........................................................ 切换时间函数 .............. …// void d_c_inter(){DI(); 〃关中断i++;if(i>7) 〃切换标志>7, i=1,否则i++i=1;EI(); 〃开中断)// ........................................................ 调整时间加函数 .............. •// void UpNum(){ switch(i){ case 1:year++;case 2:month++;if(month > 12){month = 1;)break;case 3:temp = Count_Day(month);day++;if(temp < day)day = 1;break;case 4:hour++;if(hour > 23)hour = 1;break;case 5:minute++;if(minute > 59)minute = 0;break;case 6:c_hour++;if(c_hour > 23)c_hour = 1;break;case 7:c_minute++;if(c_minute > 59)c_minute = 0;break;default:break;))// ........................................................ 调整时间减函数.............. …// void DownNum(){switch(i){case 1:year--;case 2:month--;if(month < 1){month = 12;)break;case 3:temp = Count_Day(month);day--;if(day < 1)day = temp;break;case 4:hour--;if(hour < 1)hour = 23;break;case 5:minute--;if(minute < 0)minute = 59;break;case 6:c_hour--;if(c_hour < 1)c_hour = 23;break;case 7:c_minute--;if(c_minute < 0)c_minute = 59;break;default: break;))// .................................................. 闹铃以及小灯函数.............. •//void noise(){if(c_hour == hour && c_minute == minute && Que == 1){ 〃闹铃的时,分与系统时,分相等,并且闹钟标志开启CKS=0XE0; 〃开启蜂鸣器输出,输出频率为0.98khz的音频Time1(); 〃调用时间函数))// ........................................................ 显示缓存区刷新时间函数.............. •//void Freshddisplaybuffer(){buffs[1]=LCD_num[second/10];/期的显示码放入秒的数码显示缓存区buffs[0]=LCD_num[second%10];buffm[1]=LCD_num[minute/10];//分的显示码放入分的数码显示缓存区buffm[0]=LCD_num[minute%10];buffm[0]|=0x0800; 〃分的后面显示一个"."buffh[1]=LCD_num[hour/10]; 〃时的显示码放入时的数码显示缓存区buffh[0]=LCD_num[hour%10];buffh[0]|=0x0800; 〃时的后面显示一个"."buffday[1]=LCD_num[day/10];//天的显示码放入天的数码显示缓存区buffday[0]=LCD_num[day%10];buffmonth[1]=LCD_num[month/10];//月的显示码放入月的数码显示缓存区buffmonth[0]=LCD_num[month%10];buffmonth[0]|=0x0800; 〃月的后面显示一个"."buffyear[3]=LCD_num[year/100/10];/^的显示码放入年的数码显示缓存区buffyear[2]=LCD_num[(year/100)%10];buffyear[1]=LCD_num[(year%100)/10];buffyear[0]=LCD_num[(year%100)%10];buffyear[0]|=0x0800; 〃年的后面显示一个"."buffmd[3]=LCD_num[month/10];//月,天的显示码放入月,天的数码显示缓存区buffmd[2]=LCD_num[month%10];buffmd[2]|=0x0800; 〃月,天后显示一个"."buffmd[1]=LCD_num[day/10];buffmd[0]=LCD_num[day%10];buffhm[3]=LCD_num[hour/10];//时,分的显示码放入时,分的数码显示缓存区buffhm[2]=LCD_num[hour%10];buffhm[2]|=0x0800; 〃时,分的后显示一个"."buffhm[1]=LCD_num[minute/10];buffhm[0]=LCD_num[minute%10];buffms[3]=LCD_num[minute/10];/^,秒的显示码放入分,秒的数码显示缓存区buffms[2]=LCD_num[minute%10];buffms[2]|=0x0800; 〃分,秒的后显示一个"."buffms[1]=LCD_num[second/10];buffms[0]=LCD_num[second%10];buffch[1]=LCD_num[c_hour/10];//闹钟时的显示码放入闹钟时的数码显示缓存区buffch[0]=LCD_num[c_hour%10];buffcm[1]=LCD_num[c_minute/10];//闹钟分的显示码放入闹钟分的数码显示缓存区buffcm[0]=LCD_num[c_minute%10];)// ................................. 主函数............... 〃void main(){DI(); 〃关中断PM3.4 = 0; //P3.3,P3.4端口设置为输出模式P3.4 = 1; //led灯初始化为点亮状态PM3.3 = 0;P3.3 = 0;BZOE = 0; 〃蜂鸣器初始化为熄灭Init_Lcd(); 〃初始化lcdInit_Led(); 〃初始化ledInitKey_INTKR(); 〃初始化按键EI(); 〃开中断Init_Inter(); //初始化中断while(1){ Time1(); noise(); switch(key){ case 0: Freshddisplaybuffer(); Time1(); Show_Time();Show_Time(); break; case 1:Time1();Freshddisplaybuffer(); Display_Date(); noise();break;case 2:Time1();Freshddisplaybuffer(); Display_Time(); noise();break;case 3:d_c_inter();Freshddisplaybuffer(); Set_D_T();noise();key=7; break;case 4:UpNum();Freshddisplaybuffer(); Set_D_T();noise();key=7; break;case 5:DownNum();Freshddisplaybuffer(); Set_D_T();noise();key=7; break;case 6:key = 0;if(i > 5)Que = 1;1 = 0;noise();case 7:Time1();Freshddisplaybuffer(); Set_D_T(); 〃调用计算时间函数 〃调用闹钟函数 〃没有按键执行 〃调用刷新函数 〃计算时间 〃调用显示时间函数 //按键1执行 〃计算时间 〃调用刷新函数 〃调用显示日期函数 〃调用闹钟函数 //按键2执行 //计算时间 //调用刷新函数 //调用时间显示函数 //调用闹钟函数 //按键3执行 〃调用时间切换函数 //调用刷新函数 〃调用时间设置函数 //调用闹钟函数 //按键4执行 〃调用时间加函数 //调用刷新函数 //调用时间设置函数 //调用闹钟函数 //按键5执行〃调用时间减函数 //调用刷新函数 //调用时间设置函数//调用闹钟函数//按键6执行〃判断是否确认 //调用闹钟函数〃虚拟按键7 //调用刷新函数//调用时间设置函数〃调用闹钟函数noise();break;。
实时时钟实验总结

实时时钟实验总结一、实验目的本实验的主要目的是了解实时时钟的原理及其应用,掌握实时时钟的使用方法,以及通过实验学习如何编写驱动程序。
二、实验原理1. 实时时钟是一种能够提供时间和日期信息的芯片,它通常由一个晶体振荡器和一组计数器组成。
2. 实时时钟可以通过I2C总线与处理器进行通信,读取或设置时间和日期信息。
3. 实现实时时钟需要编写相应的驱动程序,并将其与操作系统进行集成。
三、实验设备与材料1. 实验板:STM32F407ZET6开发板;2. 模块:DS1307实时时钟模块;3. 软件:Keil uVision5开发环境。
四、实验内容1. 硬件连接:将DS1307模块与STM32F407ZET6开发板连接,包括SDA、SCL、VCC和GND等引脚。
2. 编写驱动程序:根据DS1307模块手册编写相应的驱动程序,并将其集成到操作系统中。
3. 测试程序:编写测试程序,通过读取DS1307模块返回的时间和日期信息来验证驱动程序是否正常工作。
五、实验步骤1. 连接硬件:将DS1307模块与STM32F407ZET6开发板连接。
2. 编写驱动程序:根据DS1307模块手册编写相应的驱动程序,并将其集成到操作系统中。
3. 编写测试程序:编写测试程序,通过读取DS1307模块返回的时间和日期信息来验证驱动程序是否正常工作。
4. 下载程序:使用Keil uVision5开发环境将编写好的程序下载到STM32F407ZET6开发板上。
5. 运行测试:启动STM32F407ZET6开发板,通过串口助手等工具查看DS1307模块返回的时间和日期信息,验证驱动程序是否正常工作。
六、实验结果经过测试,实时时钟模块能够正确返回当前时间和日期信息,并且能够根据需要进行设置和调整。
七、实验总结本次实验通过对实时时钟原理的学习以及编写驱动程序和测试程序的练习,加深了对嵌入式系统中硬件与软件协同工作的理解。
同时也掌握了一些基本的嵌入式系统开发技能,如硬件连接、驱动编写、调试等。
嵌入式系统原理实时时钟

四实实验验设设备备
JXARM9-2410教学实验箱 ADT1000仿真器和ADT IDE集成开发环境
五 基础知识
实时时钟在嵌入式系统中的作用
在一个嵌入式系统中,实时时钟单元可以其提供可靠的 时钟,包括时分秒和年月日;即使在系统处于关机状态 下它也能够正常工作(通常采用后备电池供电),它的 外围也不需要太多的辅助电路,典型的就是只需要一个 高精度的晶振。
2410option.inc Configuration options for .S files
2410memcfg.inc Memory bank configuration file
2410lib.c
S3C2410 PLL,Uart, LED, Port Init
2410addr.h S3C2410 Define Address Register
五 基础知识
S3C2410的实时时钟
时钟数据采用BCD编码 能够对闰年的年月日进行自动处理 具有告警功能,当系统处于关机状态时,能产生告警中断; 具有独立的电源输入 提供毫秒级时钟中断,该中断可用于作为嵌入式操作系统的内核时钟
五 基础知识
S3C2410的实时时钟寄存器
实时时钟控制寄存器 告警控制寄存器 实时时钟计数器
Interrupt.c
串口接口函数说明(2410lib.c)
配置系统时钟 void ChangeMPllValue(0xa1,0x3,0x1); //FCLK=202.8MHz void ChangeClockDivider(1,1)// 修改实时时钟当前时间、日期 void rtc_set_date(st_date* p_date) 获取实时时钟当前时间、日期 void rtc_get_date(st_date* p_date) 初始化S3C2410的TICK定时器 void rtc_tick_init( char tick ) 设置S3C2410的告警时间以及方式 void rtc_alarm_set(st_date* p_date, unsigned char mode)
嵌入式实验:实时时钟实验

Irq_Request(IRQ_RTC, rtc_int_isr);
rRTCCON = 0x01;
rALMYEAR = p_date->year;
rALMMON = p_date->mon;
rALMDATE = p_date->day;
rALMHOUR = p_date->hour;
rALMMIN = p_date->min;
// Argument : p_date,待设置的日期
*****************************************************************************/
void rtc_set_date(st_date* p_date)
{
rRTCCON = 0x01;
Irq_Enable(IRQ_TICK);
}
/*****************************************************************************
// Function name: rtc_alarm_set
// Description:设置S3C2410的告警时间以及方式
rRTCCON = 0x00;
}
/*****************************************************************************
// Function name: rtc_get_date
// Description:获取实时时钟当前时间、日期
/*表示日期、时间的数据结构*/
typedef struct ST_DATE
嵌入式课程设计基于51单片机的实时时钟设计报告

目录摘要 (4)第1章设计要求 (5)1.1设计要求 (5)1.2设计内容 (5)1.3设计基本环境 (5)第2章设计方案和论证 (6)2.1总设计原理框图 (6)2.2设计方案选择 (7)第3章硬件电路 (8)3.1单片机的选择 (8)3.1.1 单片机内部原理分析 (8)3.1.2单片机的引脚及封装 (9)3.1.3单片机最小系统 (11)3.2 数码管显示工作原理 (11)3.3 8255A模块 (12)3.4时间调节模块 (13)3.4.1 时间设置 (13)3.4.2整点报时 (13)第4章软件调试 (14)4.1时间调节程序流程图 (14)4.2主程序流程图 (18)第5章仿真调试 (22)第6章总结与体会 (23)第7章参考文献 (23)摘要单片计算机即单片微型计算机。
由RAM ,ROM,CPU构成,集定时,计数和多种接口于一体的微控制器。
它体积小,成本低,功能强,广泛应用于智能产业和工业自动化上。
而51系列单片机是各单片机中最为典型和最有代表性的一种。
通过本子课程设计掌握单片机的基本原理,加深对课堂知识的理解,从而达到学习、设计、开发单片机软硬的能力。
本课程设计由AT89C51,BUTTON,六段数码管等构成,结合单片机最小系统晶振电路作为驱动电路,复位电路作为系统复位使用;结合proteus和keil软件进行设计此系统,通过四个按键调整走时时间和定时时间,由定时器定时并在数码管上显示相应的时间,通过中断和按键扫描实现对时间的停止、启动和设置调整。
程序利用C语言进行编写,结合单片机的引脚的以及相关知识完成程序的编写,由延时程序和循环程序产生的一秒定时,达到时分秒的计时,六十秒为一分钟,六十分钟为一小时,满二十四小时为一天。
运行仿真时,可以显示时钟走时时间,通过按键可以修改时间,以及可以进行手动设置闹钟闹铃时间,同时通过蜂鸣器进行闹铃的效果,通过仿真调试效果真实、准确,节省了硬件资源。
嵌入式实时时钟

实时时钟一、实验目的1.掌握RTC (Real Time Clock) 工作原理。
2.学习掌握其编程实验方法及应用。
二、实验内容阅读芯片手册,掌握RTC工作原理、编程方法及应用。
三、预备知识1.用ARM ADS1.2集成开发环境,编写和调试程序的基本过程。
2.ARM应用程序的框架结构。
3.RTC工作原理四、实验设备及工具硬件:ARM嵌入式开发板、用于ARM7TDMI的JTAG仿真器、PC机Pentumn100以上、串口线软件:PC机操作系统win98、Win2000或WinXP、ARM ADS1.2集成开发环境、仿真器驱动程序、RTC实验原理及说明五、实验原理1.RTC原理实时时钟(RTC---- Real Time Clock)的基本功能是保持跟踪时间和日期等信息,但许多RTC还提供有多种附加功能,如:看门狗定时器、系统复位、非易失存储器(NV RAM)、序列号、方波输出、涓流充电等。
接口方式RTC芯片提供有多种接口方式,其中并行接口可实现存储器的快速访问或有较大的存储容量,适合于那些对价格、尺寸要求不是很荷刻的系统,许多采用并行接口的实时时钟芯片还与晶振和电池封装在一起构成一个完整的时钟模块,从而简化了硬件设计。
并行接口包括复用总线(数据与地址总线复用)和独立的地址、数据总线。
一般用于时间保持的NV RAM都采用与SRAM相同的控制信号,并可以方便地与常用的微处理器容量。
另外,有些Phantom实时时钟还将时钟数据隐含在备用电池支持的RAM内,以便利用64位软件协议来访问时钟数据。
一般情况下,串行接口时钟芯片都具有外形尺寸较小、成本低廉等优势,但这类芯片的通信速率一般较低,因而比较适合便携式产品。
这类芯片通常包括1-Wire 接口、2线、3线、4线或SPI接口,而许多处理器也包括2线或SPI接口,当然,也有些处理器(如8051及其派生产品)则支持复用的地址和数据总线。
备用电池在有些应用中(如VCR),时钟和日期信息在系统掉电时将会丢失,而在大多数应用中要求系统主电池断电时仍保持时钟和日期有效。
嵌入式数字时钟实验总结

嵌入式数字时钟实验总结本次实验是关于嵌入式数字时钟的设计与实现。
我们通过使用单片机和数码管,成功构建了一个功能完善的数字时钟。
在实验过程中,我们学习了嵌入式系统的基本原理和设计技巧,同时也加深了对数字电路和计时器的理解。
首先,我们明确了实验的目标和需求。
作为一款嵌入式数字时钟,它应该具备显示时间、日期的功能,同时还可以提供闹钟功能和计时功能。
基于这些需求,我们进行了系统的设计和功能模块的划分。
其次,我们选用了适合该项目的硬件平台和软件开发工具。
我们选择了一款功能强大且易于使用的单片机作为主控芯片,以满足系统的高效运行和稳定性要求。
同时,我们使用了一种高亮度的数码管,以保证时间和日期的清晰显示。
然后,我们通过系统设计和模块划分来完成软件的开发。
我们根据系统需求,将整个项目划分为多个模块,如时钟模块、日期模块、闹钟模块和计时模块等。
每个模块都有相应的功能和逻辑,通过合理的调用和交互,实现了整个系统的协调运行。
在实验过程中,我们遇到了一些问题并找到了解决办法。
例如,由于数码管的显示限制,我们需要通过七段数码管的编码方式来进行显示。
我们通过查阅资料和试验,成功实现了数码管的显示功能。
另外,由于闹钟和计时功能需要精确的时间控制,我们使用了定时器和中断的方法来实现,确保了系统的准确性和稳定性。
最后,我们对实验结果进行了测试和调试。
通过测试,我们发现嵌入式数字时钟能够正常显示时间和日期,并且闹钟和计时功能也运行良好。
我们还对系统进行了性能和稳定性测试,发现系统响应快速、界面友好,并且稳定运行。
通过本次实验,我们不仅学到了嵌入式系统的设计和开发技能,还获得了对数字电路和计时器的深入理解。
同时,我们也意识到了实际工程项目中的挑战和困难,锻炼了解决问题的能力。
我们相信这次实验经历对我们今后的学习和工作都具有重要意义。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
上海电力学院嵌入式软件开发基础实验报告题目:【ARM】实时时钟实验专业:电子科学与技术年级:姓名:学号:一、实验目的1、了解实时时钟的硬件控制原理及设计方法。
2、掌握S3C44B0X 处理器的RTC 模块程序设计方法。
二、实验设备1、硬件:Embest EduKit-III 实验平台,Embest ARM 标准/增强型仿真器套件,PC 机。
2、软件:Embest IDE Pro ARM 集成开发环境,Windows 98/2000/NT/XP。
三、实验内容学习和掌握 Embest EduKit-III 实验平台中RTC 模块的使用,进行以下操作:1、编写应用程序,修改时钟日期及时间的设置。
2、使用EMBEST ARM 教学系统的串口,在超级终端显示当前系统时间。
四、实验原理1. 实时时钟(RTC)实时时钟(RTC)器件是一种能提供日历/时钟、数据存储等功能的专用集成电路,常用作各种计算机系统的时钟信号源和参数设置存储电路。
RTC 具有计时准确、耗电低和体积小等特点,特别是在各种嵌入式系统中用于记录事件发生的时间和相关信息,如通信工程、电力自动化、工业控制等自动化程度高的领域的无人值守环境。
随着集成电路技术的不断发展,RTC 器件的新品也不断推出,这些新品不仅具有准确的RTC,还有大容量的存储器、温度传感器和A/D 数据采集通道等,已成为集RTC、数据采集和存储于一体的综合功能器件,特别适用于以微控制器为核心的嵌入式系统。
RTC 器件与微控制器之间的接口大都采用连线简单的串行接口,诸如I2C、SPI、MICROWIRE和CAN 等串行总线接口。
这些串口由2~3 根线连接,分为同步和异步。
2. S3C44B0X 实时时钟(RTC)单元S3C44B0X 实时时钟(RTC)单元是处理器集成的片内外设。
由开发板上的后备电池供电,可以在系统电源关闭的情况下运行。
RTC 发送8 位BCD 码数据到CPU。
传送的数据包括秒、分、小时、星期、日期、月份和年份。
RTC 单元时钟源由外部32.768KHz 晶振提供,可以实现闹钟(报警)功能。
S3C44B0X 实时时钟(RTC)单元特性:BCD 数据:秒、分、小时、星期、日期、月份和年份1、闹钟(报警)功能:产生定时中断或激活系统2、自动计算闰年3、无2000 年问题4、独立的电源输入5、支持毫秒级时间片中断,为RTOS 提供时间基准读/写寄存器访问 RTC 模块的寄存器,首先要设RTCCON 的bit0 为1。
CPU 通过读取RTC 模块中寄存器BCDSEC、BCDMIN、BCDHOUR、BCDDAY、BCDDATE、BCDMON 和 BCDYEAR 的值,得到当前的相应时间值。
然而,由于多个寄存器依次读出,所以有可能产生错误。
比如:用户依次读取年(1989)、月(12)、日(31)、时(23)、分(59)、秒(59)。
当秒数为1 到59 时,没有任何问题,但是,当秒数为0 时,当前时间和日期就变成了1990 年1 月1 日0 时0 分。
这种情况下(秒数为0),用户应该重新读取年份到分钟的值(参考程序设计)。
后备电池:RTC 单元可以使用后备电池通过管脚RTCVDD 供电。
当系统关闭电源以后,CPU 和RTC 的接口电路被阻断,后备电池只需要驱动晶振和BCD 计数器,从而达到最小的功耗。
闹钟功能RTC 在指定的时间产生报警信号,包括CPU 工作在正常模式和休眠(power down)模式下。
在正常工作模式,报警中断信号(ALMINT)被激活。
在休眠模式,报警中断信号和唤醒信号(PMWKUP)同时被激活。
RTC 报警寄存器(RTCALM)决定报警功能的使能/屏蔽和完成报警时间检测。
时间片中断RTC 时间片中断用于中断请求。
寄存器TICNT 有一个中断使能位和中断计数。
该中断计数自动递减,当达到0 时,则产生中断。
中断周期按照下列公式计算:Period = ( n+1 ) / 128 second其中,n 为RTC 时钟中断计数,可取值为(1-127)置零计数功能RTC 的置零计数功能可以实现30、40 和50 秒步长重新计数,供某些专用系统使用。
当使用50秒置零设置时,如果当前时间是11:59:49,则下一秒后时间将变为12:00:00。
注意:所有的RTC 寄存器都是字节型的,必须使用字节访问指令(STRB、LDRB)或字符型指针访问。
五、实验设计1. 硬件电路设计2. 软件程序设计(1)时钟设置时钟设置程序必须实现时钟工作情况以及数据设置有效性检测功能。
具体实现可以参考示例程序设计。
(2)时钟显示时钟参数通过实验系统串口0 输出到超级终端,显示内容包括年月日时分秒。
参数以BCD 码形式传送,用户使用串口通信函数(参见串口通信实验)将参数取出显示。
/********************************************************************************************** name: rtc_read* func: read data from rtc* para: none* ret: none* modify:* comment:*********************************************************************************************/void rtc_read(void){while(1){// read the data from RTC registersif(rBCDYEAR == 0x99)g_nYear = 0x1999;elseg_nYear = 0x2000 + rBCDYEAR;g_nMonth = rBCDMON;g_nDay = rBCDDAY;g_nWeekday = rBCDDATE;g_nHour = rBCDHOUR;g_nMin = rBCDMIN;g_nSec = rBCDSEC;if(g_nSec != 0)break;}}/********************************************************************************************** name: rtc_display* func: display data from rtc* para: none* ret: none* modify:* comment:*********************************************************************************************/void rtc_display(void){rtc_read();uart_printf("\n\rCurrentTimeis%02x-%02x-%02x%s",g_nYear,g_nMonth,g_nDay,f_szdate[g_nWeekday]);uart_printf(" %02x:%02x:%02x\r\n",g_nHour,g_nMin,g_nSec);}六、实验操作步骤1. 准备实验环境使用Embest 仿真器连接目标板,使用Embest EduKit-III 实验板附带的串口线,连接实验板上的UART0 和PC 机的串口。
2. 串口接收设置在PC 机上运行windows 自带的超级终端串口通信程序(波特率115200、1 位停止位、无校验位、无硬件流控制);或者使用其它串口通信程序。
3. 打开实验例程1)拷贝光盘CD1\Software\EduKit44b0 文件夹到EmbestIDE\Examples\Samsung\目录下;2) 使用Embest IDE 通过Embest JTAG 仿真器连接实验板,打开实验例程目录4.5_rtc_test子目录下的rtc_test.pjf 例程,编译链接工程;3) 点击IDE 的Debug 菜单,选择Remote Connect 项或F8 键,远程连接目标板;4) 点击IDE 的Debug 菜单,选择Download 下载调试代码到目标系统的RAM 中;5) 点击Debug 菜单的Go 或F5 键运行程序。
4. 观察实验结果1).在PC 机上观察超级终端程序主窗口,可以看到如下界面:boot success...RTC Test ExampleRTC Check(Y/N)?2).用户可以选择是否对RTC 进行检查,检查正确的话,继续执行程序,检查不正确时也会提示是否重检查:RTC Check(Y/N)? ySet Default Time at 2004-12-31 FRI 23:59:59Set Alarm Time at 2005-01-01 00:00:01... RTC Alarm Interrupt O.K. ...Current Time is 2005-01-01 SAT 00:00:01RTC Working now. To set date(Y/N)?3).用户可以选择是否重新进行时钟设置,当输入不正确时也会提示是否重新设置:RTC Working now. To set date(Y/N)? y Current date is (2005,01,01, SAT). input new date (yy-mm-dd w): 5-2-23 3Current date is: 2005-02-23 WEDRTC Working now. To set time(Y/N)? y Current time is (00:02:57).To set time(hh:mm:ss): 19:32:54).最终超级终端输出信息如下:Current Time is 2005-02-23 WED 19:32:05 19:32:07七、实验参考程序1. 环境及函数声明ARM7 基础实验教程- 196 -/*------------------------------------------------------------------------------------------*//* global variables *//*------------------------------------------------------------------------------------------*/int g_nYear;intg_nMonth,g_nDay,g_nWeekday,g_nHour,g_nMi n,g_nSec;/*------------------------------------------------------------------------------------------*//* function declare *//*------------------------------------------------------------------------------------------*/int test_rtc_alarm(void);void rtc_init(void);void read_rtc(void);void display_rtc(void);void test_rtc_tick(void);void rtc_int(void);void rtc_tick(void);2. 时钟设置控制程序/******************************************************* *************************************** name: rtc_set_date* func: get and check the DATE string from uart channel to set rtc* para: none* ret: cN09 = 0 : invalid string* cN09 = 1 : set date by input string and ok* modify:* comment:******************************************************** *************************************/int rtc_set_date(char *pString){char cYn,cN09=1;char szStr[12]; // xxxx-xx-xx xint i,nTmp;memcpy((void *)szStr, pString, 12);// check the format of the datanTmp = 0;cN09 = 1;for(i = 0;((i <12)&(szStr[i] != '\0')); i++){ if((szStr[i] == '-')|(szStr[i] == ' '))nTmp += 1;}if(nTmp < 3) // at least 2 '-' and 1 ' '{ARM7 基础实验教程- 197 -cN09 = 0;uart_printf(" InValid format!!\n\r");}else // check if number 0 - 9{nTmp = i - 1; // adjust the account number// 1:MON 2:TUE 3:WED 4:THU 5:FRI 6:SAT 7:SUNif((szStr[nTmp] < '1' | szStr[nTmp] > '7')) // check weekdaycN09 = 0;for( i = nTmp; i >= 0; i--){if(!((szStr[i] == '-')|(szStr[i] == ' ')))if((szStr[i] < '0' | szStr[i] > '9'))cN09 = 0;}}// write the data into rtc registerif(cN09){rRTCCON = 0x01; // R/W enable, 1/32768, Normal(merge), No reseti = nTmp;nTmp = szStr[i]&0x0f;if(nTmp == 7)rBCDDATE = 1; // s3c44b0x: SUN:1 MON:2 TUE:3 WED:4 THU:5 FRI:6 SAT:7elserBCDDATE = nTmp+1; // -> weekday;nTmp = szStr[i-=2]&0x0f;if(szStr[--i] != '-')nTmp |= (szStr[i--]<<4)&0xff;if(nTmp > 0x31)cN09 = 0;rBCDDAY = nTmp; // -> day;nTmp = szStr[--i]&0x0f;if(szStr[--i] != '-')nTmp |= (szStr[i--]<<4)&0xff;if(nTmp > 0x12)cN09 = 0;rBCDMON = nTmp; // -> month;nTmp = szStr[--i]&0x0f;if(i)nTmp |= (szStr[--i]<<4)&0xff;if(nTmp > 0x99)cN09 = 0;rBCDYEAR = nTmp; // -> year;rRTCCON = 0x00; // R/W disableuart_printf(" Current date is:20%02x-%02x-%02x %s\n",rBCDYEAR,rBCDMON,rBCDDAY,f_szdate[rBC DDATE]);if(!cN09)uart_printf(" Wrong value!\n");}else uart_printf(" Wrong value!\n");return (int)cN09;}/******************************************************* *************************************** name: rtc_set_time* func: get and check the TIME string from uart channel to set rtc* para: none* ret: cN09 = 0 : invalid string* cN09 = 1 : set time by input string and ok* modify:* comment:******************************************************** *************************************/int rtc_set_time(char *pString){char cYn,cN09=1;char szStr[8]; // xx:xx:xxint i,nTmp;memcpy((void *)szStr, pString, 8);// check the format of the datanTmp = 0;cN09 = 1;for(i = 0;((i < 8)&(szStr[i] != '\0')); i++){if(szStr[i] == ':')nTmp += 1;}if(nTmp != 2) // at least 3 ':'{ cN09 = 0;uart_printf(" InValid format!!\n\r");}else{nTmp = i - 1;for( i = nTmp; i >= 0; i--){if(szStr[i] != ':')if((szStr[i] < '0' | szStr[i] > '9'))cN09 = 0;}}// write the data into rtc registerif(cN09){rRTCCON = 0x01; // R/W enable, 1/32768, Normal(merge), No reseti = nTmp;nTmp = szStr[i]&0x0f;if(szStr[--i] != ':')nTmp |= (szStr[i--]<<4)&0xff;if(nTmp > 0x59)cN09 = 0;rBCDSEC = nTmp; // -> second;nTmp = szStr[--i]&0x0f;if(szStr[--i] != ':')nTmp |= (szStr[i--]<<4)&0xff;if(nTmp > 0x59)cN09 = 0;rBCDMIN = nTmp; // -> min;nTmp = szStr[--i]&0x0f;if(i)nTmp |= (szStr[--i]<<4)&0xff;if(nTmp > 0x24)cN09 = 0;rBCDHOUR = nTmp; // -> hour; rRTCCON = 0x00; // R/W disableif(!cN09)uart_printf(" Wrong value!\n");ARM7 基础实验教程- 200 -}else uart_printf(" Wrong value!\n");return (int)cN09;}八、实验体会第一、对ARM的相关理论知识有了初步的了解。