单片机C语言中_nop_函数使用及延时计算
STC指令延时精确计算

STC 单片机指令精确延时分析guoguo适用单片机:STC-1T ,晶振12MHz例1:Delayus( ) —— 延时能力2~256usC51代码:/*****延时us***************************************** 功能:延时i+1 us ,包含调用时间* 参数:无* 描述:适用于STC1T 单片机,晶振12MHz* 时钟周期0.08333us ,机器周期0.125us* 特别说明:编译器优化等级设为0,i 的有效范围1~255* 作者:张国营* 日期:2013-10-12*****************************************************/void delay10us(void) //包含调用时间,误差 0us{uchar i=9;do{_nop_();_nop_();_nop_();i--;}while(i);} 编译后的汇编代码:Keil 编译器优化等级0时钟周期Code 地址 机器码 汇编指令 备注 6 LCALL addr16 无参数调用 2 C:0x0C29 753709 MOV 0x37,#0x09 初始化局部变量 1 C:0x0C2C 00 NOP循环1us 1 C:0x0C2D 00 NOP1 C:0x0C2E 00 NOP 4 C:0x0C2F 1537 DEC 0x372 C:0x0C31 E537 MOV A,0x373 C:0x0C33 70F7 JNZ C:0C2C4 C:0x0C35 22 RET 返回计算公式,T=[(6+2)+ i *(3+4+2+3)+ 4 ] / 12= (12+12 * i)/12 =1+i 单位us 局部变量n=9时,延时10us ;n=99时,延时100us例2:Delayms( )——延时能力1~255ms ,误差约为 +1.25usC51代码:/*******************延时ms************************************* * 适用于STC1T 单片机,晶振12MHz ,时钟周期0.08333us ,机器周期0.125us * 延时能力:n = 1~255 ms ,误差为 +1.25 us* 特别说明:编译器优化等级设为0*******************************************************************/ void delayms(uchar n) //精确延时,包含调用时间,{uchar i,j;//---------循环体精确延时n ms-------------------do{ //约延时[(i+1)*j+1]*n us _nop_();j = 9;do{ //约延时 (i+1)*j us _nop_();i = 110;do{ //精确延时 i us _nop_();_nop_();_nop_();i--;}while(i);j--;}while(j);n--;}while(n);}编译后的汇编代码:Keil 编译器优化等级0时钟周期Code 地址 机器码 汇编指令 备注 2 C:0x0BB7 7F32 MOV R7,#0x32 含参数调用 6 C:0x0BB9 120BFB LCALL delayms(C:0BDB)3 C:0x0BDB 8F2F MOV 0x2F,R7 传递参数1 C:0x0C04 00 NOP n 循环:1us2 C:0x0C05 753109 MOV 0x31,#0x091 C:0x0C08 00 NOP j 循环:1us2 C:0x0C09 75306E MOV 0x30,#0x6E1 C:0x0C0C 00 NOPi 循环:1 us 1 C:0x0C0D 00 NOP1 C:0x0C0E 00 NOP 4 C:0x0C0F 1530 DEC 0x302 C:0x0C11 E530 MOV A,0x303 C:0x0C13 70F7 JNZ C:0C0C4 C:0x0C15 1531 DEC 0x31j 循环:1us2 C:0x0C17 E531 MOV A,0x313 C:0x0C19 70ED JNZ C:0C084 C:0x0C1B 152F DEC 0x2Fn 循环:1us2 C:0x0C1D E52F MOV A,0x2F3 C:0x0C1F 70E3 JNZ C:0C044 C:0x0C21 22 RET 返回计算公式,T= {15+n * [ j *(i * 12+12)+ 12 ] }/ 12=15/12+n*[ j*(i+1)+1],单位us 将i=110,j=9代入上式得:T=1000 * n+1.25宁夏成泰电子科技有限公司 * 研发部张国营。
单片机编写延时函数的简单方法

