摘 要
在日常生活中,手表,闹钟是不可或缺的。在实际生活生产活动中,也要考虑时间的因素,如工时的计算,霓虹灯的亮灭。
因为集成电路制造技术的不断提高,出现了高性能、高可靠的集成芯片。电子时钟在工业领域,日常生活中得到了广泛的应用。电子时钟在性能方面具有精度高,实时性好,易于调整等优点。这些使得温度控制系统的研究和开发得到的各方面的广泛关注和支持。
本次课程设计,我利用8254计数芯片,8255芯片,4*4小键盘,12864LCD液晶显示器,蜂鸣器制作了一个带有闹钟功能的电子时钟万年历。它可以实现由4*4小键盘输入初始时间(包括年月日时分秒星期),利用8254计数,通过程序处理进位,判断闰年,在液晶显示屏上实时显示时间。还可以由小键盘选择不同的闹钟模式,设定闹钟时间。
关键词 : 电子时钟 ; 8255A芯片; 8254芯片; 12864LCD液晶显示器; 键盘输入; 蜂鸣器; 闹钟功能; 万年历
目 录
1.设计任务与要求 …………………………………………………………………6- 实验目的 ………………………………………………………………………6 具体要求 ………………………………………………………………………6 2. 总体方案与说明 …………………………………………………………………6- 使用硬件 ………………………………………………………………………6 流程设计 ………………………………………………………………………6 系统程序模块………………………………………………………………6 系统流程图…………………………………………………………………7
3.硬件方案……………………………………………………………………………7
硬件说明 ………………………………………………………………………7 计数芯片8254………………………………………………………………7 可编程外围接口芯片8255A………………………………………………8 128×64字符液晶显示器…………………………………………………11 电路原理图与说明 …………………………………………………………12 键盘电路……………………………………………………………………13 8254计数电路……………………………………………………………13 液晶显示电路……………………………………………………………14 电路连接图 ………………………………………………………………14 8254计数芯片………………………………………………………………14 整体电路……………………………………………………………………15
4.软件方案…………………………………………………………………………15 软件主要模块流程图 ……………………………………………………15 输入子程序模块流程图…………………………………………………16 显示子程序模块流程图…………………………………………………18 闰年子程序模块流程图…………………………………………………18 蜂鸣器子程序模块流程图…………………………………………………18 时间进位程序模块流程图…………………………………………………19 主程序模块流程图…………………………………………………………20 源程序清单与注释 ……………………………………………………21
5.分析与测试………………………………………………………………………38 6.运行结果………………………………………………………………………38 试验线路图 …………………………………………………………39
实验结果 ………………………………………………………………39 欢迎界面…………………………………………………………………39 闹钟设定界面………………………………………………………………40 闹钟功能实现……………………………………………………………41 闰年功能实现……………………………………………………………41
7.结论与体会………………………………………………………………………43 结论 …………………………………………………………………………43 体会 …………………………………………………………………………44 参考文献……………………………………………………………………………45 -
1 设计任务与要求
实验目的
1.复习8255芯片,8254芯片工作原理及使用方法 2.学会使用12864字符液晶显示屏,蜂鸣器 3.锻炼小规模逻辑电路设计 4.提高分析、解决问题的能力
具体要求
本系统要求能通过4*4键盘输入预设时间,实时反映当前时间的变化并能对闰年进行准确判断。另外,当时间与预先设置的闹钟时间相同时,能够蜂鸣,并在电脑屏幕上显示。
2 总体方案与说明
使用硬件
8255芯片、8254芯片、12864字符液晶显示器、蜂鸣器、4*4键盘
流程设计
系统程序模块
系统流程图
3硬件方案
硬件说明
计数芯片8254
8254 芯片是一款使用十分广泛的可编程定时,计数芯片,其主要功能是定时和计数的功能。我们的微机内的动态存储器刷新电路,系统日时钟的技术以及发声系统的声源都是由8254芯片来完成的。 结构
8254 芯片的外部引脚和内部结构如下图
工作原理
8254芯片共有六种工作方式,分别对应与六种不同的用途。 (1)方式0:计数到0结束输出正跃变信号方式。 (2)方式1:硬件可重触发单稳方式。 (3)方式2:频率发生器方式。 (4)方式3:方波发生器。
(5)方式4:软件触发选通方式。 (6)方式5:硬件触发选通方式。 可编程外围接口芯片8255A
8255A是一种通用的可编程并行I/O接口芯片,它是为Intel系列微处理器设计配套电路,也可用于其他微处理器系统中。通过对它编程,芯片可工作于不同的工作方式。在微型计算机系统中,用8255A做接口时,通常不需要附加外部逻辑电路就可直接为CPU与外设之间提供数据通道,因此得到了极为广泛的应用。 结构和功能
8255A的外部引脚和内部结构如下图
图
3-3
8255
外
部
引
脚
图
图3-4 8255内部功能图
由图可见,8255A由数据端口A、B、C(期中,C口被分为C口上半部分和C口下半部分),A组和B组控制逻辑,数据总线缓冲器和读写控制逻辑。
8255A内部包含3个8位输入输出端口,通过外部的24根输入输出线与外设进行通信联络。A口和B口可以用作8位输入口或8位输出口。C口既可以用作8位输入输出口用,也可作为两个4位的输入输出口。还常常用来配合A口和B
口工作,分别用来产生A口和B口的输出控制信号和输入A口和B口的端口状态端口信号。
表3-1 8255A的基本操作
A1 0 0 1 0 0 1 1 X 1 X A0 0 1 0 0 1 0 1 X 1 X RD 0 0 0 1 1 1 1 X 0 1 WR 1 1 1 0 0 0 X 1 1 CS 0 0 0 0 0 0 1 0 0 操作 端口A→数据总线 端口B→数据总线 端口C→数据总线 数据总线→端口A 数据总线→端口B 数据总线→端口C 数据总线→控制字寄存器 数据总线三态 非法状态 数据总线三态 8255A的控制字 方式选择控制字
8255A具有3种基本工作方式。 方式0:基本输入输出方式; 方式1:选通输入输出方式; 方式2:双向总线I/O方式。
端口A可以工作于3种方式中的任一种;端口B只能工作于方式0和方式1,而不能工作于方式2;端口C常被分成2个4位端口,除了用做输入输出端口外,还能用来配合A口和B口工作,为这两个端口的输入输出操作提供联络信号。
图3-5 8255方式选择控制字格式
工作方式 A.方式0
基本输入输出方式,它适用于不需要应答信号的简单输入输出场合。在这种方式下,A口和B口可作为8位端口,C口的高4和低4为可作为两个4为端口。 CPU与这些端口交换数据时,可以直接输入指令从端口读取数据,或用输出指令将数据写入指定端口,不需要任何其他联络信号。 B.方式1
选通输入/输出方式。在这种方式下,A口和B口作为数据口,均可用于输入或
输出方式。而且这两个8位数据口的输入、输出数据都能锁存,但它们必须在联络信号的控制下才能完成I/O操作。端口C的6根线用来产生或接受这些联络信号。 C.方式2
双向总线方式。只有A口可以工作于这种方式。在这种方式下,CPU与外设交换数据时,可在单一的8位端口数据线PA7-PA9上进行,既可以通过A口把数据传送到外设,又可以从A口接收从外设送来的数据,而且输入和输出的数据均能锁存,但输入和输出不能同时进行 128×64字符液晶显示器
ST7920是台湾矽创电子公司生产的中文图形控制芯片,它是一种内置128×64-12汉字图形点阵的液晶显示控制模块,用于显示汉字及图形。12864A-1汉字图形点阵液晶显示模块集成ST7920驱动器,可显示汉字及图形,内置8192个中文汉字(16×16点阵)、128个字符(8×16点阵)及64×256点阵显示RAM(GDRAM)。 结构
图3-6 LCD液晶字符显示器外形尺寸
图3-7 LCD液晶字符坐标
工作原理
12864液晶显示器工作于并行模式。8位数据线与8255A芯片8位数据口连接,控制口(E、R/W、D/I)与8255A芯片C口四位相连。
通过8255A的8位数据空向12864液晶显示器传送数据,通过C口低四位传送
控制信号。控制口E为使能端,高电位有效。R/W为读写控制,低点位为写数据、高电位为读数据。D/I为数据与命令口,低电位为命令、高电位为数据。 将需要显示的地址通过数据口以命令的形式送入显示器,再将需要显示的数据通过数据口以数据的形式送入显示器,即可显示内容。
表3-2 LCD汉字显示坐标
Line1 Line2 Line3 Line4
X坐标 80H 90H 88H 98H 81H 91H 89H 99H 82H 92H 8AH 9AH 83H 93H 8BH 9BH 84H 94H 8CH 9CH 85H 95H 8DH 9DH 86H 96H 8EH 9EH 87H 97H 8FH 9FH
图3-8 LCD中文字库截图
电路原理图与说明
键盘输入电路
图3-9 键盘输入电路原理图
8254计数电路
图3-10 计数电路原理图
液晶显示电路
图3-11 液晶显示电路原理图
电路连接图
8254计数芯片
整体电路
4 软件方案
软件主要模块流程图
输入子程序模块流程图
图4-1 输入子程序模块流程图
显示子程序模块流程图
闰年子程序模块流程图
时间进位程序模块流程图
蜂鸣器子程序模块流程图
主程序模块流程图
源程序清单与注释
#include<>;/*头文件*/ #include<> #include<> #include \"\"
#pragma comment(lib,\"\") char
lcd1[10]={0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3};char
lcd2[10]={0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9};
char l1[8]={0,0xd2,0xb6,0xc8,0xcb,0xce,0xc1,0xc8};/*字符机内码数组*/ char l2[8]={0,0xbb,0xfe,0xfd,0xc4,0xe5,0xf9,0xd5}; char
lhy1[32]={0xb5,0xe7,0xd7,0xd3,0xca,0xb1,0xd6,0xd3,0xcd,0xf2,0xc4,0xea,0xc0,0xfa,0xa1,0xef,0xa1,0xf1,0xbb,0xb6,0xd3,0xad,0xc4,0xfa,0xca,0xb9,0xd3,0xc3,0xa1,0xc3,0xa3,0xa9}; char
lhy2[32]={0xc7,0xeb,0xca,0xb9,0xd3,0xc3,0xd0,0xa1,0xbc,0xfc,0xc5,0xcc,0xca,0xe4,0xc8,0xeb,0xa1,0xf9,0xd6,0xc6,0xd7,0xf7,0xa1,0xaa,0xcb,0xce,0xca,0xc0,0xbb,0xdb,0xa1,0xf9}; char
sd1[64]={0xc7,0xeb,0xc9,0xe8,0xb6,0xa8,0xc4,0xd6,0xd6,0xd3,0xc4,0xa3,0xca,0xbd,0xa2,0xa0,0xa2,0xd9,0xca,0xb1,0xb7,0xd6,0xc3,0xeb,0xa2,0xa0,0xa2,0xa0,0xa2,0xa0,0xa2,0xa0,0xa2,0xda,0xd0,0xc7,0xc6,0xda,0xca,0xb1,0xb7,0xd6,0xc3,0xeb,0xa2,0xa0,0xa2,0xa0,0xa2,0xdb,0xc4,0xea,0xd4,0xc2,0xc8,0xd5,0xca,0xb1,0xb7,0xd6,0xc3,0xeb,0xa2,0xa0};
char sd2[16]={0xc7,0xeb,0xc9,0xe8,0xb6,0xa8,0xc4,0xd6,0xd6,0xd3,0xca,0xb1,0xbc,0xe4,0xa2,0xa0};
void clear(); void cmdsetup(); void datasetup(); void input();/*数字输入*/
void show(int,int); /*数字显示*/ void show1(int,int,int);/*单位显示*/ void show2(int);/*星期显示*/ void showhy();/*欢迎界面显示*/ void showclr();/*界面清屏*/ void showsd1();/*设定界面1显示*/ void showsd2(); int days(int,int);
void clock();/*蜂鸣器闹铃*/ byte i,k; int j;
void main() {
int year,month,day,week,hour,minute,second; int
flag,scheduledyear,scheduledmonth,scheduledday,scheduledweek,scheduledhour,scheduledminute,scheduledsecond; byte data;;
showhy();/*欢迎界面显示*/ showclr();
showsd1();/*闹钟模式界面显示*/
input(); flag=j; showclr();
showsd2();/*闹钟设定模式界面显示*/
if (flag==1) /*闹钟模式1 输入,显示预设时分秒*/ {
show1(0x92,0xca,0xb1); show1(0x8a,0xb7,0xd6); show1(0x9a,0xc3,0xeb);
k=0x90; input();
scheduledhour=10*j; k=0x91; input();
scheduledhour=scheduledhour+j;
k=0x88; input();
scheduledminute=10*j; k=0x89; input();
scheduledminute=scheduledminute+j;
k=0x98; input();
scheduledsecond=10*j; k=0x99; input();
scheduledsecond=scheduledsecond+j;
showclr(); }
if (flag==2) /*闹钟模式2 输入,显示预设星期时分秒*/ {
show1(0x90,0xd0,0xc7); show1(0x91,0xc6,0xda); show1(0x96,0xca,0xb1); show1(0x8a,0xb7,0xd6); show1(0x8e,0xc3,0xeb);
k=0x92; input();
scheduledweek=j;
k=0x94; input();
scheduledhour=10*j; k=0x95; input();
scheduledhour=scheduledhour+j;
k=0x88; input();
scheduledminute=10*j; k=0x89; input();
scheduledminute=scheduledminute+j;
k=0x8c; input();
scheduledsecond=10*j; k=0x8d; input();
scheduledsecond=scheduledsecond+j;
showclr(); }
if (flag==3) /*闹钟模式3 输入,显示预设年月日时分秒*/ {
show1(0x94,0xc4,0xea); show1(0x97,0xd4,0xc2); show1(0x8a,0xc8,0xd5); show1(0x8e,0xca,0xb1); show1(0x9a,0xb7,0xd6); show1(0x9e,0xc3,0xeb); k=0x90; input();
scheduledyear=1000*j; k=0x91; input();
scheduledyear=scheduledyear+100*j; k=0x92;
input();
scheduledyear=scheduledyear+10*j; k=0x93; input();
scheduledyear=scheduledyear+j;
k=0x95; input();
scheduledmonth=10*j; k=0x96; input();
scheduledmonth=scheduledmonth+j; k=0x88; input();
scheduledday=10*j; k=0x89; input();
scheduledday=scheduledday+j;
k=0x8c; input();
scheduledhour=10*j; k=0x8d; input();
scheduledhour=scheduledhour+j;
k=0x98; input();
scheduledminute=10*j; k=0x99; input();
scheduledminute=scheduledminute+j;
k=0x9c; input();
scheduledsecond=10*j; k=0x9d; input();
scheduledsecond=scheduledsecond+j;
showclr(); }
k=0x80; /*输入,显示预设的年月日时分秒星期*/ input(); year=j*1000;
k++; /*K储存字符显示在液晶屏的地址*/ input();
year=year+j*100; k++; input(); year=year+j*10; k++; input(); year=year+j;
k++; show1(k,0xc4,0xea); k=0x90; input(); month=j*10; k++; input(); month=month+j; k++;
show1(k,0xd4,0xc2);
k=0x94; input(); day=j*10; k++; input(); day=day+j; k++;
show1(k,0xc8,0xd5);
k=0x88;
show1(k,0xd0,0xc7); k++;
show1(k,0xc6,0xda); k++; input(); week=j;
/*显示单位汉字*/ k=0x8c; input(); hour=j*10; k++; input(); hour=hour+j; k++;
show1(k,0xca,0xb1);
k=0x98; input(); minute=j*10; k++; input();
minute=minute+j; k++;
show1(k,0xb7,0xd6);
k=0x9b; input(); second=j*10; k++; input();
second=second+j;
k++;
show1(k,0xc3,0xeb)
printf(\"Press any key to begin!\\n\\n\"); getch();
cout< PortWriteByte(0x28b,0x82); /* ,8255B口输入*/ PortWriteByte(0x283,0x77); /*01110111,通道1,方式3,bcd计数*/ PortWriteByte(0x280,0x00); /*写入初值1000*/ PortWriteByte(0x280,0x10); PortWriteByte(0x283,0xb1); /*,通道2,方式0,bcd计数*/ PortWriteByte(0x281,0x00); /*写入初值2000*/ PortWriteByte(0x281,0x20); while(!(data&&0x10)) /* B4检出高电平,证明1秒过去*/ { PortReadByte(0x289,&data); } second++; /* 时间更新进位*/ if (second>=60) { minute++; if (minute>=60) { hour++; if (hour>=24) { week++; if (week>=7) {week=1;} /* 星期数归1,而不是归0*/ day++; if (day>days(month,year)) /* 调用闰年子程序,计算当月应有天数*/ { month++; if (month>=12) { year++; month=1; /* 月份数归1,而不是归0*/ } day=1; /* 天数数归1,而不是归0*/ } hour=0; } minute=0; } second=0; } cout< ((flag==1)&&(hour==scheduledhour)&&(minute==scheduledminute)&&(second==scheduledsecond)) clock(); /* 调用蜂鸣器子程序*/ if ((flag==2)&&(week==scheduledweek)&&(hour==scheduledhour)&&(minute==scheduledminute)&&(second==scheduledsecond)) clock(); if ((flag==3)&&(year==scheduledyear)&&(month==scheduledmonth)&&(day=scheduledday)&&(hour=scheduledhour)&&(minute==scheduledminute)&&(second==scheduledsecond)) clock(); k=0x80; /* 调用显示子程序*/ show(year/1000,k); /* 液晶屏上显示更新后的时间日期*/ k++; show(year/100%10,k); /* 逐位分离*/ k++; show(year/10%10,k); k++; show(year%10,k); k=0x90; show(month/10,k); k++; show(month%10,k); k=0x94; show(day/10,k); k++; show(day%10,k); k=0x8a; show2(week); k=0x8c; show(hour/10,k); k++; show(hour%10,k); k=0x98; show(minute/10,k); k++; show(minute%10,k); k=0x9b; show(second/10,k); k++; show(second%10,k); } } /************************/ /* 数字输入 */ /************************/ void input() { { } printf(\"ERROR: Open Device Error!\\n\"); return; if(!Startup()) /* 检查设备是否正确打开*/ byte data; printf(\"Press any key to begin!\\n\\n\"); getch(); printf(\"请输入数字\\n\"); while(!kbhit()) { PortWriteByte(0x28b,0x81); PortWriteByte(0x28a,0x0f); i=data; if (i!=0x0f) { i=data; Sleep(50); /* 延时*/ PortWriteByte(0x28b,0x88); /* 防抖动,再次读入,初始化8255*/ PortWriteByte(0x28a,0xf0); i=i|data; if (i==0x77) j=0; /* 将按键值转化为数字*/ else if(i==0x7b) j=1; else if(i==0x7d) j=2; /* 向C口高4位送1111*/ PortReadByte(0x28a,&data); /* 读取C口高4位*/ /* 初始化8255*/ /* 向C口低4位送1111*/ PortReadByte(0x28a,&data); /* 读取C口低4位*/ else if(i==0x7e) j=3; else if(i==0xb7) j=4; else if(i==0xbb) j=5; else if(i==0xbd) j=6; else if(i==0xbe) j=7; else if(i==0xd7) j=8; else if(i==0xdb) j=9; else; printf(\"%d\\n\ /* 电脑屏幕显示*/ if (k==0x8a) {show2(j); /* 显示星期数,使用汉字*/ Cleanup(); return;} show(j,k); } } } /************************/ /* LCD显示 */ /************************/ void show(int j,int k) { if(!Startup()) { printf(\"ERROR: Open Device Error!\\n\"); return; /* 检查设备是否正确打开*/ Cleanup(); return; } PortWriteByte(0x28b,0x80); clear(); PortWriteByte(0x288,k); /*向A口送入字符在液晶屏上显示的地址*/ cmdsetup(); Sleep(10); /*延时*/ PortWriteByte(0x288,lcd1[j]); datasetup(); /*向A口送入字符机内码高位*/ /*设8255为方式0,C口输出,A口输出*/ PortWriteByte(0x288,lcd2[j]); datasetup(); /*向A口送入字符机内码低位*/ return; } void show1(int k,int j1,int j2) /*在液晶屏上显示单位 */ { printf(\"请进行下一位\\n\"); PortWriteByte(0x28b,0x80); clear(); PortWriteByte(0x288,k); cmdsetup(); Sleep(10); PortWriteByte(0x288,j1); datasetup(); PortWriteByte(0x288,j2); datasetup(); Cleanup(); return; } void show2(int j) /*显示星期数,一至日 */ { PortWriteByte(0x28b,0x80); clear(); PortWriteByte(0x288,k); cmdsetup(); Sleep(10); PortWriteByte(0x288,l1[j]); datasetup(); /*设8255为方式0,C口输出,A口输出*/ cout<<\"aaaaaaaa\"< getch(); PortWriteByte(0x288,l2[j]); datasetup(); return; } void showhy() /*显示欢迎界面 */ { printf(\"Press any key to begin!\\n\\n\"); if(!Startup()) } PortWriteByte(0x28b,0x80); clear(); PortWriteByte(0x288,0x80); cmdsetup(); Sleep(10); for (i=0;i<16;i++) { PortWriteByte(0x288,lhy1[i]); datasetup(); }; PortWriteByte(0x288,0x90); cmdsetup(); Sleep(10); for (i=16;i<32;i++) { PortWriteByte(0x288,lhy1[i]); datasetup(); }; PortWriteByte(0x288,0x88); cmdsetup(); Sleep(10); for (i=0;i<16;i++) { { printf(\"ERROR: Open Device Error!\\n\"); return; getch(); cout<<\"aaaaaaaa\"< PortWriteByte(0x288,0x98); cmdsetup(); Sleep(10); for (i=16;i<32;i++) { PortWriteByte(0x288,lhy2[i]); datasetup(); }; Cleanup(); return; } void showsd1() /*显示闹钟模式选择界面 */ { printf(\"Press any key to begin!\\n\\n\"); if(!Startup()) { printf(\"ERROR: Open Device Error!\\n\"); return; /*设8255为方式0,C口输出,A口输出*/ getch(); cout<<\"aaaaaaaa\"< PortWriteByte(0x28b,0x80); clear(); PortWriteByte(0x288,0x80); cmdsetup(); Sleep(10); for (i=0;i<16;i++) { PortWriteByte(0x288,sd1[i]); datasetup(); }; PortWriteByte(0x288,0x90); cmdsetup(); Sleep(10); for (i=16;i<32;i++) { PortWriteByte(0x288,sd1[i]); datasetup(); }; PortWriteByte(0x288,0x88); cmdsetup(); Sleep(10); for (i=32;i<48;i++) { PortWriteByte(0x288,sd1[i]); datasetup(); }; PortWriteByte(0x288,0x98); cmdsetup(); Sleep(10); for (i=48;i<64;i++) { PortWriteByte(0x288,sd1[i]); datasetup(); }; Cleanup(); return; } void showsd2() /*显示闹钟预设时间设定界面 */ { printf(\"Press any key to begin!\\n\\n\"); if(!Startup()) { printf(\"ERROR: Open Device Error!\\n\"); return; getch(); cout<<\"aaaaaaaa\"< PortWriteByte(0x28b,0x80); clear(); PortWriteByte(0x288,0x80); cmdsetup(); Sleep(10); for (i=0;i<16;i++) /*设8255为方式0,C口输出,A口输出*/ { PortWriteByte(0x288,sd2[i]); datasetup(); }; Cleanup(); return; } void showclr() /*以显示满屏空格的方法来进行清屏 */ { printf(\"Press any key to begin!\\n\\n\"); if(!Startup()) { printf(\"ERROR: Open Device Error!\\n\"); return; getch(); cout<<\"aaaaaaaa\"< PortWriteByte(0x28b,0x80); clear(); PortWriteByte(0x288,0x80); cmdsetup(); Sleep(10); for (i=0;i<8;i++) { PortWriteByte(0x288,0xa2); datasetup(); PortWriteByte(0x288,0xa0); datasetup(); }; PortWriteByte(0x288,0x90); cmdsetup(); Sleep(10); for (i=0;i<8;i++) { PortWriteByte(0x288,0xa2); datasetup(); PortWriteByte(0x288,0xa0); datasetup(); }; PortWriteByte(0x288,0x88); cmdsetup(); Sleep(10); for (i=0;i<8;i++) { PortWriteByte(0x288,0xa2); datasetup(); PortWriteByte(0x288,0xa0); datasetup(); }; PortWriteByte(0x288,0x98); cmdsetup(); Sleep(10); for (i=0;i<8;i++) { PortWriteByte(0x288,0xa2); datasetup(); PortWriteByte(0x288,0xa0); datasetup(); }; Cleanup(); return; } void clear() { PortWriteByte(0x288,0x0c); cmdsetup(); } void cmdsetup() { PortWriteByte(0x289,0x00); Sleep(1); PortWriteByte(0x289,0x04); Sleep(1); PortWriteByte(0x289,0x00); Sleep(1); } void datasetup() { PortWriteByte(0x289,0x01); Sleep(1); PortWriteByte(0x289,0x05); Sleep(1); PortWriteByte(0x289,0x01); Sleep(1); } /************************/ /* 闰年计算 */ /************************/ int days(int month,int year) { int rn; /*闰年标记,=1代表是闰年 */ if((year%4==0&&year%100!=0)||year%400==0) { rn=1;} else{rn=0;} switch(month) /*返回每月应有天数 */ { case 1: return 31; case 2: if(rn==1){return 29;} /*考虑闰年情况,返回2月份应有天数 */ else {return 28;} case 3: return 31; case 4: return 30; case 5: return 31; case 6: return 30; case 7: return 31; case 8: return 31; case 9: return 30; case 10: return 31; case 11: return 30; case 12: return 31; } } /************************/ /* 蜂鸣器闹铃*/ /************************/ void clock() { PortWriteByte(0x28b,0x80); /*初始化8255,B口输出*/ PortWriteByte(0x289,0x80); /*由B7向蜂鸣器送高电平,启动蜂鸣器*/ cout<<\"到时间啦!!!\"< 5 分析与测试 首先,在连接键盘和显示程序后,总是无法达到设想中的效果,后来发现是遗漏了检查设备是否正常启动的Startup(),Cleanup()之类的部分。 将8254的OUT2接入B4口后,发现总是无法检测到高电平。后来发现,是控制字的问题。在输入,显示过程中,B口一直作为输出口。但这种情况下,B口应当是输入口。后来在程序中增添了重新初始化8253的语句,解决了问题。 开始时,所有的时间单位都是清零的,后来测试数据时出现了0日,0月的笑话。才发现,天数,月份,星期都是要归一而不是清零。同时是>=边界值,还是>边界值,也要谨慎考虑。 没有找到可以一次完全清除液晶屏上所有数据的语句,所以采取了向所有位送空格的方式实现了清屏。 程序运行后,发现每次跑秒的时间不一样,而且液晶显示屏和电脑显示屏有不规律的不同步现象,咨询老师后,证明是硬件原因造成,如晶振,内部延迟时间。 6 运行结果 实验线路图 图6-1 实验接线实物图 实验结果 欢迎界面 闹钟设定界面 闹钟功能实现 选择闹钟模式1,闹钟时间设定为13时52分10秒,初始时间设定为13时50分10秒,如下图所示。 闰年功能实现 当输入2013年(非闰年)2月28日23时59分12秒为初始时间后,可观察到时间由2月28日跳转到3月1日。 证明程序判断出此年份为非闰年,2月只有28天。 当输入2012年(闰年)2月29日23时59分12秒为初始时间后,可观察到时间由2月29日跳转到3月1日。 证明程序判断出此年份为闰年,2月应有29天。 参考资料 [1].周荷琴 吴秀清编著. 微型计算机原理与接口技术(第四版).合肥:中国科学技术大学出版社,2008. 因篇幅问题不能全部显示,请点此查看更多更全内容