单片机课程设--电子钟设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单片机MCS-51数钟
课程设计
系别:
专业:
班级:
姓名及学号:
日期:
目录
单片机MCS-51数钟 (1)
课程设计 (1)
一、课程设计的目的 (3)
二、课程设计任务 (3)
三、硬件结构概述 (4)
(一)复位电路 (4)
(二)晶振电路 (4)
(三)按键电路 (4)
(四)显示部分 (5)
四、软件结构概述 (5)
(一)代码说明 (5)
(二)按键处理思路 (10)
(三)秒表设计思路 (11)
五、调试过程 (12)
(一)系统仿真 (12)
(二)仿真过程中出现的问题及解决方案 (12)
六、心得体会 (13)
七、参考文献 (14)
一、课程设计的目的
(1)巩固、加深和扩大单片机应用的知识面, 提高综合及灵活运用所学知识解决工业控制的能力;
二、(2)培养针对课题需要, 选择和查阅有关手册、图表及文献资料的自学
能力, 提高组成系统、编程、调试的动手能力;
三、(3)过对课题设计方案的分析、选择、比较、熟悉单片机用系统开发、
研制的过程, 软硬件设计的方法、内容及步骤。
四、课程设计任务
(1)在ZY15MCU12BD型综合单片机实验箱的硬件结构上编写软件完成设计。
也可以在其它MCS—51单片机硬件板上完成, 或自行设计硬件并制做完成。
(2)程序的首地址应使目标机可以直接运行, 即从0000H开始。
在主程序的开始部分必须设置一个合适的栈底。
程序放置的地址须连续且靠前, 不要在中间留下大量的空闲地址, 以使目标机可以使用较少的硬件资源。
(3)6位LED数码管从左到右分别显示时、分、秒(各占用2位), 采用24小时标准计时制。
开始计时时为000000, 到235959后又变成000000。
(4)在键盘上选定3个键分别作为小时、分、秒的调校键。
每按一次键, 对应的显示值便加1。
分、秒加到59后再按键即变为00;小时加到23后再按键即变为00。
在调校时均不向上一单位进位 (例如分加到59后变为00, 但小时不发生改变)。
(5) 软件设计必须使用MCS-51片内定时器, 采用定时中断结构, 不得使用软件延时法。
(6)在以上设计的基础上, 修改程序制作一个电子秒表。
分、秒各占用2位显示, 1/10秒、1/100秒各占用1位显示。
设定二个键分别作启动停止、清零。
(7)在做完(6)后, 将时钟与秒表合二为一, 并且在同时使用时互不影响。
即可在时钟与秒表之间任意切换, 而不影响走时、计秒。
(8)简化按键, 用3个按键完成以上功能。
(9)上机调试通过。
五、硬件结构概述
(一)复位电路
单片机复位的条件是: 必须使RST/VPD 或RST引(9)加上持续两个机器周期(即24个振荡周期)的高电平。
例如, 若时钟频率为12 MHz, 每机器周期为1μs, 则只需2μs以上时间的高电平, 在RST引脚出现高电平后的第二个机器周期执行复位。
单片机常见的复位如图所示。
电路为上电复位电路, 它是利用电容充电来实现的。
在接电瞬间, RESET端的电位与VCC相同, 随着充电电流的减少, RESET的电位逐渐下降。
只要保证RESET为高电平的时间大于两个机器周期, 便能正常复位。
该电路除具有上电复位功能外, 若要复位, 只需按图中的RESET键, 此时电源VCC经电阻R1.R2分压, 在RESET端产生一个复位高
电平
图1单片机复位电路
(二)晶振电路
下图所示为时钟电路原理图, 在AT89S51芯片内部有一个高增益反相放大器, 其输入端为芯片引脚XTAL1, 输出端为引脚XTAL2。
而在芯片内部, XTAL1和XTAL2之间跨接晶体振荡器和微调电容, 从而构成一个稳定的自激振荡器。
时钟电路产生的振荡脉冲经过触发器进行二分频之后, 才成为单片机的时
钟脉冲信号。
图2晶振电路
(三)按键电路
图3 按键电路
如图3所示, 为按键部分。
其中, K1为功能选择键, K2为确定键, K3为复位键, 其原理为: 检测P1.0-P1.1上点位, 当有键按下时为高电平, 当没有键按下时为低电平。
图4 显示电路
(四)显示部分
六、如图4所示, 为显示电路部分, P0口输出段码, P2口输出位码。
采用六位共阳极七段数码管显示, 用NPN型三极管驱动位,
P0口接上拉电阻, 驱动段。
七、软件结构概述
(一)代码说明
/******************Copyright (asm)********************* 文件名: 单片机课程设计(汪劲08118012 舒坦08118037)
功能: 基于MCS-51单片机的时钟及秒表设计
说明:采用6位LED软件译码动态显示;P0口输出字段码, P2口输出位码;按键 key1为功能选择键;按键 key2为确定键;按键
key3为复位键
**********************************************************/
变量和标志位的定义
#include"reg51.h"
unsigned int i=1;
unsigned int code x[]={0x01,0x02,0x04,0x08,0x10,0x20}; unsigned int code table[]={0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned int sfm[6],s=0,f=0,m=0,keyS,flag=0,ss=0;
bit flagbit=0,run=0,bitc=0;
sbit key1=P1^0;
sbit key2=P1^1;
sbit key3=P1^2;
char lm, mm=0,ms=0,mf=0;
1ms软件延时子函数
void delay(unsigned int t) //1ms软件延时子函数
{
unsigned int ii,jj;
for(ii=t;ii>0;ii--)
for(jj=0;jj<120;jj++);
}
定时器T0中断
void init() interrupt 1 //定时器T0中断
{
TH0=0x0d8; //重装初值
TL0=0x9b;
i++; //10ms计数器加1
if(i>=100) //如果时间到 1S, 秒加 1, 10ms计数器复位i=1,m++;
if(m>=60 ) //如果时间到 1min, 分加 1, 秒计数器复位{
m=0;
f++;
}
if(f>=60) f=0,s++;//若时间到 1小时,小时加 1,分计数器复位if(s>=24) s=0; //如果时间到 1天, 小时计数器复位
if(run) //启动秒表
{
if(i<lm) // 1/10秒和1/100秒计数器计数
mm=100+i-lm;
else
mm=i-lm;
if(mm>=99) //如果计数到 1秒, 则秒加 1, 1/10秒
和1/100秒计数器复位
mm=0,ms++;
if(ms>=60) ms=0,mf++;//如果计数到 1分, 则分加 1,
秒计数器复位
}
}
更新数据缓冲子函数
void deal(void) //更新数据缓冲子函数
{
sfm[0]=s/10;
sfm[1]=s%10;
sfm[2]=f/10;
sfm[3]=f%10;
sfm[4]=m/10;
sfm[5]=m%10;
}
按键处理子函数
void key() //按键处理子函数
{
delay(20); //消抖
if(P1!=0 && !flagbit) //确认按键是否按下
{
flagbit=1; // flagbit为长按标志, 若按
键未松开, 则为置为 1 if(key1==1 && !flag) // 按下功能选择键 key1
keyS++; // 功能编号加 1
if(key1==1 && flag==1)//若功能编号为 1进入时钟加 1调整{
if(ss==0)
m++;
if(ss==2)
f++;
if(ss==4) s++;
}
if(key1==1 && flag==2)//若功能编号为 2, 进入时钟减 1调整{
if(ss==0)
if(m>0) m--;
else m=59;
if(ss==2)
if(f>0) f--;
else f=59;
if(ss==4)
if(s>0) s--;
else s=23;
}
if(key2==1 && !flag)//按下确定键key2, 进入相应功能flag=keyS,keyS=0;
if(key2 && (flag==1 || flag==2))//按下key2, 进行时
钟调整移位(依次选择分、时、秒)
if(ss!=4) ss+=2;
else ss=0;
if(flag==3) //如果功能编号为 3, 则进入秒表
{
if(key1==1 && !run)//按下key1, 清空秒表并启动秒表 {run=1,mm=0,ms=0,mf=0,lm=i;}
if(key2==1) //按下key2,秒表暂停run=0;
}
if(key3==1) //按下 key3,停止秒表或时钟调整回到时钟
{
flag=0;
keyS=0;
ss=0;
mm=0,ms=0,mf=0;
}
}
}
显示时钟子函数
void disp1() //显示时钟子函数
{
char l;
for(l=0;l<6;l++) //动态显示
{
P2=x[l];
P0=table[sfm[l]];
delay(3);
P0=0xff;
}
}
功能编号的显示子函数
void disp2() //功能编号的显示子函数{
char l;
for(l=0;l<6;l++)
{
P2=x[5];
P0=table[keyS];
delay(3);
P0=0xff;
}
}
当时钟调整时, 对应的位闪烁子程序
void disp3() //当时钟调整时, 对应的位闪烁{
char l;
for(l=0;l<6;l++)
{
P2=x[l];
if(l==ss && (i<25 || (i<75 && i>50))) //闪烁条件continue;
P0=table[sfm[l]];
delay(3);
P0=0xff;
}
}
秒表子函数
void disp4() //秒表子函数
{
char l;
while(flag==3) //当功能编号为3时, 进入秒表功能{
sfm[0]=mf/10;
sfm[1]=mf%10;
sfm[2]=ms/10;
sfm[3]=ms%10;
sfm[4]=mm/10;
sfm[5]=mm%10;
for(l=0;l<6;l++)
{
P2=x[l];
P0=table[sfm[l]];
delay(3);
P0=0xff;
}
if(P1!=0x00 && !flagbit) //当有按键按下时,
key(); 进按键处理子函数if(P1==0x00 && flagbit) //防止按键长按
flagbit=0;
}
}
主函数
void main()
{
delay(1); //延时1ms
P1=0x00;
TMOD=0x01; //选择中断T0, 工作在方式1 TH0=0x0d8; //定时器赋初值, 定时10ms TL0=0x0f0;
ET0=1;EA=1; // 开T0中断允许
TR0=1; //启动定时
while(1)
{
deal();
if(P1!=0x00 && !flagbit) //当有按键按下时,
key(); 进按键处理子函数if(P1==0x00 && flagbit) //防止按键长按
flagbit=0;
if(keyS) //判断并进入相应功能
disp2();
else
disp1();
if(flag==1)
disp3();
if(flag==3)
disp4();
}
}
(二)按键处理思路
为了简化硬件电路, 体现软件的灵活性, 本设计只用了3个按键来完成时钟调整(包括时分秒的加减), 秒表暂停, 整体复位等一系列功能。
其具体功能如下: 当没有键按下时, 时钟正常显示;当key1键按下时, 会显示1-3的功能编号, 其中1号功能为加1,2号功能为减1,3号功能为秒表;key2键为确定键, 用来选择并进入各功能模块, 当进入1和2的调时模块后, 还用来选择调整时分秒中的某两位;key3为复位键, 在任何时候按下key3, 都会回到显示时钟状态。
如图5为按键部分的流程图
图5 按键处理流程图
(三)秒表设计思路
当选择功能3时, 启动秒表, 此时1/10秒和1/100秒计数器的计数处理是关键。
1/10秒和1/100秒计数器计数假设此时的10ms计数器i 的值为lm, 则将此时的i 值lm 当做秒表的零值, 以此作为标志来丈量秒表的计数, 我们的处理程序如下:
if(i<lm) // 1/10秒和1/100秒计数器计数 mm=100+i-lm;
else
mm=i-lm;
比如: 若此时的i =68, 则将68赋值给lm , 当i 从68变到100时, mm将从
0变到32;当i 从0变到67时, mm将从33变到100, 到此计满1S。
图6 秒表流程图
八、调试过程
(一)系统仿真
首先建立一个工程项目选择芯片确定选项, 然后建立c源文件(将做好的*.c 文件加入), 再用项目管理器生成(编译)各种应用文件, 最后检查并修改源文件中的错误。
运行proteus软件进行仿真现在proteus软件中建立一个新的文件, 再根据自己的要求选择所需的器件, 把器件进行适当的排位后进行连接, 连接后运行软件进行
仿真。
效果如图:
图6 调试效果
(二)仿真过程中出现的问题及解决方案
1)子函数disp3( )原本想要的效果是, 当对时钟的某位(时、分、秒)进行调整时, 对应的两位数码管会闪烁, 但在调试过程中, 我们发现当设置同样的闪烁间隔时间时, 不同电脑会有不同的效果。
比如, 在这台电脑上闪烁, 而在另一台上调试时却不闪烁。
九、2)开始调试时, 经常会发现按键没有按照预定的功能进行工作, 或者出现乱码, 经过多次尝试, 我们发现这都是我们在原来按键的基础上添加功能时, 更改或影响了其他的计数器或状态值, 根据这个原因, 我们逐个排除了许多错误, 最终所有的功能都达到了满意的效果。
十、3)调试过程中, 我们发现了一个奇怪的现象, 到现在还不能解释清楚:在对计数器重装初值时, 本来是要对初值进行加3-8个周期的修正以减小误差计数误差, 但实际上我们发现适当减小计数初值, 系统的误差会更小。
经过多次的调时我们将时钟的误差保持在0.002s/25s, 算是比较理
想的了。
十一、心得体会
单片机作为我们主要的专业课程之一, 我觉得单片机课程设计很有必要, 而且很有意义。
但当拿到题目时, 确实不知道怎么着手, 有些迷茫, 上网查资料, 问老师, 在老师的帮助下, 历时两个星期, 解决一个又一个的困难, 终于完成任务。
十二、在这次课程设计中, 运用到了很多以前的专业知识, 虽然过去从未独立应用过它们, 但在学习的过程中带着问题去学我发现效率很高, 这是我做这次课程设计的一大收获。
另外, 要做好一个课程设计, 就必须做到: 在设计程序之前, 对所用单片机的内部结构有一个系统的了解, 知道该单片机内有哪些资源;要有一个清晰的思路和一个完整的的软件流程图;在设计程序时, 不能妄想一次就将整个程序设计好, 反复修改、不断改进是程序设计的必经之路;要养成注释程序的好习惯, 一个程序的完美与否不仅仅是实现功能, 而应该让人一看就能明白你的思路, 这样也为资料的保存和交流提供了方便;在设计课程过程中遇到问题是很正常德, 但我们应该将每次遇到的问题记录下来, 并分析清楚, 以免下次再碰到同样的问题的课程设计结束了, 但是从中学到的知识会让我受益终身。
发现、提出、分析、解决问题和实践能力的提高都会受益于我在以后的学习、工作和生活中。
设计过程, 好比是我们人类成长的历程, 常有一些不如意, 但毕竟这是第一次做, 难免会遇到各种各样的问题。
在设计的过程中发现了自己的不足之处, 对以前所学过的知识理解得不够深刻, 掌握得不够牢固, 不能灵活运用。
十三、通过这次设计, 我懂得了学习的重要性, 了解到理论知识与实践相结合的重要意义, 学会了坚持、耐心和努力, 这将为自己今后的学习和工作做出了最好的榜样。
另外, 要非常感谢我的指导老师, 是她指引我克服一个由一个的困难, 让我学会对困难无所畏惧, 以及对问题的一些很重要的
思考方法。
十四、我学会对困难无所畏惧, 以及对问题的一些很重
要的思考方法。
十五、参考文献
(1)胡汉.单片机原理及其接口技术(第二版). 北京: 清华大学出版社, 2004.2
(2)杨家国等单片机原理与应用及C51程序设计北京:清华大学出版社, 2006.8。