单片机编写延时函数的简单方法单片机编程中,延时函数是很常用的一种函数。
它用于在程序的执行过程中,暂停一段时间,以实现一些需要时间控制的功能,比如LED灯的闪烁、舵机运动等。
在单片机编写延时函数时,一般有以下几种常见的方法:1. 使用定时器(Timer):定时器是单片机内部的一个功能模块,可以按照设定的时间间隔触发中断或产生脉冲,通过编写中断服务程序来实现延时。
具体步骤如下:-初始化定时器,设置计时器的工作模式、预分频系数等。
-设置计时器的计数值或比较值,根据这个值来确定延时的时间。
-等待定时器中断发生,即延时结束。
使用定时器编写延时函数的优点是精度高,可以实现较长的延时时间。
但是相应地,也需要花费较多的代码来配置和控制定时器的工作。
2.使用循环延时:循环延时是单片机编程中最容易理解和实现的一种延时方法。
通过循环执行一段代码,直到达到预期的延时时间。
具体步骤如下:-计算循环次数,根据CPU的主频和需要延时的时间来确定循环次数。
-进入循环,执行空操作,多次循环达到延时效果。
使用循环延时的优点是简单易用,只需要几行代码就可以实现。
缺点是精度较低,受到CPU主频和其他程序的影响。
3.使用外部晶振:外部晶振是单片机工作的主时钟,也可以用来实现延时操作。
-初始化外部晶振,设置晶振的频率和倍频系数等。
-使用定时器或其他方法,根据晶振频率计算延时时间。
-等待延时结束。
使用外部晶振进行延时的优点是精度较高,可以根据实际的晶振频率来计算延时时间。
缺点是需要额外的硬件电路来连接外部晶振。
以上是几种常见的单片机编写延时函数的方法,相应的选择取决于具体的应用场景和需求。
在实际编写中,可以根据需要进行选择和结合使用,以达到最优的延时效果。
51单片机延时函数

51单片机延时函数在嵌入式系统开发中,51单片机因其易于学习和使用、成本低廉等优点被广泛使用。
在51单片机的程序设计中,延时函数是一个常见的需求。
通过延时函数,我们可以控制程序的执行速度,实现定时器功能,或者在需要的时候进行延时操作。
本文将介绍51单片机中常见的延时函数及其实现方法。
一、使用for循环延时这种方法不精确,但是对于要求不高的场合,可以用来估算延时。
cvoid delay(unsigned int time){unsigned int i,j;for(i=0;i<time;i++)for(j=0;j<1275;j++);}这个延时函数的原理是:在第一个for循环中,我们循环了指定的时间次数(time次),然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有很大差异,所以只适用于对延时时间要求不精确的场合。
二、使用while循环延时这种方法比使用for循环延时更精确一些,但是同样因为硬件和编译器的不同,延时时间会有差异。
cvoid delay(unsigned int time){unsigned int i;while(time--)for(i=0;i<1275;i++);}这个延时函数的原理是:我们先进入一个while循环,在这个循环中,我们循环指定的时间次数(time次)。
然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有差异,所以只适用于对延时时间要求不精确的场合。
三、使用定时器0实现精确延时这种方法需要在单片机中开启定时器0,并设置定时器中断。
在中断服务程序中,我们进行相应的操作来实现精确的延时。
这种方法需要使用到单片机的定时器中断功能,相对复杂一些,但是可以实现精确的延时。
汇编nop指令

汇编nop指令一、概述汇编语言是一种低级语言,它直接操作计算机硬件,与高级语言相比,汇编语言更加灵活和高效。
在汇编语言中,nop指令是一个非常常见的指令,它的作用是让CPU暂停执行一定的时间。
二、nop指令的定义nop指令是汇编语言中的一个伪指令(pseudo-instruction),它不会被翻译成任何机器码,只是告诉汇编器在该位置生成一个空操作码。
nop指令通常被用来填充程序空间或者延迟执行。
三、nop指令的格式在x86架构中,nop指令有多种格式:1. nop:表示生成一个空操作码。
2. nopw:表示生成两个字节的空操作码。
3. nopd:表示生成四个字节的空操作码。
4. nopq:表示生成八个字节的空操作码。
四、nop指令的作用1. 填充程序空间:在程序开发过程中,为了保证代码段对齐或者调整代码段大小,需要插入一些无意义的代码来填充程序空间。
这时候可以使用nop指令来填充。
2. 延迟执行:有些时候需要让CPU暂停执行一定时间以等待外部设备的响应或者其他操作的完成。
这时候可以使用nop指令来延迟执行。
3. 调试程序:在调试程序时,有时需要在某个位置暂停执行以便于观察程序运行状态。
这时候可以在该位置插入nop指令来实现暂停。
五、nop指令的优化虽然nop指令是一个空操作码,但是它也会消耗CPU的时间和资源。
因此,在编写程序时需要避免无意义的nop指令的使用,以提高程序效率。
六、总结通过本文的介绍,我们了解了汇编语言中常见的nop指令。
它可以用来填充程序空间、延迟执行和调试程序等多种场景。
同时,在编写程序时也需要注意避免无意义的nop指令的使用,以提高程序效率。
单片机C51延时时间怎样计算

