在单片机运用中,经常会遇到需求短时刻延时的状况,一般都是几十到几百μs,而且需求很高的精度(比方用单片机驱动DS18B20时,差错容许的范围在十几μs以内,否则很简略犯错);而某些状况下延时时刻较长,用计时器往往有点小题大做。别的在特别状况下,计时器乃至现已悉数用于其他方面的守时处理,此刻就只能运用软件守时了[1]。
1 C言语程序延时
Keil C51的编程言语常用的有2种: 一种是汇编言语;另一种是C 言语。用汇编言语写单片机程序时,准确时刻延时是相对简略处理的。比方,用的是晶振频率为12 MHz的AT89C51,计划延时20 μs,51单片机的指令周期是晶振频率的1/12,即一个机器周期为1 μs;“MOV R0,#X”需求2个机器周期,DJNZ也需求2个机器周期,单循环延时时刻t=2X+3(X为装入寄存器R0的时刻常数)[2]。这样,存入R0里的数初始化为8即可,其精度能够到达1 μs。用这种办法,能够十分方便地完结512 μs以下时刻的延时。假如需求更长时刻,能够运用两层或更多层的嵌套,当然其精度差错会跟着嵌套层的添加而成倍添加。
尽管汇编言语的机器代码生成功率很高,但可读性却并不强,杂乱一点的程序就更难读懂;而C言语在大多数状况下,其机器代码生成功率和汇编言语适当,但可读性和可移植性却远远超越汇编言语,且C 言语还能够嵌入汇编程序来处理高时效性的代码编写问题。就开发周期而言,中大型软件的编写运用C 言语的开发周期一般要比汇编言语短许多,因而研讨C言语程序的准确延时功用具有重要的含义[3]。
C程序中可运用不同类型的变量来进行延时规划。经试验测验,运用unsigned char类型具有比unsigned int更优化的代码,在运用时应该运用unsigned char作为延时变量。
2 单层循环延时精度剖析
下面是进行μs级延时的while程序代码。
延时函数:
void delay1(unsigned char i) {
while(i );}
主函数:
void main() {
while(1) {
delay1(i);
}
}
运用Keil C51的反汇编功用,延时函数的汇编代码如下:
C:0x00E6AE07MOVR6,0x07
C:0x00E81FDECR7
C:0x00E9EEMOVA,R6
C:0x00EA70FAJNZC:00E6
C:0x00EC22RET
图1 断点设置方位图
经过对i赋值为10,在主程序中图1所示的方位设置断点。经过测验,第1次履行到断点处的时刻为457 μs,再次履行到该处的时刻为531 μs,第3次履行到断点处的时刻为605 μs,10次while循环的时刻为74 μs,整个测验成果如图2所示。
图2 运用i–办法测验仿真成果图
经过对汇编代码剖析,时刻推迟t=7X+4(其间X为i的取值)。测验标明,for循环办法尽管生成的代码与用while句子不大一样,可是这两种办法的功率简直相同。C言语中的自减办法有两种,前面都运用的是i–的办法,能不能运用–i办法来取得不同的作用呢?将前面的主函数坚持不变,delay1函数修改为下面的办法:
void delay1(unsigned char i) {
while(–i);}
相同进行反汇编,得到如下成果:
C:0x00E3DFFEDJNZR7,
C:00E3C:0x00E522RET
比较发现,–i的汇编代码功率显着高于i–办法。因为只需1条句子DJNZ,履行只需求2个时钟周期, 1个时钟周期按1 μs核算,其延时精度为2 μs;别的,RET需求2个时钟周期,能够到达汇编言语代码的功率。按前面的测验条件进行测验,第1次履行到断点处的时刻为437 μs,再次履行到该处的时刻为465 μs,第3次履行到断点处的时刻为493 μs,10次while循环的时刻为28 μs,整个测验成果如图3所示。
图3 运用–i办法测验仿真成果图
调整i的取值,i取8时延时时刻为24 μs,i取9时延时时刻为26 μs。经过剖析得出,10次循环为28 μs是因为外层循环形成的,其精度能够到达2 μs。在规划时应该考虑参数传递和RET句子履行所需求的时刻周期。试验剖析发现,for句子运用–i办法,相同能够到达与汇编代码相同的精度。i取不同值时延时仿真成果如图4所示。
图4 i取不同值时延时仿真成果图
3 多重嵌套下的C程序延时
在某些状况下,延时较长,仅运用单层循环办法是不能完结的。此刻,只能运用多层循环办法,那么多重循环条件下,C程序的精度怎么呢?下面是一个运用for句子完结1 s延时的函数。
延时函数
void delay1s(void) {
for(k=100;k>0;k–) //守时1 s
for(i=20;i>0;i–)
for(j=248;j>0;j–);
}
主函数调用延时函数代码段:
while(1) {
delay1s();
scond+=1;
}
为了直接衡量这段代码的作用,运用Keil C找出这段代码发生的汇编代码:
C:0x00B37002JNZ
C:00B7C:0x00B5150CDEC0x0C
C:0x00B7E50DMOVA,0x0D
C:0x00B9450CORLA,0x0C
C:0x00BB70DEJNZC:009B
C:0x00BDE50BMOVA,0x0B
C:0x00BF150BDEC0x0B
C:0x00C17002JNZC:00C5
C:0x00C3150ADEC0x0A
C:0x00C5E50BMOVA,0x0B
C:0x00C7450AORLA,0x0A
C:0x00C970CAJNZC:0095
C:0x00CB22RET
剖析汇编代码,其他汇编代码运用的不是DJNZ跳转办法,而是DEC和JNZ句子来完结循环判别。1条JNZ指令要花费2个时钟周期,3条指令就需求6个机器周期,MOV指令和DEC指令各需求1小时钟周期,1个时钟周期按1 μs算,其精度最多到达8 μs,最终加上一条LCALL和一条RET句子,所以整个延时精度较差[4]。
运用Keil C的测验东西,在一处设置一个断点。第1次履行到中止处的时刻为0.000 513 s,第2次履行到中止处的时刻为1.000 922 s,时刻推迟为1.000 409 s,测验成果如图5所示。关于上面的3种循环嵌套,循环次数为100×20×248=496 000,每次循环的时刻约为2 μs。
图5 三重嵌套循环1 s完结时刻测验成果
为获取与汇编言语延时的距离,相同进行1 s的延时,程序代码段如下:
LCALL DELY1S
INC Second
DELY1S:MOV R5,#100
D2:MOV R6,#20
D1:MOV R7,#248
DJNZ R7,$
DJNZ R6,D1
DJNZ R5,D2
RET
经过Keil C51测验,其实践推迟时刻为0.997 943 s。尽管C言语完结延时办法的汇编代码杂乱度添加,可是与汇编言语完结的办法功用距离并不大。
4 总结
汇编言语在实时性方面具有较大的优越性,尽管运用Keil C51能够在C言语程序中嵌入汇编代码,可是杂乱度显着提高。试验证明,只需合理地运用C言语,在延时编程方面就能够到达与汇编言语附近的精度。为了取得准确的时刻推迟,可经过Keil C东西的仿真功用,调整推迟量,然后得到较抱负的成果。
参考文献
[1] InfiniteSpace Studio/isjfk. 51单片机KeilC延时程序的简略研讨[EB/OL]. http://www.icwin.net/ShowArtitle.ASP?art_id=5564cat_id=33.
[2] 沈舷. 延时程序延时时刻的准确核算.电工技能与自动化[J]. 2005,34(6):152-153,157.
[3] 蹇兴亮.单片机守时中止的准确守时编程办法种种[J].单片机与嵌入式体系运用,2004(8).
[4] 聂毅.单片机守时器中止时刻差错的剖析及补偿[J].微核算机信息,2002,18(4):37-38.
单片机C程序延时精度研讨
在单片机应用中,经常会遇到需要短时间延时的情况,一般都是几十到几百μs,并且需要很高的精度(比如用单片机驱动DS18B20时,误差容许的范围在十几μs以内,不然很容易出错);而某些情况下延时时间较长,
声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/chuanganqi/199013.html