程序延时里的思维

摘要:
即使用空循环来消耗CPU时间,以达到延迟的目的。如果有一个空间,其中有键、显示器、串行端口接收和led。在判断按键后,您需要在大约10毫秒的延迟后再次判断//等待钥匙释放12}13}14}图1-2 2D;按键扫描采用定时器中断扫描模式。将串行端口和密钥视为来自不同的平面~此处引用了缓存的概念。将值保存在密钥buf中。

程序延时里的思维

  大概所有的51单片机初学者在用到延时的时候都有一个共同点,那就是使用一段空循环消耗CPU的时间从而达到延时目的,常见的函数就是图1-1中的delay函数。这种模式在初学阶段的确是简单易懂,学习起来会得心应手,这可以称得上是我们单片机生涯的童年时代,它使我们学会了走起来。但对于学习了三四年单片机的人来说,不能再单单走了,要跑起来!

1 void delay(unsigned int ms)    
2 { 
3     unsigned int i,j; 
4     for( i = 0; i < ms; i++ )
5     { 
6         for( j = 0; j < 1141; j++ );
7     }
8 }

 

                          图1-1

   为何说delay函数只是走起来?这得要看清楚作为初学者我们的思维是一种什么样的概念,其实我也说不清。。。只能打个比喻,假如有个空间里面有按键、显示屏、串口接收、led。在我的认知里有三种思维维度:

  一维度:一个平面里的一条直线。程序从开始就一步一个模块地走,我们都知道,按键存在这机械抖动,为了消除这个抖动,就需要在判断按键后延时10ms左右的时间再次判断,如图1-2,那么这10ms的时间被固定在了这条时间轴里面。10ms的时间对单片机来说是很长很长的,会导致显示屏刷新变慢,LED驱动迟钝,串口数据丢失。

                                        程序延时里的思维第1张

 1 keyscan(void)
 2 {    
 3     unsigned char keynum;
 4     if(Key==0)   //检测是否有键按下
 5     {
 6         delay(10);    //延时10ms去抖动
 7         if(Key==0)    //再次检测是否依然有键按下
 8         {
 9             
10              keynum = 1;
11              while(Key==0);          //等待按键释放
12          }
13     }
14 }   

                           图1-2

二维度:一个平面里的曲线。串口接收采用了中断方式,按键扫描采用了定时器中断扫描方式,因为串口数据不是一直有,且按键不是一直被按,所以时间轴比一维度的要缩短了,但是当定时器中断时,进入中断扫描按键,delay函数依然占用了10ms的时间。

                                  程序延时里的思维第2张

三维度:空间里不同维度交织的直线。立体图太难画了,就当串口和按键是来自不同的平面吧~这里引用了缓存的概念,通过变量buf缓存数据,串口通过中断把数据存到串口buf中,按键通过定时器中断扫描,把值存到按键buf中,这时候按键扫描用的是图1-3中的函数,配置定时器为2.5ms中断,如此一来,取消了delay函数,主函数轴中只需要几条指令的时间就把按键扫描的功能完成。在需要扫描按键的时候,读取按键buf的值,判断它是否大于10即可,而按键其实在另一个时间轴里完成了10*2,5个ms的滤波。串口和按键各自在不同的时间轴中运行,通过buf变量和主时间轴交织在一起,仿佛形成了一个三维的空间,用专业的术语描述这就叫做——分时系统。

                            程序延时里的思维第3张

 1 void timer() interrupt 1 //定时器中断函数 2.5ms
 2 {
 3     if(key == 0)                     //如果按键按下
 4     {
 5         if(buf < 20)                //滤波20*2.5ms
 6         {
 7             buf++;    
 8         }
 9     }
10     else
11     {
12         if(buf > 0)
13         {
14             buf--;
15         }    
16     }        
17 }        

                       图1-3

  现在回过头来看看delay函数,是不是处在一维度里?这种思维会约束我们写代码的习惯,使我们的代码得不到高效率、高稳定性,我们必须要往上冲破更高维度的思维。CPU的时间是非常宝贵的,哪怕是1ms的时间。为了得到更快的速度,IC厂商不断地提高CPU时钟频率,主流的STM32F4系列达到了168M的主频;CPU架构也由冯诺依曼结构发展成了哈佛结构;过去取指令一个时钟,而后再执行指令又一个时钟,已经演变成多级流水线架构,,如图1-4。IC厂商如此努力把CPU速度提高,我们怎么能让CPU原地转几万圈来延时,这太对不起人家了~

程序延时里的思维第4张程序延时里的思维第5张

免责声明:文章转载自《程序延时里的思维》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Web Worker 使用教程Microsoft Web Test Recorder在录制时没有显示下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

框架模块设计经验总结

转自:http://www.cnblogs.com/zgynhqf/archive/2011/07/15/2107593.html 这是原创,尊重原创、、、、、、、、、、、、     框架模块设计经验总结      三个月没写日志了,比较懒散……下半年准备做OEA 的 B/S 版本,比较复杂,需要从架构设计开始认真入手。正好今天到了部门反思的时间,今天...

缓存三大问题的解决办法

1.缓存穿透  在大多数互联网应用中,缓存的使用方式如下图所示:       当业务系统发起某一个请求时:     首先判断缓存中是否有该数据。     如果缓存中存在,则直接返回数据。     如果缓存中不存在,则再查询数据库,然后返回数据。   了解了上述过程后,下面说说缓存穿透。   1.1 缓存穿透的危害   如果存在海量请求查询根本就不存在的数据...

终于理解二级指针的作用了

之前学习swap函数时,知道传递指针可以实现对要交换变量本尊的修改,而直接传递值做不到这一点.究其原因,是因为函数传递参数时是以拷贝的形式,因此函数内部对其拷贝进行操作,不会影响到本尊. 如果想要通过函数实现对一级指针的值进行修改该如何去做呢?如果直接把它传进去,其实修改的是它的拷贝,而对它并没有影响.这个时候就是二级指针出场的时候了. #include...

格式Table.TransformColumns(Power Query 之 M 语言)

数据源:         任意表,其中包含文本列 目标:         对文本列格式进行设置  操作过程:    选取文本列》【转换】》【格式】》选取        M公式:     = Table.TransformColumns( 表, {{"列名1", 转换函数1, 数据类型1},…,{"列名n", 转换函数n, 数据类型n}}, 剩余列转换函数,...

Android开发之Instrumentation(自动化测试)

Android在JUnit的之外给我们又提供了Instrumentation测试框架。通过Instrumentation可以模拟按键按下、抬起、屏幕点击、滚动等事件,有效地控制Activity进行自动化测试。 Instrumentation是执行application instrumentation代码的基类。当应用程序运行的时候instrumentati...

转 将python的datetime转换为unix时间戳

python datetime unix时间戳以及字符串时间戳转换   将python的datetime转换为unix时间戳 import time import datetime dtime = datetime.datetime.now() ans_time = time.mktime(dtime.timetuple())  将unix时间戳转换为...