单片机C51延时时间怎样计算计算单片机C51延时时间通常需要考虑以下几个因素:1. 单片机的工作频率:单片机的工作频率决定了每个时钟周期的时长。
时钟周期(T)为1 / 片内晶振频率。
例如,若单片机的晶振频率为11.0592MHz,则时钟周期为1 / 11.0592MHz ≈ 90.52ns。
2. 延时的时间要求:您需要计算的是具体的延时时间,例如1毫秒(ms),10毫秒(ms)等。
有了上述信息,我们可以使用下面的公式来计算延时时间:延时时间(单位:时钟周期)=(目标延时时间(单位:秒)/时钟周期(单位:秒))延时时间(单位:毫秒)=延时时间(单位:时钟周期)×1000下面是一个示例的代码来演示如何计算并实现一个1毫秒的延时:```c#include <reg51.h>//定义时钟周期#define CLOCK_PERIOD 100 // 以纳秒为单位//定义延时函数void delay_ms(unsigned int milliseconds)unsigned int i, j;for (i = 0; i < milliseconds; i++)for (j = 0; j < 120; j++) // 这里的120是根据实际测量得到的,可以根据硬件和软件环境适当微调//每次循环消耗的时间为120*100纳秒≈12微秒//因此,总延时时间为12*1000微秒=1毫秒}}//主函数void mainP1=0x00;//把P1引脚置为低电平while (1)delay_ms(1000); // 1秒的延时P1=~P1;//翻转P1引脚的电平}```上述代码中,我们通过嵌套循环实现了一个1毫秒的延时。
根据实际硬件和软件环境,您可能需要微调内层循环的次数以达到准确的1毫秒延时。
需要注意的是,单片机的延时准确性受到各种因素影响,包括时钟精度、环境温度等。
在实际应用中,如果对延时精度有较高要求,可能需要进一步进行校准或采用其他更精确的延时方式。
51单片机延时函数

C程序中可使用不同类型的变量来进行延时设计。
经实验测试,使用unsigned char类型具有比unsigned int更优化的代码,在使用时应该使用unsigned char作为延时变量。
以某晶振为12MHz 的单片机为例,晶振为12MHz即一个机器周期为1us。
一. 500ms延时子程序程序:void delay500ms(void){unsigned char i,j,k;for(i=15;i>0;i--)for(j=202;j>0;j--)for(k=81;k>0;k--);}计算分析:程序共有三层循环一层循环n:R5*2 = 81*2 = 162us DJNZ 2us二层循环m:R6*(n+3) = 202*165 = 33330us DJNZ2us + R5赋值 1us = 3us三层循环: R7*(m+3) = 15*33333 = 499995us DJNZ 2us + R6赋值1us = 3us循环外: 5us子程序调用2us + 子程序返回 2us + R7赋值 1us = 5us延时总时间= 三层循环+ 循环外= 499995+5 = 500000us =500ms计算公式:延时时间=[(2*R5+3)*R6+3]*R7+5二. 200ms延时子程序程序:{unsigned char i,j,k;for(i=5;i>0;i--)for(j=132;j>0;j --)for(k=150;k>0;k --);}三. 10ms延时子程序程序:{unsigned char i,j,k;for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=248;k>0;k --);}四. 1s延时子程序程序:void delay1s(void){unsigned char h,i,j,k;for(h=5;h>0;h--)for(i=4;i>0;i--)for(j=116;j>0;j --)for(k=214;k>0;k --);}关于单片机C语言的精确延时,网上很多都是大约给出延时值没有准确那值是多少,也就没有达到精确高的要求,而本函数克服了以上缺点,能够精确计数出要延时值且精确达到1us,本举例所用CPU为STC12C5412系列12倍速的单片机,只要修改一下参数值其它系例单片机也通用,适用范围宽。
51单片机延迟函数

