更多课程 选择中心

嵌入式培训
达内IT学院

400-111-8989

嵌入式中究竟该如何活用“延迟”?

  • 发布:嵌入式培训
  • 来源:嵌入式资讯
  • 时间:2020-07-17 10:49

背景:有人问“有没有好用的延迟函数啊?”我的第一反应就是“延迟函数要视自己的应用而编写,不可能千篇一律的应用。”可是回首一看,单片机的发展历程,在不同时期里有着不一样的延迟函数。

在我上学的年代里,单片机课程老师对汇编语言有着非常深入的了解,如XX指令是单指令周期,XX指令是双指令周期。如果使用了C语言编程,也要仔细看生成的汇编代码然后再调节。例如下面的代码示例:

功能 延时(12M 24M)

误差 Ms S 5% 10Us 8%-80%

//24M晶振 延时 n毫秒

void DelayMs_24M(unsigned int n)

{

unsigned int i=0,j=0;

for(i=0;i

for(j=0;j<357;j++);

}

延迟函数是通过的两个循环计算而形成的停机等待而达到延迟的目的。代码是通过查看由C语言生成的汇编代码指令——那个357便是由此计算出来的。当然,延迟函数是否精准也完全取决于那个357数字的选择了。

单周期指令,双周期指令,数一数便可以了?其实查看汇编代码没有这么简单的,毕竟For循环也需要系统开销的,还有其它比较,判断指令什么的。但这一切在IAR for AVR编译环境里似乎就简单多了。

在IAR for AVR编译环境里,用户只需要 #include "intrinsics.h"便可以调用void __delay_cycles(unsigned long);函数,这个函数是系统函数,其代表着一个机器周期。用户不再需要计算汇编语言的指令周期,不必再细读单片机的操作手册,强大的IAR编译环境 自己就算好了——单片机发展到IAR for AVR时代,也基本代表着汇编退居二线。由于篇幅的原因,版主就不再这里为大家帖出代码示例了。

在Atmel的8位单片机AVR系列一统天下的时候,ARM内核为代表的单片机在悄然崛起。不知不觉,以ST公司stm32f103为代表的32位Cortex-M3内核的单片机占据了市场大部分分额,各大论坛争先推出STM32版块。

其中,某位牛人推出的使用systick函数来完成延迟函数颇具人气。我们来看一下源代码:

//初始化延迟函数

void delay_init(u8 SYSCLK)

{

SysTick->CTRL&=0xfffffffb;//选择内部时钟 HCLK/8

fac_us=SYSCLK/8;

fac_ms=(u16)fac_us*1000;

}

void delay_ms(u16 nms)

{

SysTick->LOAD=(u32)nms*fac_ms; //时间加载

SysTick->CTRL|=0x01; //开始倒数

while(!(SysTick->CTRL&(1<<16))); //等待时间到达

SysTick->CTRL&=0XFFFFFFFE; //关闭计数器

SysTick->VAL=0X00000000; //清空计数器

}

牛人的代码还是非常简洁的,使用起来也方便,首先调用delay_init函数,然后,再调用delay_ms()函数。这个延迟函数也是非常 准确的,因为其使用了单片机的硬件定时器模块。在STM32F103高达72MHz的主频,优化的指令集系统下,系统的开销完成可以忽略。笔者也将其成功 应用于单总线通讯方式的数字温度采集传感器18B20芯片上,测试良好。

写到这里,笔者已经介绍了三种延迟函数,它们三个都有一个共同的特点:阻塞延迟函数——在“等待”延迟函数到来的时候里,单片机并没有处理其它 有用,有意义的事情,而是停机在等待着时间的到来。对于我们要处理大量数据的单片机系统来说,这个劣势有时就很难接受的。那么我们要怎么解决呢?

我们仍然以STM32F103为例,仍然要使用强大的定时器,这里我们再次选用systick定时器。我们首先要初始化ST单片机systick,其每1ms进入中断一次,代码如下:

if (SysTick_Config(72000)) //参数为系统时钟的向上溢出值,此配置为72000,即1ms中断一次

{

/* Capture error */

while (1);

}

之后,我们在systick的中断函数里计数,示例代码如下:

void SysTick_Handler(void)

{

if(gCntLed[0] > 0)

{

gCntLed[0]--;

}

else

{

gCntLed[0] = 0;

}

}

从上面代码可以清楚看到,每1ms,gCntLed[0]将计数值减1,直到为0时止。而main函数里,就要不断的查询这个gCntLed[0]的值,当未达到0值时,就去做别的事情,而查询到0值时,再去处理自己的事情,示例代码如下:

while(1)

{

if(gCntLed[0] == 0)

{

LedToggle(0);

gCntLed[0] = 200;

}

KeyScan();

}

通过未阻塞的延迟函数,我们实现了LED灯每隔200ms闪烁一次的效果,与其同时,我们也没有停止不断扫描按键。——这就是非阻塞延迟函数的强大优势。非阻塞式延迟函数还主要应用于嵌入式操作系统函数里,喜欢的网友可以自己查看相关函数。

随着时代的进步,能源的问题逐渐突出出来。刚刚笔者介绍的几种函数都是在不停的“运行”,看似什么事情也没有做,但是单片机确实在全力的“奔跑”,这与当前节碳减排,低功耗格格不入。MSP430算得上是低功耗的代表了,其延迟函数可以拿来借鉴一下。

在MSP430的低功耗设计中,阻塞式延迟函数是基本不用的——因为功耗太大,未阻塞式延迟函数是必备条件。设计主要思想是,定时让 MSP430从睡眠模式里“醒”过来,查看一下当前的时间与状态,然后再做决定如何处理。换句话说,上面的示例就变成了,MSP430每1ms准时醒来一 次,处理了一下gCntLed[0]的值,然后又查看了一下,如果非0值,则继续“睡”去了;如果恰好是0值,则再干一会儿事情……这里,MSP430大 部分时间里就处于了低功耗的睡眠模式,自然也就节能了。

 最后,达内嵌入式培训机构提醒每一个it爱好者:如果你想要在短时间内快速入门,顺利掌握一门技术,建议还是认真学习视频。多练习,多动手。

版权声明:转载文章来自公开网络,版权归作者本人所有,推送文章除非无法确认,我们都会注明作者和来源。如果出处有误或侵犯到原作者权益,请与我们联系删除或授权事宜。

预约申请免费试听课

填写下面表单即可预约申请免费试听!怕钱不够?可就业挣钱后再付学费! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:嵌入式C语言学习技巧有哪些?
下一篇:嵌入式的你,为啥要懂uboot?

怎样才能学好单片机?

单片机:写1清零,写0清零,有什么区别?

嵌入式工程师一定不要乱用全局变量

嵌入式培训靠谱吗?就业怎么样?

  • 扫码领取资料

    回复关键字:视频资料

    免费领取 达内课程视频学习资料

  • 搜索抖音号

    搜索抖音号:1821685962

    免费领取达内课程视频学习资料

Copyright © 2021 Tedu.cn All Rights Reserved 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有

选择城市和中心
黑龙江省

吉林省

河北省

湖南省

贵州省

云南省

广西省

海南省