,使得_clcok不能及时更新时间,并且_convert不能转换代码,那么显示结果仍然没有变化。当loop循环执行一次完毕之后,_clock和_convert才开始更新.
但是这里可能会有个疑问:既然如此,计算_disp2的执行时间大概为500ms,当_disp2子程序执行完毕之后,那么也开始循环执行_clock和
_convert,然后LCM再显示,此刻应该显示的是更新的时间了吧,总时间也大概为1s多一点,为何执行结果大概等到1分钟左右,秒区数字才加1呢?
问题提得很好。
思考原因可能为 :由于_clock不能及时更新时间,及不能及时取走(us+1:us)中大于50ms时的50ms量,但中断服务代码中始终严格执行下面两
条指令:
movlw 0x10 ; 256x16分频=4096=0x1000的高位(0x10)
addwf us+1 ; 微秒的高位字节加上定时时间
多次累加后(15次累加令us+1单元的内容为从00H到F0H)令us+1单元溢出,丢失定时的时间增量,若当_clock更新时,(us+1:us)发生溢出使得其
值小于50ms(代数值50000),因此也不能使得变量ms50的值增加,那么秒钟变量sec也不会变化,转换后时间显示仍然保持不变.
注意: 当_clock更新时间时,(us+1:us)若满足大于50 000的条件,则ms50变量加一,在main主程序中_clock循环更新时,若捕捉到20次
(us+1:us)单元大于50000(50ms)时,sec的值才能加1。而这个在多次更新过程中捕捉该条件的周期,就是秒区显示加1的周期,我认为这个周
期是固定的,也许是30秒,也许是1分钟,也许更长,只要程序长度和结构没有发生变化。后来在程序中,我增加延时子程序的时间,结果秒区数字加1的间隔时间也跟着延长了。
到了这里,知道了问题所在,那么在基于原程序的框架下,我对几种解决方案都尝试了一下:
方案1:
[既然症结是在_clock不能真实捕捉到每一次中断时间累加增量(us+1:us)值大于50ms(50000)的条件,那么,将_clock内嵌中断中去,中
断每一次改变us+1的值然后马上进行时间更新,这样,使得_clock能真实捕捉每一次(us+1:us)值大于50ms(50000)的条件,也能真实更新系统时
间。]
方案1分析:这样确实可以保证每一次都可以捕捉us时间增量,不考虑运行的结果问题,该方案有几个缺点:
1) 中断服务代码由于调用了_clock子程序,显得异常臃肿;
2) 每次中断(4096us)都调用_clock,判断其是否到50ms(值为50000),增加了程序的开销,效率较低;
3) 由于LCM慢显示特性的原因,可能使得结果仍然不能令人满意:
关于3) 我描述一下一下:虽然此刻,秒区的数字能基本上每秒钟跳变一次了,但是调试过程中出现了一个问题: 秒区数字跳变有时会忽略下
一个值,而跳到下下一个值去,比如,当前显示12,然后马上显示14。
那么问题出在什么地方呢? 试想,若_convert在进行格式转换时,发生中断,且更改了sec变量,那么,_convert会按新的值进行转换,这
样,本来这次要转换并送显示的旧值被新值给覆盖了,所以,_disp2在显示的时候,也就根据_convert的转换结果,忠实地显示了一个新值,将
本来应该显示的值给忽略了。
既然如此,有什么办法来解决呢?两个方法:
(a) _convert在对时间变量进行格式转换时,暂时禁止TMR0中断,转换后再开启TMR0中断;
(b) 将_conver也归并到中断代码中去,规定次序,使得_clock更新时间后,_convert再进行转换,这样,格式转换区的变量不用担心被
_clock修改;
**那么方法(a)会存在什么问题呢?试想:当_convert在转换时,TMR0定时时间到,TMR0向内核提交中断,但由于TMR0中断请求被禁止,即使
_convert转换完毕之后,允许TMR0中断,那么TMR0的中断请求会不会被丢弃呢? 显然,根据PIC的中断系统,当TMR0定时时间到后,首先将
T0IF置1,并由T0IF向内核提出中断请求,如果该中断请求被禁止,那么只要其中断标志T0IF仍然保持为1,当该中断响应解禁之后,内核根据
T0IF立即响应其中断。
因此,方法(a)中"TMR0的中断请求可能会被遗弃的担心"是多余的.
并且,由于_convert的执行时间少于一个中断周期,所以它对中断的暂禁操作不会出现在一个暂禁中断的过程中,中断标志T0IF的多次被置一
的现象,所以不会发生中断响应被冲掉的不良后果。同样,_clock子程序在没有加载到中断服务代码中去时,其对TMR0的暂禁影响与_convert分
析的结果相同.
那么,既然如此,我认为这样的话,由于_disp2的执行时间也不会超过1秒,因此,不会出现当秒跳变时,_convert来不及转换而丢弃上一次待
转换的字符。所以,结果应该是正常.
于是按照这种方法修改程序,结果发现秒区每次都跳变,最小增量为2,最多为为3(跳变周期大约1.2秒)。于是将延迟子程序的外循环值由
64H-〉40H(大概右25ms变成16ms),结果仍然如此,秒区每次都跳变,只是跳变节奏比未修改延时子程序前变快很多(跳变周期大约0.6s),但最
小跳变增量1,最多为2。
[正在分析其根源,也请有兴趣的兄弟一起思考一下.....]
那么那试试方法(b).我按方法(b)修改了程序,结果发现,仍然出现秒区数字跳变的情况。
究其原因,跟3)类似:当_disp2运行的时候,准备从显示缓冲区取字符来显示,如果发生中断,_clock,_convert更改了显示缓冲区的内容
,使得本来即将待显示的内容被替换成下一次显示的内容。所以,该方法依然存在,而且,由于_disp执行时间大于一次中断的255us,如果在
_disp执行过程暂禁TMR0中断将会丢弃中断请求(即:TMR0的中断请求被自己下一次中断请求覆盖,上一次中断请求被忽略,显示时间将变慢)。
----------------------------------------------------------------
方案2:
[中断服务仍然只改变us+1的值,但是格式转换及显示功能内嵌到_clock子程序中去,主程序执行_clock循环。]
下午我按这种方式更改了程序,在软件模拟时发现程序跑飞。原因是:内嵌了这些功能之后,代码由400行变成500多行,在_disp1查表显示
字符时,_table已经超过PCL的256字ROM空间,而查表时未注意PCLATH内容,以致跑飞。解决此问题后,下载到ICD中运行,发现结果倒是正常
了,但是感觉时间好像有一点点慢。
呵呵,细心的站友想必已经看出来了,由于加了显示功能的_clock子程序中依然是暂时禁止TMR0中断的,虽然该时间显示功能只是在时间跳
变时刷新LCD屏幕,但是正是由于在时间跳变时执行时间刷新的周期过长(大于4096us),TMR0 的多次中断请求最后只被响应一次,即T0IF多次
被置1后,却只能在_clock子程序末对TMR0解禁时得到一次中断响应,未被响应的累积时间被丢弃了,没有加到(us+1:us)中去,引起时钟显示变
慢了.
方案3:
由于前两个方案均存在不近人意的问题,难道在用TMR0做秒表时,且当"定时中断的周期小于LCD慢显器件的驱动刷新周期的情况下",就没有一个
完美的解决方案么?
留在这里和有兴趣的站友一起思考...
上一页 [1] [2]
本文关键字:单片机 PIC单片机,单片机-工控设备 - PIC单片机