51单片机延迟函数51单片机延迟函数是一种非常重要的函数,它可以帮助我们在程序中实现延迟的效果。
在很多应用场景中,我们需要让程序暂停一段时间,比如等待传感器采集数据、等待外设响应等等。
这时候,延迟函数就可以派上用场了。
在51单片机中,延迟函数的实现方式有很多种,比如使用定时器、循环计数等等。
其中,使用循环计数实现延迟函数是最简单、最常用的方法。
具体实现方式如下:```cvoid delay(unsigned int ms){unsigned int i, j;for (i = 0; i < ms; i++){for (j = 0; j < 1141; j++);}}```这个函数的原理很简单,就是通过两个嵌套的循环来实现延迟。
外层循环控制延迟的时间,内层循环则是一个空循环,用来消耗CPU 的时间。
通过调整内层循环的次数,就可以控制延迟的时间。
需要注意的是,这种延迟函数的精度并不高,因为它的延迟时间受到CPU时钟频率的影响。
如果CPU时钟频率发生变化,延迟时间也会发生变化。
因此,在实际应用中,我们需要根据具体的情况来选择合适的延迟函数。
除了使用循环计数实现延迟函数外,还可以使用定时器来实现。
定时器可以精确地控制延迟时间,而且不会受到CPU时钟频率的影响。
但是,定时器的使用比较复杂,需要对定时器的寄存器进行配置,不太适合初学者使用。
51单片机延迟函数是一种非常实用的函数,可以帮助我们在程序中实现延迟的效果。
在实际应用中,我们需要根据具体的情况来选择合适的延迟函数,以达到最佳的延迟效果。
51单片机延时函数

