点击链接获取Keil源码与Project Backups仿真图:
https://download.csdn.net/download/qq_64505944/87695258?spm=1001.2014.3001.5503
源码获取
主要内容:
1.设计出电子数字钟的电路,并用protus进行仿真画出对应的电路图
2.设计出电子数字钟的源程序,并用Keil进行编辑生成HEX文件
3.在protus中进行测试。
基本要求:
1、电子数字钟电路设计图;
2、电子数字钟设计源程序;
2、keil运行源程序;
3、protus中仿真;
4、运行结果分析。
主要参考资料:
[1] 谭浩强.C.程序设计.北京:清华大学出版社,2002
[2] 王为青,程国刚.单片机 Keil Cx51 应用技术开发,北京:人民邮电大学出版社,2007
[3] 马忠梅等.单片机的C语言应用程序设计.北京航空航天大学出版社,2003.
完 成 期 限:12 月 11 日 - 12 月 26 日
指导教师签名:
课程负责人签名:
摘 要
随着科技的发展,时代的进步,数字电子钟成为了我们生活当中的必需品,数字钟是采用数字电路实现对 .时, 分,秒.数字显示的计时装置 ,广泛用于个人家庭 ,车站, 码头办公室等公共场所 ,成为人们日常生活中不可少的必需品 , 由于数字集成电路的发展和石英晶体振荡器的广泛应用 , 使得数字钟的精度, 远远超过老式钟表 , 钟表的数字化给人们生产 生活带来了极大的方便,而且大大地扩展了钟表原先的报时功能。诸如定时自动报警、按时 自动打铃、时间程序自动控制、定时广播、自动起闭路灯、定时开关烘箱、通断动力设备、 甚至各种定时电气的自动启用等,所有这些,都是以钟表数字化为基础的。因此,研究数字钟及扩大其应用,有着非常现实的意义。
与传统的机械钟相比,电子钟具有更突出的优点。由于电子钟采用数字集成电路的发展和采用了先进的石英技术,使电子钟具有走时准确、性能稳定、携带方便等优点,电子钟用于定时自动报警、按时自动打铃、时间程序自动控制、定时广播及自动控制等各个领域。本次课程设计将采用protus进行电路的仿真模拟,使用Keil完成对程序的编程。最终实现数字电子钟的模拟
关 键 词:protus;Keil;1602数字电子钟;
目录
摘 要 I
目录 II
-
1602数字电子钟开发方法 1
1.1开发背景 1
1.2开发平台 1
1.3 设计目的 2
1.4 设计要求 2 -
系统设计 3
2.1功能设计 3
2.2 电路设计 3
2.3 单片机控制系统 3
2.4 LM016L显示器 4 -
电路整体设计 6
3.1 显示模块设计 6
3.2按键模块设计 6
3.3复位电路模块设计 7
3.4蜂鸣器设计 8
3.5 电路整体设计 8 -
程序设计 10
4.1 程序整体设计 10
5.测试与运行 24
5.1 电子钟显示测试 24
5.2 时间调节测试 24
5.3 设定闹钟测试 26 -
总结 27
参考文献 28 -
1602数字电子钟开发方法
1.1开发背景
1602数字电子时钟是人们日常生活中不可或缺的必需品电子钟主要是利用现代电子技术将时钟电子化数字化与传统的机械钟相比具有时钟精确显示直观无机械传动装置等优点因而得到广泛应用另外在生活和工农业生产中人们对电子钟的功能又提出了诸多要求报时闹钟日历温度显示这就需要电子时钟的多功能性与传统的机械钟相比,电子钟具有更突出的优点。由于电子钟采用数字集成电路的发展和采用了先进的石英技术,使电子钟具有走时准确、性能稳定、携带方便等优点,电子钟用于定时自动报警、按时自动打铃、时间程序自动控制、定时广播及自动控制等各个领域。
1.2开发平台
(1)本次数字电子钟开发所用的平台是proteus,Proteus软件是英国Lab Center Electronics公司出版的EDA工具软件。它不仅具有其它EDA工具软件的仿真功能,还能仿真单片机及外围器件。它是比较好的仿真单片机及外围器件的工具。虽然国内推广刚起步,但已受到单片机爱好者、从事单片机教学的教师、致力于单片机开发应用的科技工作者的青睐。
Proteus是英国著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。是世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DSPIC33、AVR、ARM、8086和MSP430等,2010年又增加了Cortex和DSP系列处理器,并持续增加其他系列处理器模型。在编译方面,它也支持IAR、Keil和MATLAB等多种编译器。
(2)Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。Keil提供了包括C编译器、宏汇编、链接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(μVision)将这些部分组合在一起。运行Keil软件需要WIN98、NT、WIN2000、WINXP等操作系统。如果你使用C语言编程,那么Keil几乎就是你的不二之选,即使不使用C语言而仅用汇编语言编程,其方便易用的集成环境、强大的软件仿真调试工具也会令你事半功倍。
(3)Windows 11是由微软公司(Microsoft)开发的操作系统,应用于计算机和平板电脑等设备。于2021年6月24日发布,2021年10月5日发行。
Windows 11提供了许多创新功能,增加了新版开始菜单和输入逻辑等,支持与时代相符的混合工作环境,侧重于在灵活多变的体验中提高最终用户的工作效率。
1.3 设计目的
通过本次课程设计,运用《单片机微型计算机原理及应用》的知识,设计出一个简单的1602电子钟,从而将课堂上所讲的理论知识与实际的操作给结合在一起,已达到对知识的复习,提高自己的动手能力。
1.4 设计要求
设计一个单片机系统,利用Keil来进行程序的书写与编程并且用proteus软件完成系统软硬件的设计及模拟调试。要求以AT89C51为控制系统,LM016为显示器,便且能够通过按钮来调整时钟的时间的一个建议的电子数字钟。最后能够在显示器上正常的显示时间,并且可以调节时间。
2.系统设计
2.1功能设计
1、设计一个有“时”,“分”,“秒”(23小时59分59秒)显示且可以调节时间的电子钟。
2、用中小规模集成电路组成电子钟。
2.2 电路设计
想做好一个单片机系统,首先必须想好应该用什么样子的电路,并且把需要的用的电路元件给拿出来,如图2-1电路设计流程图所示:
图2-1控制系统
2.3 单片机控制系统
本次实现1602数字钟采用的控制系统是AT89C51。AT89C51是一种带4K字节闪烁可编程可擦除只读存储器(FPEROM—FalshProgrammable and Erasable Read Only Memory )的低电压,高性能CMOS8位微处理器,俗称单片机。AT89C2051是一种带2K字节闪烁可编程可擦除只读存储器的单片机。单片机的可擦除只读存储器可以反复擦除100次。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,AT89C2051是它的一种精简版本。AT89C51单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。该控制系统如图2-2所示:
图2-2 控制系统
2.4 LM016L显示器
LM016L液晶模块采用HD44780控制器,hd44780具有简单而功能较强的指令集,可以实现字符移动,闪烁等功能,LM016L与单片机MCU通讯可采用8位或4位并行传输两种方式,hd44780控制器由两个8位寄存器,指令寄存器(IR)和数据寄存器(DR)忙标志(BF),显示数RAM(DDRAM),字符发生器ROMA(CGOROM)_字符发生器RAM(CGRAM),地址计数器RAM(AC)IR用于资存指令码,只能写入丕能读出;DR用于资存数据。数据由内部操作自动写入 DDRAM和CGRAM,或者暂存从 DDRAM和CGRAM读出的数据, BF为1时,液品模块处于内部模式,不响应外部操作指令和接受数据,DDTAM用来存储显示的字符,能存储80个字符码,CGROM由8位字符码生成57点阵字符160中和510点阵字符32种.8位字符编码和字符的对应关系,CGRAM 是为用户编写特殊字符留用的,它的容量仅64字节,可以自定义8个57点阵字符或者4个510点阵字符,AC可以存储DDRAM和CGRAM的地址,如果地址码随指令写入R,则R自动把地址码装入AC,同时选择 DDRAM或CGRA,LM016L液品模块的引脚功能如图2-3所示:
图2-3 LM016L显示器
- 电路整体设计
3.1显示模块设计
本次课程设计采用的是LM016L为显示器,以及使用RESPACK-8和3214G-1-104E组成显示模块,显示器模块图如图3-1所示:
图3-1 LM016L显示器模块
3.2按键模块设计
因为要求时钟可以调节时间,因此按键模块需要使5个按键来调节时间。用五个调整按键调整时间﹐分别为KI·K2·K3·K4·K5,其中K1键为功能选择键﹐可以调节时或分﹔K2为数值加一键﹔K3为数值减一键,K4为确认键,K5为调节闹钟的按键。按键模块设计如图3-2所示:
图3-2 按键模块设计
3.3复位电路模块设计
单片机在启动时都需要复位,以使CPU及系统各部件处于确定的初始状态,并从初态开始工作。89系列单片机的复位信号是从RST引脚输入到芯片内的施密特触发器中的。当系统处于正常工作状态时,且振荡器稳定后,如果RST引脚上有一个高电平并维持2个机器周期(24个振荡周期)以上,则CPU就可以响应并将系统复位。复位电路如图3-3所示:
图3-3 复位电路模块设计
3.4蜂鸣器设计
单片机SOUNDER是什么,sounder是数字蜂鸣器元件。蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。蜂鸣器的设计如图3-4所示:
图3-4 蜂鸣器设计
3.5 电路整体设计
单片机的电子电路设计中要求能够满足单一操作的要求,即能够通過简单的操作就完成电子设备的系统功能。但是电子电路设计在功能作用中却要求能够实现综合化发展。当前单片机在电子设备系统中的应用,其能够起到完善电子设备系统安全功能、显示功能、预警功能等辅助功能,更好地推动电子设备系统的智能化,精细化发展。电路的整体设计关乎此次课程设计的成功与否,是本次课程设计的重中之重。
该1602电子数字钟的整体的电路设计图如图3-5所示:
图3-4 电路整体设计
- 程序设计
4.1 程序整体设计
完成了电路的设计,想要将该电路运行起来,当然离不开程序的设计,只有程序设计的符合电路的工作条件,与电路结合在一起才能使该电路运行起来,因此,该电子时钟的程序设计的代码如下所示:
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit RS=P2^6;
sbit RW=P2^5;
sbit E=P2^7;
sbit K1=P1^0;
sbit K2=P1^1;
sbit K3=P1^2;
sbit K4=P1^3;
sbit K5=P1^4;
sbit BEEP=P3^0;
unsigned char cishu=0;
unsigned char mode_flag;//状态标志位 0表示正处于正常,1设置时间,2设置闹钟
unsigned char Current_Time[]={"Current Time "}; //正常运行模式
unsigned char Set_time[]={"Set New Time..."}; //设置时间模式
unsigned char Set_nao[]={"Set nao Time..."}; //设置闹钟模式
unsigned char show_time[]={">00:00:00"};
unsigned char now_shi=12,now_fen=30,now_miao;//运行时的时间变量
unsigned char temp_shi,temp_fen,temp_miao;//调时间的时间变量
unsigned char nao_shi=13,nao_fen=30,nao_miao;//闹钟的时间变量
unsigned char flag_sf; //0表示设置时,1表示设置分
//歌曲音调编码
uchar code SONG_TONE[]={212,212,190,212,159,169,212,212,190,212,142,159,212,212,106,126,159,169,190,119,119,126,159,142,159,0};
//歌曲长音节
uchar code SONG_LONG[]={9,3,12,12,12,24,9,3,12,12,12,24,9,3,12,12,12,12,12,9,3,12,12,12,24,0};
void display_mode();
void display_time(unsigned char shi,unsigned char fen,unsigned char miao);
void keyscan();
void PlayMusic();
void lcd_w_cmd(unsigned char com);
void lcd_w_dat(unsigned char dat);
void lcd_int ();
void delay1(unsigned int i);
unsigned char lcd_r_start();
void been(unsigned int time);
void main()
{
lcd_int (); //初始化lcd
mode_flag=0;//运行
display_mode(); //调用显示模式函数
TMOD=0x01; //初始化定时器
EA=1; //打开总中断
TH0=(65536-50000)/256; //赋初值
TL0=(65536-50000)%256;
ET0=1; //打开定时器T0中断标志位
TR0=1; //启动T0
while(1){
if(mode_flag==0)display_time(now_shi,now_fen,now_miao); //状态标志位mode_flag=0表示正处于时间正常运行
else display_time(temp_shi,temp_fen,temp_miao); //否则mode_flag为1时设置时间,为2时设置闹钟
keyscan(); //调用按键开关控制函数
if(now_shi==nao_shi&&now_fen==nao_fen&&now_miao==nao_miao) PlayMusic(); //如果正在运行的时间为闹钟的时间,则闹铃响(此为音乐)
}
}
void display_mode()//第一行模式的显示,有三种模式:(1)正在运行的显示Current_Time[]字符串(2)设置时间的显示Set_time[]字符串 (3)设置闹钟的显示Set_nao[]字符串
{
unsigned char i;
lcd_w_cmd(0x82); //设置显示地址(第一行)
if(mode_flag==0) //状态标志位mode_flag=0表示正处于时间正常运行
{
for(i=0;Current_Time[i]!='\0';i++) //此处显示Current_Time[]字符串,字符串结束符为‘0’
{
lcd_w_dat(Current_Time[i]);
}
}
else if(mode_flag==1)
{
for(i=0;Set_time[i]!='\0';i++) //此处显示Set_time[]字符串,字符串结束符为‘0’
{
lcd_w_dat(Set_time[i]);
}
}
else if(mode_flag==2)
{
for(i=0;Set_nao[i]!='\0';i++) //此处显示Set_nao[]字符串,字符串结束符为‘0’
{
lcd_w_dat(Set_nao[i]);
}
}
}
void display_time(unsigned char shi,unsigned char fen,unsigned char miao)//第二行的数字显示
{
unsigned char i;
if(mode_flag==0)show_time[0]=' '; //如果mode_flag=0,第二行第0位显示' '
else show_time[0]='>'; //否则第二行第0位显示'>'
show_time[1]=shi/10+0x30; //第一位显示时的十位数
show_time[2]=shi%10+0x30; //第二位显示时的个位数
show_time[4]=fen/10+'0'; //第四位显示分的十位数
show_time[5]=fen%10+'0'; //第五位显示分的个位数
show_time[7]=miao/10+'0'; //第七位显示秒的十位数
show_time[8]=miao%10+'0'; //第八位显示秒的个位数
lcd_w_cmd(0xC3); //更改显示位置用
for(i=0;show_time[i]!='\0';i++) //此处显示show_time[]字符串,字符串结束符为‘0’
{
lcd_w_dat(show_time[i]);
}
}
void keyscan() //按键控制,k1调时或分,k2加时或分,k3减时或分,k4确定调好的时间,k5调闹钟
{
if(K1==0)
{
delay1(1000);
if(K1==0)
{
if(mode_flag==0) //正在运行的时间要进入调时间的状态
{
been(300);
temp_shi=now_shi;
temp_fen=now_fen;
temp_miao=now_miao;
mode_flag=1;
}
else{
been(300);
flag_sf=~flag_sf; //切换状态,flag_sf=0调时钟 flag_sf=1调分钟
}
display_mode();
while(!K1); //松手检测
}
}
if(K2==0) //加时或分
{
delay1(1000);
if(K2==0)
{
if(mode_flag!=0)
{
been(300);
if(flag_sf==0) //调时钟状态
{
temp_shi++;
if(temp_shi==24)temp_shi=0; //如果加时钟到24就清零
}
else { //调分钟状态
temp_fen++;
if(temp_fen==60)temp_fen=0; //如果加分钟到60就清零
}
}
while(!K2); //松手检测
}
}
if(K3==0) //减时或分
{
delay1(1000);
if(K3==0)
{
if(mode_flag!=0)
{
been(300);
if(flag_sf==0) //调时钟状态
{
if(temp_shi==0)temp_shi=24; //如果减时钟减到最低到0就又回到最高位24
temp_shi--;
}
else { //调分钟状态
if(temp_fen==0)temp_fen=60; //如果减分钟减到最低到0就又回到最高位60
temp_fen--;
}
}
while(!K3); //松手检测
}
}
//确定设置的时间和调好闹钟的时间
if(K4==0)
{
delay1(1000);
if(K4==0)
{
if(mode_flag==1) //设置时间 设置好的时间确定后正常运行
{
been(300);
now_shi=temp_shi;
now_fen=temp_fen;
now_miao=temp_miao;
mode_flag=0;
}
if(mode_flag==2) //设置闹钟 设置好的时间确定好之后定为闹钟
{
been(300);
nao_shi=temp_shi;
nao_fen=temp_fen;
nao_miao=temp_miao;
mode_flag=0;
}
while(!K4); //松手检测
}
display_mode(); //调用显示模式函数
}
if(K5==0) //设置闹钟
{
delay1(1000);
if(K5==0)
{
if(mode_flag==0)
{
been(300);
mode_flag=2;
temp_shi=nao_shi;
temp_fen=nao_fen;
temp_miao=nao_miao;
}
display_mode();
while(!K5); //松手检测
}
}
}
void been(unsigned int time)
{
unsigned int i;
for(i=0;i<time;i++)
{
BEEP=~BEEP;
delay1(10);
}
}
void delay(uint ms) //闹铃的延时函数
{
char t;
while(ms--) for(t=0;t<120;t++);
}
void PlayMusic()
{
uint i=0,j,k;
while (SONG_LONG[i]!=0||SONG_TONE[i]!=0)
{
for(j=0;j<SONG_LONG[i]*30;j++)
{
BEEP=~BEEP;
for(k=0;k<SONG_TONE[i]/4;k++);
}
delay(10);
i++;
display_time(now_shi,now_fen,now_miao);
}
}
//函数名:time0
//函数功能:定时器T0的中断函数,T0在工作方式1下每50ms产生中断,执行该中断函数
void time0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
cishu++;
if(cishu==20) //一秒时间到后,次数清零,秒数加一
{
cishu=0;
now_miao++;
}
if(now_miao==60) //60秒时间到后,秒数清零,分钟加一
{
now_miao=0;
now_fen++;
}
if(now_fen==60) //60分钟时间到后,分钟清零,时钟加一
{
now_fen=0;
now_shi++;
}
if(now_shi==24) //24小时到后,时钟清零
{
now_shi=0;
}
}
//函数名:lcd_int
//函数功能:lcd初始化
void lcd_int()
{
lcd_w_cmd(0x3c); //设置工作方式
lcd_w_cmd(0x0c); //设置显示状态
lcd_w_cmd(0x01); //清屏
lcd_w_cmd(0x06); //设置输入方式
lcd_w_cmd(0x80); //设置初始显示位置
}
//函数名:lcd_w_cmd
//函数功能:写命令
//形式参数:命令字已经存入com单元中
void lcd_w_cmd(unsigned char com)
{
unsigned char i;
do
{ //查lcd忙状态
i=lcd_r_start(); //调用读状态字函数
i&=0x80; //“与”操作屏蔽掉低7位
delay1(2);
}while(i!=0); //lcd忙,继续查询,否则退出循环
RW=0;
delay1(1);
RS=0; //RW=0,RS=0,写lcd命令字
delay1(1);
E=1; //E端时序以0或1高低波动
delay1(1);
P0=com; //将com中的命令字写入lcd数据口
delay1(1);
E=0;
delay1(1);
RW=1;
delay1(2);
}
void lcd_w_dat(unsigned char dat)
{
unsigned char i;
do
{ //查忙操作
i=lcd_r_start(); //调用读状态字函数
i&=0x80; //“与”操作屏蔽掉低7位
delay1(2);
}while(i!=0); //lcd忙,继续查询,否则退出循环
RW=0;
delay1(1);
RS=1; //RW=0,RS=1,写lcd命令字
delay1(1);
E=1; //E端时序以0或1高低波动
delay1(1);
P0=dat; //将dat中的显示数据写入lcd数据口
delay1(1);
E=0;
delay1(1);
RW=1;
delay1(2);
}
void delay1(unsigned int i)
{
unsigned int k;
for(k=0;k<i;k++);
}
//函数名:lcd_r_start
//函数功能:读状态字
unsigned char lcd_r_start()
{
unsigned char s;
RW=1; //RW=1,RS=0,读lcd状态
delay1(1);
RS=0;
delay1(1);
E=1; //E端时序以0或1高低波动
delay1(1);
s=P0; //从lcd的数据口读状态
delay1(1);
E=0;
delay1(1);
RW=0;
delay1(1);
return(s); //返回值s读取状态忙或空闲
}
5.测试与运行
5.1 电子钟显示测试
完成了电路设计以及程序设计后,把程序做成工程后,把生成的HEX文件放入到AT89C51控制器后便可开始测试,开始测试后电子钟的显示如图5-1所示:
图5-1 电子钟显示测试
5.2 时间调节测试
完成上述电子钟的显示测试后,便要开始进行电子钟的时间调节测试,电子钟是否能够正常的进行调节,是本次课程设计的重中之重,只有能够进行时间调节的电子钟,才可以真正的运用在生产电子钟的上面,电子钟的时间调节测试,如图5-2与5-3所示:
图5-2 电子钟时间调节测试
图5-3 电子钟时间调节测试
5.3 设定闹钟测试
完成上述测试后,可以直观的感受到,该电子钟是可以正常的进行调节,即可加时间也可以减时间,接下来就要进行闹钟的设定,测试结果如图5-4所示:
图5-4 电子钟设定闹钟测试
完成了上述的所有测试,即可证明该1602数字电子钟是可以正常的进行运作的,既可以调节时间,也可以定闹钟,蜂鸣器也可以正常的进行工作,虽然功能非常有限,但是基本上完成了设计的要求。
- 总结
通过这次的课程设计作品的制作让我对单片机的理论有了更加深入的了解,本次我所设计的电子数字钟,在日常生活中算是一个非常常见的一个物品,但是,真正的在设计中,我发现遇到了很多的麻烦,电路的设计,程序的设计。都有很多困难,不仅仅是运用了课堂上所讲的单片机的知识,就连大一与大二所学习的c语言的知识和电路的知识也都运用到了里面,同时在具体的制作过程中我们发现现在书本上的知识与实际的应用存在着不小的差距,书本上的知识很多都是理想化后的结论,忽略了很多实际的因素,或者涉及的不全面,可在实际的应用时这些是不能被忽略的,我们不得不考虑这方的问题,这让我们无法根据书上的理论就轻易得到预想中的结果,有时结果甚至很差别很大。通过这次实践使我更深刻的体会到了理论联系实际的重要性。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,更加加深了我对单片机理论知识的认知,对c语言的使用以及对电路的理解。更加明白了只有理论知识是远远不够的,只有把所学的理论知识与实践相合起来,从理论中得出结论,才能真正为社会服务,从而提升自己的实际动手水平和独立思考的水平。在设计的过程中遇到问题,能够说得是困难重重,但可喜的是最终都得到了解决。