关于郭天祥老师10天学会51单片机第三讲最后一个定时器出现问题的解释
在学习到郭天祥老师的第三讲《计数器/定时器》时,老师在课程最后的代码出现了一些小问题:由于老师忘记把delay函数给注释掉,而导致了在老师将计时器设置为tt=4(记时200ms)时跳不出while循环,而在tt=20(计时1s,LED正常跳转(时间并没有因为delay函数而增加,具体后面有解释))程序能够正常运行的问题。
tt=4,计时200ms,此时LED管显示跳转到1就卡住不动了
tt=20,计时1s,此时LED管正常跳转
(忽略掉我dl的设置,我只是想观察delay函数是否正常运行(delay函数正常运行的话发光二极管会保持1s的亮起状态再熄灭))
老师在最后解释道是因为没有把delay函数注释掉的原因,但是我却产生了一些疑惑,如果是没有把delay函数注释掉的原因的话,tt=20的情况下应该是计时时间增长(由本来的1s变为1s+delay的时间),tt=4的时候函数应该也可以正常运行且时间应该比tt=20的时候短一些,为什么LED显示器会卡在num=1的地方呢?
结论:
之所以LED显示器会卡在了num=1 的地方,是因为函数进入第一次if循环时,即num++,tt置0后,在delay语句执行的同时,计数器也在进行计数,所以tt在跳出if循环的时候已经溢出4(此时tt为17),进入while第二次循环的时候tt继续增加,if语句(tt==4)永远无法满足,不能执行。
解释:
我是怎么得到这个结论的呢?我进入了DEBUG功能,对tt的值进行了观察:
进入delay函数之前tt的值是0
我设置了三个断点,第一个用来观察进入if循环后tt的值是否正常(正常的),第二个断点观察进入delay循环之前的tt值是否正常(确实被成功置0),第三个断点用来观察出delay循环后的tt值。
跳出delay循环之后tt的值变为了17
程序卡在了第二次while循环,且tt的值一直增长
果不其然我们可以看到在出delay循环之后的tt值变为了17,此时跳出if循环进入第二次while循环的tt初始值已经是17,当然会卡在if循环外面一直计数增加永远也不可能达到4啦。而我们第一次设置的条件是tt==20,17比20小所以继续计数可以满足if条件语句,程序可以正常运行,且程序延迟的时间是由delay函数的时间即tt=17加上进入第二次while循环后在tt=17的基础上继续计数(此时只需要将tt从17累加到20),所以计时的时间并没有增长,依然是1s。
但是tt的值为什么会是17呢?
我们可以从上面两张图左边的sec看到delay函数比较精确的时间应该是1.1742-0.2175=0.9567s左右。
而执行一次振荡周期*50000大概是0.0547s。(见下两张图)
所以在delay函数执行期间,计数器计数0.9567/0.0537 = 17.4差不多是17的样子。
所以在跳出delay循环之后,tt变为了17。
解决方案
由以上的分析总结可知,产生这种情况,是因为在我们执行delay函数时,中断函数并没有被delay打断,而是按照他原来自己的时钟执行,所以只要delay函数的时间小于中断这个程序就不会有错,但是一旦delay超出了中断的时间,就会出现计时器超出判断标准而无法进入下一次中断程序进而出错。
所以我建议
1.不要随意在中断程序中添加delay函数
计时函数本来就相当于一个延时器了,如果没有特殊需求(比如我在上图代码中添加了发光二极管的闪烁,如果没有delay函数二极管亮起的时间会非常短,肉眼几乎看不到),没有必要添加delay函数在中断程序中。
2.delay函数的时间不得长于计时器设定时间,且计数器置0一定要在delay函数之前。
第一句话很好理解,上文已经解释过,如果长于计时器设定时间会由于永远无法满足if条件卡在while第二次循环开始。
第二句话怎么解释呢?
如果我们将tt =0放在delay函数之后,就会出现我们一开始猜测的情况,计时器正常运行,但是执行的时间是delay函数+计时器设定的时间。
下面跟问题无关看到这里可以关掉了
臭屁碎碎念:
烦了我一晚上的问题终于解决啦,果不其然我从小时候养成的刨根问底的习惯长这么大了还是没有改掉,折腾了一晚上好歹是有了一个答案,所以想着记录一下!也算是自己给自己打气↖(ω)↗加油啦!谁说女孩子学不好硬件学不好嵌入式开发的,本理工脑袋非要证明我可以!哼!