众所周知,比较于其他编程言语,C言语在编写嵌入式编程中有着肯定的优势。但它总也有缺陷的:它的时序性比较差,不容易编写精准的延时。而在编写嵌入体系驱动程序时,常常需求比较准确的软件延时,这使得C言语的“下风”暴露了出来,一般都只能经过嵌入汇编的办法完成。例如,在1MHZ作业频率下需求延时10us,就需求嵌入10句“空操作”指令,显然在书写上比较尴尬。本文提出一种简化书写的延时计划,运用带参数的宏构来造细小时刻片,能够完成彻底准确的软件延时,大大方便了驱动程序及软件模仿通信协议的编写。
阐明:以下皆为ICC AVR渠道下的评论,对AVR系列一切类型的单片机皆有用。至于其他渠道,可据此计划自行修正和移值。
该计划的完成办法其实很简单:
首要界说N个宏,别离调用 1 ~ N 个汇编“空操作”指令,如:
#define NOP_1 asm(“nop”) //延时一个时钟周期
#define NOP_2 NOP_1; asm(“nop”) //延时两个时钟周期
#define NOP_3 NOP_2; asm(“nop”) //延时三个时钟周期
#define NOP_4 NOP_3; asm(“nop”) //延时四个时钟周期
……
#define NOP_40 NOP_40; asm(“nop”) //延时40个时钟周期
然后运用“##”操作符,完成带参数宏的延时:
#define NOP(N) NOP_##N //延时 N个时钟周期
操作符的作用是把两个部分的内容连成一个内容。就是说,NOP(3)打开后成为NOP_3,NOP(4)打开后成为NOP_4,等等。因而,界说上述宏之后,就可经过调用NOP(N)句子完成准确软件延时。例如:
NOP(4); //延时4个时钟周期
上述句子打开进程如下:
NOP_3 ; asm(“nop”);
NOP_2; asm(“nop”); asm(“nop”);
NOP_1; asm(“nop”); asm(“nop”); asm(“nop”);
asm(“nop”); asm(“nop”); asm(“nop”); asm(“nop”);
正好延时4个时钟周期
不过,上面的宏还不行完善,假如企图运用下面的句子,程序将会呈现缝隙。
if(表达式)
NOP(3);
else
NOP(4);
这是由于NOP(N)宏打开之后,不是一个句子,而是变成N个句子。故有必要用花括号括起来,程序才干运转正确。即应该改为:
if(表达式)
{
NOP(3);
}
else
{
NOP(4);
}
假如把NOP(N)宏的界说改为:
#define NOP(N) do{ NOP_##N ; }while(0)
则NOP(N)宏打开之后只构成一个句子,将不会呈现上面的问题。
可是要留意,“##”操作符只能依照原样把两头的内容连在一起。故NOP(N)的参数有必要是详细的常量,即只能是数字,而且,与该数字相对应的宏NOP_N已有必要现已界说。
例如:
“NOP(3+4);”句子打开之后,将将变成“NOP_3+4;”,呈现语法错误;
又如:
“NOP(a);”句子打开之后,将将变成“NOP_a;”,而“NOP_a;”未界说。
只要这样的句子才是正确的调用:
NOP(20); //延时20个时钟周期
将上述计划整理成一个头文件,今后就能够恣意调用了。下面是整理好的头文件:
留意:该文件不宜作长时刻的延时。长时刻的延时将会调用很多的“空操作”指令,占用很多的程序指令空间。这个问题将在V2.0版别中处理。