实时时钟设计实验报告.docx
《实时时钟设计实验报告.docx》由会员分享,可在线阅读,更多相关《实时时钟设计实验报告.docx(26页珍藏版)》请在冰豆网上搜索。
![实时时钟设计实验报告.docx](https://file1.bdocx.com/fileroot1/2023-3/1/5b009446-54c2-4047-aa58-5debb13f6a5a/5b009446-54c2-4047-aa58-5debb13f6a5a1.gif)
实时时钟设计实验报告
实验报告
姓名
学号
专业班级
课程名称
实验日期
成绩
实验名称
实时时钟设计
一、实验环境
1)µPD78F0485单片机:
接受来自PC的程序,并通过实验盒中的LCD显示屏、蜂鸣器、LED灯等部件显示出来。
2Notepad++:
编写修改源程序;
3)软件NECElectronicsMicrocomputer:
运行所编写的源程序;
二、实验内容
1、电路原理
μPD78F0485单片机外围硬件端口P13到端口P15都是具有输出锁存功能的4位I/O端口。
实验中选择这三个端口分别控制12个LED灯的亮灭。
端口4是具有输出锁存功能的8位I/O端口,有P40到P47共8个I/O引脚。
选择P40到P45共6个端口与6个按钮连接,当对按键模式寄存器KRM进行有效设置,并且在P40/KR0到P47/KR7引脚上输入一个下降沿信号时,就会产生一个按键返回中断信号INTER。
P34引脚连接一个led灯,P33引脚连接一个蜂鸣器。
LCD驱动方式为4分时1/3偏压,驱动电压为3V,通过COM0—COM3,SEG0-SEG19引脚连接1个LCD显示屏
2、实验步骤
(1)、设计时钟功能对应到每个按键并设计各个时钟函数如显示年月日函数Display_Date()。
(2)、打开PM+V6.31软件,新建一个工作空间(SS)。
(3)、在PMplus环境下在“File”选项下选择“New”,在弹出的窗口中编写源程序。
(4)、编译源程序并调试成功。
(5)、设置PMplus环境并且安装µPD78F0485单片机。
(6)、运行结果并改进。
3、实验结果
单片机通电后运行启动Show_Time()函数和分秒计数函数。
Led小灯从P13.1开始每五秒顺时针一个一个亮。
Key1按键后显示年月日,key2按下后显示时分秒,按下key3键则可以在年,月,日,时,分,闹钟时,闹钟分之间进行切换。
按下key4键则可以进行加1调整。
按下key5键则可以进行减1调整。
按下key6键则确定,小灯灭。
按下INT键则闹钟结束。
4、操作说明
1.无按键
Lcd显示屏中间显示程序默认分秒00.00,并且时间运行。
P13.1灯亮,其它灯按照5秒顺时针一次亮。
2.按下Key1
Lcd显示屏显示程序默认日期2014.05.12。
Led灯按照5秒顺时针一个一个亮。
3.按下Key2
Lcd显示屏显示程序时间,并且时间运行。
Led灯按照5秒顺时针一个一个亮。
4.按下Key3
每按一下按键,Lcd显示屏中间循环显示年,月,日,时,分,闹钟时,闹钟分。
Led灯按照5秒顺时针一个一个亮。
5.按下Key4
Key3执行时,该按键执行加一操作,Led灯按照5秒顺时针一个一个亮。
6.按下Key5
Key3执行时,该按键执行减一操作,Led灯按照5秒顺时针一个一个亮。
7.按下Key6
Key3执行时,该按键执行确定操作,Led灯按照5秒顺时针一个一个亮。
8.按下INT
闹钟关闭。
5、实验总结
本次实验是对课本上“电子日历钟设计”的加深。
通过本次试验我对led和lcd显示有了更加熟悉的认识,能熟练应用它们的功能。
同时我对时钟计数器也有了一定的认识,可以使用定时中断实现实时时钟,更重要的是我的实践能力有很大的提高。
程序设计中遇到的问题
(1)、问题:
初始完成程序后秒针走的时间很快,不是精确的一秒走一次。
原因:
单片机只能用主系统时间,修改fprs后可以真确显示。
(2)、问题:
时间切换函数与显示函数和设计的不一样,如只需要显示时,却多显示分。
原因:
在仔细看代码后发现每次按键中断都在调用time1()函数,而second++在里面,所以每次都会加快秒的运行。
把second++移到外面放入time()函数后这个问题就解决了。
(3)、问题:
运行时发现按键中断总会加快秒的运行,不是很精确。
原因:
最后设置了一个虚拟的key7,当执行完时间指向case7,然后调用Freshddisplaybuffer();函数,这样就很好的解决了这个问题。
在程序调试过程中,设置断点并且在断点处增加一个LED灯,通过判断灯是否亮可以判断程序是否执行到该位置,对程序调试有很大的帮助。
附件:
程序流程图:
主程序流程图
源代码:
#pragmasfr//使用特殊功能寄存器
#pragmaEI//开中断
#pragmaDI//关中断
#pragmaaccess//使用绝对地址指令
#pragmainterruptINTTM000Time//定义时间中断函数为Time
#pragmainterruptINTKROnKeyPress//定义按键中断为OnKeyPress
#pragmainterruptINTP5OnKeyOver//定义INT中断为OnKeyOver
voidInit_Led();
voidInitKey_INTKR();
voidInit_Lcd();
voidInit_Inter();
voidLightOneLed(unsignedcharucNum);
voidLightOff();
intCount_Day(intmonth);
chari=0;//定义变量i,是切换时间的标志
intkey=0;//定义key=0
inttemp=1;//用于存放当前月的天数
inttemp1=1;
intsecond=0;//默认的秒second=0
intminute=0;//默认的分minute=0
inthour=12;//默认的时hour=12
intday=1;//默认的天day=1
intmonth=5;//默认的月month=5
intyear=2014;//默认的年year=2014
intc_hour=1;//默认的闹钟时=1
intc_minute=1;//默认的闹钟分=1
intbuffs[2];//秒的数码显示缓存区
intbuffm[2];//分的数码显示缓存区
intbuffh[2];//时的数码显示缓存区
intbuffday[2];//天的数码显示缓存区
intbuffmonth[2];//月的数码显示缓存区
intbuffyear[4];//年的数码显示缓存区
intbuffmd[4];//月,天的数码显示缓存区
intbuffhm[4];//时,分的数码显示缓存区
intbuffms[4];//分,秒的数码显示缓存区
intbuffch[2];//闹钟时的数码显示缓存区
intbuffcm[2];//闹钟分的数码显示缓存区
unsignedcharQue=0;//INT中断中间变量
intLCD_num[10]={0X070d,0x0600,0x030e,0x070a,0x0603,0x050b,0x050f,0x0700,0x070f,0x070b};//
数字0~~9的显示码
unsignedcharScond;
//…………………………延时函数1……………………//
voidDelay(intk){
inti,j;
for(i=0;ifor(j=0;j}
}
}
//………………………初始化Led函数……………………//
voidInit_Led(){
PM13=0XF0;//端口13的第四位为输出模式
PM14=0XF0;//端口14的第四位为输出模式
PM15=0XF0;//端口15的第四位为输出模式
}
//……………………………按键中断函数……………………//
voidInitKey_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函数……………………//
voidInit_Lcd(){
PFALL=0x0F;//所有接lcd引脚指定为lcd引脚
LCDC0=0x34;//设置原时钟和时钟频率
LCDMD=0x30;//设置lcd电压为3/5电压
LCDM=0xC0;//4分时1/3偏压模式
}
//………………初始化定时器Inter函数……………………//
voidInit_Inter(){
CRC00.0=0;//CR000为比较寄存器
PRM00=0X04;//计数时钟为fprs/2^8
CR000=0X7FFF;//时间间隔为1s
TMMK010=1;//TMMK010中断屏蔽
TMMK000=0;//TMMK000中断允许
TMC00=0X0C;//TM00和CR000相等时进入清零&启动模式
}
voidTime(){
second++;
}
//……………………………按键中断函数……………………//
voidOnKeyPress(){
DI();
switch(P4&0x3F)//判断哪个按键按下
{
case0x3e:
key=1;//按键key1按下
break;
case0x3d:
key=2;//按键key2按下
break;
case0x3b:
key=3;//按键key3按下
break;
case0x37:
key=4;//按键key4按下
break;
case0x2f:
key=5;//按键key5按下
break;
case0x1f:
key=7;//按键key6按下
break;
default:
break;
}
EI();
}
//……………………………INT按键中断函数……………………//
voidOnKeyOver(){
DI();
Que=0;//判断Que是否为0
BZOE=0;//蜂鸣器关闭
EI();
}
//………………………Led小灯函数……………………//
voidLightOneLed(unsignedcharucNum){
switch(ucNum){//检测变量ucNum
case0:
case1:
case2:
case3:
P13|=(unsignedchar)1<<(ucNum);
//如果为0到3中的一个值则让LED1到LED4中的一个亮
break;
case4:
case5:
case6:
case7:
P14|=(unsignedchar)1<<(ucNum-4);
//如果为4到7中的一个值则让LED5到LED8中的一个亮
break;
case8:
case9:
case10:
case11:
P15|=(unsignedchar)1<<(ucNum-8);
//如果为8到11中的一个值则让LED9到LED12中的一个亮
break;
default:
break;
}
}
//………………………Led小灯熄灭函数……………………//
voidLightOff(){
P13=0;
P14=0;
P15=0;
}
//……………………时间函数……………………//
voidTime1(){
if((second%5)==0){//秒大于5变为0
Scond=second/5+1;
LightOff();//调用小灯亮函数
LightOneLed(Scond%12);
}
if(second>=60){
minute++;//秒大于60时分加1
second=0;
if(minute>=60){
minute=0;
hour++;//分大于60时时加1
if(hour>=24){
hour=0;
day++;//时大于24时天加1
temp=Count_Day(month);
if(day>=temp){
day=1;
month++;//天大于当前月份的天数时月加1
if(month>=13){
month=1;
year++;//月大于12时年加1
}
}
}
}
}
}
//…………………计算当前月的天数……………………//
intCount_Day(intmonth){
intday;
if((month==4)||(month==6)||(month==9)||(month==11))//4,6,9,11月为30天
day=30;
elseif(month==2)
{if((year%4==0&&year%100==0)||(year%400==0))
day=29;//闰年2月29天
else
day=28;//平年2月28天
}
else
day=31;//1,3,5,7,8,10,12月为31天
return(day);
}
//………………倒计时函数.............//
voidShow_Time(){
pokew(0xFA40,0x00);
pokew(0xFA42,0x00);
pokew(0XFA48,buffs[1]);//在lcd右边显示1
pokew(0XFA4A,buffs[0]);//在lcd右边显示0
pokew(0XFA44,buffm[1]);//在lcd右边显示1
pokew(0XFA46,buffm[0]);//在lcd右边显示0
pokew(0xFA4C,0x00);
pokew(0xFA4E,0x00);
Delay(100);
}
//………………………………日期显示函数……………………//
voidDisplay_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;
}
//………………………………时间显示函数……………………//
voidDisplay_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]);
}
//………………………………设定时间函数……………………//
voidSet_D_T(){
intlcd_addr;
lcd_addr=0xFA40;
switch(i){
case1:
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;
case2:
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;
case3:
pokew(lcd_addr,0x00);
pokew(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;
case4:
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;
case5:
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;
case6:
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;
case7:
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;
}
}
//…………………………切换时间函数……………………//
voidd_c_inter(){
DI();//关中断
i++;
if(i>7)//切换标志>7,i=1,否则i++
i=1;
EI();//开中断
}
//…………………………调整时间加函数……………………//
voidUpNum(){
switch(i){
case1:
year++;
case2:
month++;
if(month>12){
month=1;
}
break;
case3:
temp=Count_Day(month);
day++;
if(tempday=1;
break;
case4:
hour++;
if(hour>23)
hour=1;
break;
case5:
minute++;
if(minute>59)
minute=0;
break;
case6:
c_hour++;
if(c_hour>23)
c_hour=1;
break;
case7:
c_minute++;
if(c_minute>59)
c_minute=0;
break;
default:
break;
}
}
//…………………………调整时间减函数……………………//
voidDownNum(){
switch(i){
case1:
year--;
case2:
month--;
if(month<1){
month=12;
}
break;
case3:
temp=Count_Day(month);
day--;
if(day<1)
day=temp;
break;
case4:
hour--;
if(hour<1)
hour=23;
break;
case5:
minute--;
if(minute<0)
minute=