C程序中可使用不同类型的变量来进行延时设计。
经实验测试,使用unsigned char类型具有比unsigned int更优化的代码,在使用时应该使用unsigned char作为延时变量。
以某晶振为12MHz 的单片机为例,晶振为12MHz即一个机器周期为1us。
一. 500ms延时子程序程序:void delay500ms(void){unsigned char i,j,k;for(i=15;i>0;i--)for(j=202;j>0;j--)for(k=81;k>0;k--);}计算分析:程序共有三层循环一层循环n:R5*2 = 81*2 = 162us DJNZ 2us二层循环m:R6*(n+3) = 202*165 = 33330us DJNZ2us + R5赋值 1us = 3us三层循环: R7*(m+3) = 15*33333 = 499995us DJNZ 2us + R6赋值1us = 3us循环外: 5us子程序调用2us + 子程序返回 2us + R7赋值 1us = 5us延时总时间= 三层循环+ 循环外= 499995+5 = 500000us =500ms计算公式:延时时间=[(2*R5+3)*R6+3]*R7+5二. 200ms延时子程序程序:void delay200ms(void){unsigned char i,j,k;for(i=5;i>0;i--)for(j=132;j>0; j--)for(k=150;k>0; k--);}三. 10ms延时子程序程序:void delay10ms(void){unsigned char i,j,k;for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=248;k>0; k--);}四. 1s延时子程序程序:void delay1s(void){unsigned char h,i,j,k;for(h=5;h>0;h--)for(i=4;i>0;i--)for(j=116;j>0; j--)for(k=214;k>0; k--);}关于单片机C语言的精确延时,网上很多都是大约给出延时值没有准确那值是多少,也就没有达到精确高的要求,而本函数克服了以上缺点,能够精确计数出要延时值且精确达到1us,本举例所用CPU为STC12C5412系列12倍速的单片机,只要修改一下参数值其它系例单片机也通用,适用范围宽。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
标准的C语言中没有空语句。
但在单片机的C语言编程中,经常需要用几个空指令产生短延时的效果。
这在汇编语言中很容易实现,写几个nop就行了。
在keil C51中,直接调用库函数:
#include<intrins.h> // 声明了void _nop_(void);
_nop_(); // 产生一条NOP指令
作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
NOP指令为单周期指令,可由晶振频率算出延时时间,对于12M晶振,延时1uS。
对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。
在选择C51中循环语句时,要注意以下几个问题
第一、定义的C51中循环变量,尽量采用无符号字符型变量。
第二、在FOR循环语句中,尽量采用变量减减来做循环。
第三、在do…while,while语句中,循环体内变量也采用减减方法。
这因为在C51编译器中,对不同的循环方法,采用不同的指令来完成的。
下面举例说明:
unsigned char i;
for(i=0;i<255;i++);
unsigned char i;
for(i=255;i>0;i--);
其中,第二个循环语句C51编译后,就用DJNZ指令来完成,相当于如下指令:MOV 09H,#0FFH
LOOP: DJNZ 09H,LOOP
指令相当简洁,也很好计算精确的延时时间。
同样对do…while,while循环语句中,也是如此
例:
unsigned char n;
n=255;
do{n--}
while(n);
或
n=255;
while(n)
{n--};
这两个循环语句经过C51编译之后,形成DJNZ来完成的方法,
故其精确时间的计算也很方便。
其三:对于要求精确延时时间更长,这时就要采用循环嵌套的方法来实现,因此,循环嵌套的方法常用于达到ms级的延时。
对于循环语句同样可以采用for,do…while,while结构来完成,每个循环体内的变量仍然采用无符号字符变量。
unsigned char i,j
for(i=255;i>0;i--)
for(j=255;j>0;j--);
或
unsigned char i,j
i=255;
do{j=255;
do{j--}
while(j);
i--;
}
while(i);
或
unsigned char i,j
i=255;
while(i)
{j=255;
while(j)
{j--};
i--;
}
这三种方法都是用DJNZ指令嵌套实现循环的,由C51编译器用下面的指令组合来完成的
MOV R7,#0FFH
LOOP2: MOV R6,#0FFH
LOOP1: DJNZ R6,LOOP1
DJNZ R7,LOOP2
这些指令的组合在汇编语言中采用DJNZ指令来做延时用,因此它的时间精确计算也是很简单,假上面变量i的初值为m,变量j的初值为n,则总延时时间为:m×(n×T+T),其中T为DJNZ指令执行时间(DJNZ指令为双周期指令)。
这里的+T为MOV这条指令所使用的时间。
同样对于更长时间的延时,可以采用多重循环来完成。
只要在程序设计循环语句时注意以上几个问题。
下面给出有关在C51中延时子程序设计时要注意的问题
1、在C51中进行精确的延时子程序设计时,尽量不要或少在延时子程序中定义局部变量,所有的延时子程序中变量通过有参函数传递。
2、在延时子程序设计时,采用do…while,结构做循环体要比for结构做循环体好。
3、在延时子程序设计时,要进行循环体嵌套时,采用先内循环,再减减比先减减,再内循环要好。
unsigned char delay(unsigned char i,unsigned char j,unsigned char k) {unsigned char b,c;
b="j";
c="k";
do{
do{
do{k--};
while(k);
k="c";
j--;};
while(j);
j=b;
i--;};
while(i);
}
这精确延时子程序就被C51编译为有下面的指令组合完成
delay延时子程序如下:
MOV R6,05H
MOV R4,03H
C0012: DJNZ R3, C0012
MOV R3,04H
DJNZ R5, C0012
MOV R5,06H
DJNZ R7, C0012
RET
假设参数变量i的初值为m,参数变量j的初值为n,参数变量k的初值为l,则总延时时间为:l×(n×(m×T+2T)+2T)+3T,其中T为DJNZ和MOV指令执行的时间。
当m=n=l时,精确延时为9T,最短;当m=n=l=256时,精确延时到16908803T,最长。