目前本人已经不再写代码了,只是想把自己走过的弯路,踩过的坑分享出来,希望更多的小伙伴能看到,少走弯路,仅供参考哈!
这章重点给新手们提供一个能最大利用CPU性能的程序架构思路,具体程序就不再展示了。
前言
在学习51单片机或者用51单片机做项目时,由于51单片机的资源配置都是有限的,所以当外围需要实现的功能较多时,就必须要从程序的架构上下功夫,如果使用“单一任务”的思维去写程序,会直接影响效果甚至运行不起来。
架构思路
而在上一篇文章中,我们使用定时器的方式,避免了CPU空等待的情况,没看过的小伙伴可以戳这里:
其实思路也是比较简单的,如下图1所示:
上图中的任务体其实就是CPU在一定的时间内需要“光顾”的事件,比如想让LED在1S的时间做亮灭的动作,那CPU就不用一直“盯着”LED,可以先去做其他“事件”,等1S时间到了之后再去控制LED就行。
举个日常生活的例子:
假如水烧开需要8分钟,那在这8分钟里,我们可以不用一直在等着,我们可以利用这8分钟去做其他事情,比如画板子和写代码都是没问题的,等8分钟到了之后我们再回来把热水壶关掉(现实中热水壶开了会自动断电,这里只是举例说明)。
那在实际的项目中,比如LCD显示屏的刷新和ADC的采集,都是不用CPU一直盯着的,特别是ADC采集转化时是需要时间的,如果ADC转换时间CPU一直在等,那将是致命的,LCD面对的对象是人眼,所以刷新的频率并不需要太快。
还有按键的扫描,数码管的显示等等!
但需要注意的一点就是:CPU不会像人一样,工作起来可以随时停下来,CPU是需要借助“中断”来把CPU“拉回来”,从而实现任务的切换。
如下图1和图2所示
图1
图2
图1和图2是两种不同的方式,图1中CPU在没有任务需要执行的时候,都是在空闲任务里面循环运行,定时器中断隔一段时间把CPU拉回来。不同的任务当满足要求时,就可以获得CPU的“关照”,关照完后就回到空闲任务重进行循环。
图2中,中断可以发生在任何时候,包括任务执行的时候,但是需要提前定义不同任务需要CPU啥时候回来“关照”。一般以200HZ或者100HZ作为“基准”时间,再加上“节拍计数器”让不同的任务获得CPU短暂的“关照”,任务而不至于被CPU“冷落”。
一般来说LCD刷新的频率10HZ左右即可满足,按键做到20HZ基本上不会出现丢键的情况,数码管刷新率做到50HZ左右即可满足人眼的需求。
我们以100HZ作为定时器中断时间,也就是任务切换的基准时间,则:
LCD的节拍数:100HZ/10HZ=10
按键的节拍数:100HZ/20HZ=5
数码管的节拍数:100HZ/50HZ=2
那任务切换代码是如何实现的,其实很简单,只需要在大循环里面用if做判断即可,给每一个任务做条件判断,满足条件即可让CPU执行相应的任务,如下:
while(1)
{
if(task_num[0]==0) task0(); //task0 节拍数到,CPU执行task0
if(task_num[1]==0) task1(); //task1 节拍数到,CPU执行task1
if(task_num[2]==0) task2(); //task2节拍数到,CPU执行task2
if(task_num[3]==0) task3(); //task3节拍数到,CPU执行task3
}
最后,我们看一下定时中断服务函数里面该怎么写?(省略TH0和TL0部分代码)
void timer0(void) interrupt 1
{
if(task_num[0]) task_num[0]--;
if(task_num[1]) task_num[1]--;
if(task_num[2]) task_num[2]--;
if(task_num[3]) task_num[3]--;
}
这一类程序的架构思路,中心思想就是把“单一的CPU”划分成“多个CPU”的效果,充分利用CPU的资源,使外围电路较多的项目运行起来更为流畅。
好了,今天就先聊到这吧,以上纯属个人看法,仅供参考!