前些天在版主群里有人问“有没有好用的推迟函数啊?”我的榜首反响就是“推迟函数要视自己的运用而编写,不可能千人一面的运用。”可是回忆一看,单片机的开展进程,在不一起期里有着不一样的推迟函数。
在版主上学的年代里,单片机课程教师对汇编言语有着十分深化的了解,如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大部分时刻里就处于了低功耗的睡觉形式,天然也就节能了。
又到总结的时分了,几种推迟函数各有特色与运用场景,各位亲爱的网友们依据自己的需求来自行挑选吧!当然,也能够来论坛的ARM版块发帖求助,版主也会倾力贡献的。