Keil C51程序设计中精确延时的总结
扫描二维码
随时随地手机看文章
一、实现延时的两种方法
1、硬件延时
优点:用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;
缺点:往往在精度要求不是很高时,会使定时器/计数器大材小用,而且很极端时,定时器根本不够的。
2、软件延时
优点:节省硬件资源的同时,只要正确使用可接近要求的精度,这种方法主要采用循环体进行;
缺点:精度不高,对编程者经验要求甚高。
二、硬件延时
1、常用晶振:11.059 2 MHz(容易产生各种标准的波特率)、12 MHz或6 MHz(机器周期
分别为1 μs和2 μs,便于精确延时)。
2、本程序中假设使用频率为12 MHz的晶振。最长的延时时间可达2的16次方=65 536。若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考
虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
3、在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延
时。使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。
三、软件延时(通过调用延时函数)
1、调用延时函数三要素:
入口周期Te、返回周期Tr、内部代码执行周期Ti
则:该函数总执行周期Tf=Te+Tr+Ti;其中:Ti=循环次数*循环周期N
2、短暂延时
如Delay10us( ):总执行高峰期为10us=2us+6us+2us.
void Delay10us()
{
_nop_;
_nop_;
_nop_;
_nop_;
_nop_;
_nop_;
}
说明:不宜嵌套调用,嵌套次数越多误差越大。
3、在C51中嵌套汇编程序段实现延时
在C51中通过预处理指令#pragma asm和#pragma endasm可以嵌套汇编语言语句。用户编写的汇编语言紧跟在#pragma asm之后,在#pragma endasm之前结束。
如:#pragma asm
…
汇编语言程序段
…
#pragma endasm
延时函数可设置入口参数,可将参数定义为unsigned char、int或long型。根据参数与返回值的传递规则,这时参数和函数返回值位于R7、R7R6、R7R6R5中。在应用时应注意以下几点:
◆#pragma asm、#pragma endasm不允许嵌套使用;
◆在程序的开头应加上预处理指令#pragma asm,在该指令之前只能有注释或其他预处理指令;
◆当使用asm语句时,编译系统并不输出目标模块,而只输出汇编源文件;
◆asm只能用小写字母,如果把asm写成大写,编译系统就把它作为普通变量;
◆#pragma asm、#pragma endasm和asm只能在函数内使用。
说明:将汇编语言与C51结合起来,充分发挥各自的优势,无疑是单片机开发人员的最佳选择。
4、使用示波器确定延时时间
熟悉硬件的开发人员,也可以利用示波器来测定延时程序执行时间。方法如下:编写一个实现延时的函数,在该函数的开始置某个I/O口线如P1.0为高电平,在函数的最后清P1.0为低电平。在主程序中循环调用该延时函数,通过示波器测量P1.0引脚上的高电平时间即可确定延时函数的执行时间。方法如下:
把P1.0接入示波器,运行上面的程序,可以看到P1.0输出的波形为周期是3 ms的方波。其中,高电平为2 ms,低电平为1 ms,即for循环结构“for(j=0;j<124;j++) {;}”的执行时间为1 ms。通过改变循环次数,可得到不同时间的延时。当然,也可以不用for循环而用别的语句实现延时。
说明:这里讨论的只是确定延时的方法。
5、使用反汇编工具计算延时时间
对于不熟悉示波器的开发人员可用Keil C51中的反汇编工具计算延时时间,在反汇编窗
口中可用源程序和汇编程序的混合代码或汇编代码显示目标应用程序。但要求对于汇编的指令周期要熟悉。
说明:此种方法如果你熟悉汇编指令周期是比较简单的,这里不作详细讨论。
6、使用性能分析器计算延时时间(即:Keil C51的debug技巧)
A51的程序执行时间可能通过指令周期计算出来,而C51的却无从下手,很多程序员为了得到精确的执行时间而研读反汇编代码,何等的悲哀。巧妙的使用Keil中的debug功能,问题就迎刃而解了。
下面举例说明:
该程序为一个延时程序,在12M的晶振下,调用一次的时间为16uS ,执行一次循环的时间为9uS(延时范围(25us~589.831ms))。这样来,假设有语句Delay(N);那么该语句的精确延时的计算公式就是(9*N+16)uS了.这个公式可以理解吧!
如何得到程序的调用时间和执行一次循环的时间了。接着看下面:
在主程序MAIN()函数下添加上面两条语句,当前的SEC栏为执行到DELAY(1);语句所花的时间。T(0-)
上面的SEC栏为执行完DELAY(1)所花的时间,这样就可以得到DEALY(1)这条语句的执行时间为595-570=25uS.
上面的SEC栏为执行完DELAY(2)所花的时间,这样就可以得到DEALY(2)这条语句的执行时间为629-595=34uS.
结果不就出来了嘛,T[DELAY(2)]-T[DELAY(1)]不就是执行一次循环的时间嘛,
而T[DELAY(1)]减去执行一次循环的时间就是调用一次要花的时间了。精确到1个机器周期。(这里可以通过列简单的一元二次方程组求出来的,因此不作详细讨论)