代码编译后在Proteus中仿真运行,可以获得预期结果,如s上图所示。由于是一个简单的测试程序,任务单一,所以程序设计时把所有工作都放在中断服务程序中处理了,包括显示输出,经测试中断服务程序最长的一个分支执行时间在2ms左右,比定时器TO的中断时间间隔要小的多,因此不会出现中断来不及响应的情况。而在主程序中唯一的事情就是等中断,只要芯片支持,此时可以进入节能的状态运行。如果系统较复杂,中断情况较多,编程的思路则是尽量让中断服务程序简单化。在该测试程序中,考虑了按键去抖问题,由于不需要确认按键模式问题,所以没有考虑释键去抖。此外,显示输出使用了printf()函数,这用到上讲中的包括putchar()函数在内的自制的二进制库,不过引入了一个上次示例中未实现的转移字符’\b’,所完成的功能就是后退一格,请读者在putchar0中自行补充相关代码。
四、数字钟的整机程序设计
简易数字钟的主要功能有计时、校时及显示等几个。校时涉及到用户的按键输入,及时的键盘响应会带来良好的用户感受,需要较高的实时性。计时过程中,每1秒时钟步进一次,秒定时的来源还是出自单片机的定时器。请注意,此时会出现一个问题,16位的定时器在11.0592MHz振荡频率下无法到达1秒的定时,怎么解决呢?处理的办法通过软件累计定时器的溢出次数,延长定时时间,使其达到要求值。比如,我们将12.5ms的定时器时长作为一个时间片,计满80个时间片就可以获得Is的定时长度。我们可将按键的检测、定时器的计数等事件级的程序放在中断服务程序以便及时响应,一般称之为前台程序;而时钟调整、按键模式及其键值处理、显示等任务级的程序放在主程序中运行,一般称为后台程序。
主程序的流程很简单,在完成系统初始化之后,就在显示、计时、校时之间循环执行程序,其参考代码如下:
为提高显示效率,程序只在显示数据变化后才予以刷新。显示输出函数printf()中引入了’\r’转义控制字符,需要读者自行在putchar0函数中实现。LCD和定时器TO的初始化程序同前。中断服务程序作为前台程序,处理的事情更为简单,主要是时间片的计数和键盘扫描,参考代码如下:
变量tICks用于秒时间的计数,变量tickd用于延时时间的计数。键盘扫描程序KeySCAN()用于检测按键和释键两个动作。按键动作的检测方法就是在无键按下的情况下连续两次测到有键按下则为一次有效“键按下”事件;如果在键按下的情况下连续两次测到无键按下则为一次有效的“键释放”事件。KeyScan0函数的参考代码如下:
相比计时而言,时间的调整相对复杂些,主要是由于按键模式的确定要想较好地符合人的心理习惯需要考虑的情况较多一点。一次按键,先输出一个有效键,若持续按键,则以一定速度输出多个有效键。为方便理解这一过程,我们以状态转换图来描述,如下图所示。
在上图中,定义了“空闲”、“单键”、“连发”三个状态,并给出了状态转移的条件。单键状态与连发状态的区别在持续按键时间的长短,给出一个持续时间阈值tTH,小于它的则为单键状态,超过的为连发状态。在单键状态下,仅在进入该状态时输出一个有效键值;在连发状态下,则以一定速率连续输出有效键值。参考代码如下:
将上述代码整合起来后编译,并在Proteus中仿真运行,其效果截屏示意图如下图所示。程序下载至EDP实验箱上运行,同样也获得了很好的效果。
最后留出一个问题给读者朋友思考,如果需要对显示字符做一些闪烁效果,请问该如何实现。
本文关键字:暂无联系方式时钟-定时电路,单元电路 - 时钟-定时电路