对于某些对时间精度要求较高的程序,用 c 写延时显得有些力不从心,故需用到汇编程序。本人通过测试,总结了 51 的精确延时函数(在 c 语言中嵌入汇编)分享给大家。至于如何在 c 中嵌入汇编大家可以去网上查查,这方面的资料很多,且很简单。以 12MHz 晶振为例,12MHz晶振的机器周期为 1us,所以,执行一条单周期指令所用时间就是 1us,如 NOP 指令。下面具体阐述一下。
若要延时 1us,则可以调用_nop_();函数,此函数是一个 c 函数,其相当于一个 NOP 指令
使用时必须包含头文件 intrins.h
例如:
#include #include void main(void) { P1 = 0x0; _nop_(); //延时 1us P1 = 0xff; } 延时 5us,则可以写一个delay_5us()函数 delay_5us() { #pragma asm nop #pragma endasm } 这就是一个延时 5us 的函数,只需要在需要延时 5us 时调用此函数即可。或许有人会问,只有一个 NOP 指令,怎么是延时 5us 呢? 答案是: 在调用此函数时,需要一个调用指令,此指令消耗 2个周期(即 2us);函数执行完 毕时要返回主调函数,需要一个返回指令,此指令消耗 2 个周期(2us)。调用和返回消耗了 2us + 2us = 4us。然后再加上一个NOP指令消耗 1us,不就是5us吗? 延时 10us。 我们编写一个 delay_10us()函数 delay_10us(){ #pragma asm nop nop nop nop nop nop #pragma endasm } 这就是延时 10us 的函数。同延时 5us 函数一样,调用和返回消耗 4us,加上函数中的6个 NOP 指令6us,正好是10us。 此时有人不禁要问那么,任意微秒时,函数应该怎么写呢? 看我慢慢道来:首先,延时任意微秒我暂时没有想到,但是,我可以延时任意偶数微秒或延时任意奇数微秒, 也就是说,需要两个函数,一个函数专门实现任意偶数的微秒级延时,另一个函数专门实现 任意奇数的微秒级延时。只要有了这两个函数在,不就可以延时任意的微秒了吗! 首先我们来实现任意偶数的微秒级延时: void delay_even_us(unsigned char even){ //任意偶数的微秒级延时 #pragma asm 1 mov a, r7 //为什么要用到 r7 呢,因为 r7 里面装的是函数的参数!!! // ^_^ 这句消耗 1 个周期 2 subb a, #10H //这句看完程序我再解释 这句消耗 1 个周期 3 mov b, #02H //这句看完程序我再解释 这句消耗 2 个周期 4 div ab // 这句意思是 a/b ,商放在 a 里,余数放在 b 里 稍 //后解释 这句消耗 4 个周期 5 mov r0, a //这句消耗 1 个周期 6 nop //这句消耗 1 个周期 7 loop: 8 djnz r0, loop //不等于 0 跳转指令,也就是说 r0 中的值若不为 0 的话, //就跳转到 loop 处 这句消耗 2 个周期 #pragma endasm } 下面我们来分析一下为何这样写:为了方便分析,我给句子编上了序号。我们以延时 100us为例(delay_even_us(100))。 首先减去调用和返回的 4 个周期(4us)。再减去参数传递所消耗的2 个周期。因为 c 函数参数传递到汇编是需要消耗周期的。一共消耗了 6 个周期。也就是消 耗了 6us,还剩下 100us-6us=94us。 然后再看我再程序上面注释的各语句消耗时间: 从 1 句到 5 句一共消耗了 10 个周期(不信你数数^_^)。还剩下 94us-10us=84us。 现在就看第 8 句了,这句应该消耗 84 个周期才能达到我们延时 100us。而这句每执行一次消耗 2 个周期,也就是说 r0 的值应该为 84/2=42。 那么,怎样达到 r0=42 的呢?我们从第 1 句开始分析: 第 1 句中,r7 为 c 传递过来的参数,此例子中为 100.执行完此句后 a 的值为 100; 第 2 句中,将 a=a-16 = 100-16=84。此句结束后 a 的值为 84; 第 3 句中,给 b 赋值为 2; 第 4 句中,用 a 来除以 b。结果商存入 a 中,余数存入 b 中,此句结束后 a 的值为 a=a/b = 84/2= 42; 第 5 句,将 a 值赋给 r0,此句结束后 r0 的值为 42。 于是乎, r0 的值为 42 这个目的达到了。结合前面的分析,此程序是不是延时了 100us 呢? 答案当然是 “是”了! 这个函数可以实现任意偶数微秒(>=18)的延时的,不信的话可以带一个值进去算的。至于为什么值必须>=18us,用不着我解释了吧。 任意奇数的微秒级延时: void delay_odd_us(unsigned char odd){ #pragma asm 1 mov a, r7 2 subb a, #0fH 3 mov b, #02H 4 div ab 5 mov r0, a 6 loop1: 7 djnz r0, loop1 #pragma endasm } 此即为任意奇数微秒的延时,和偶数延时一样的道理,不解释了。^_^ 此函数的参数必须大于等于 17,请思考为什么?^_^
上一篇:51单片机最小系统电路-设计教程
下一篇:51单片机汇编程序,温度报警项目
推荐阅读最新更新时间:2024-11-06 10:03
设计资源 培训 开发板 精华推荐
- HV257DB1,基于HV257的高压采样保持阵列演示板
- 【天津工业大学】差分放大电路测试仪 滕天淇
- 霍尔电流表
- 使用 Analog Devices 的 REF192 的参考设计
- AM6TW-4807DZ ±7.2V 6 瓦双路输出 DC/DC 转换器的典型应用
- LTC3214EDD 演示板、低噪声、高电流 LED 闪光灯充电泵,Vin = 2.9V - 4.4V,AOT LED
- NCP3337MN250GEVB,NCP3337 评估板,用于 PCMCIA 卡的 2.5V DC 至 DC 单输出电源
- MCP1501T-40E/SN 4.096V 负参考电压典型应用电路
- STR-PWRNCV8163-R0-GEVK:Strata NCV8163 LDO 稳压器,250 mA,超低压差,超低 Iq,超高 PSRR,超低噪声
- EVAL-AD9835EB,AD9835 直接数字合成器、波形发生器评估板