c语言中的精确延时程序举例
C语言里如何编写精确的微量延时
C 语言里如何编写精确的微量延时
众所周知,相比于其他编程语言,C 语言在编写嵌入式编程中有着绝对的优势。
但它总也有缺点的:它的时序性比较差,不容易编写精准的延时。
而在编写嵌入系统驱动程序时,常常需要比较精确的软件延时,这使得C 语言的劣势暴露了出来,一般都只能通过嵌入汇编的方式实现。
例如,在1MHZ 工作频率下需要延时10us,就需要嵌入10 句空操作指令,显然在书写上比较难堪。
本文提出一种简化书写的延时方案,使用带参数的宏构来造微小时间片,可以实现完全精确的软件延时,大大方便了驱动程序及软件模拟通信协议的编写。
说明:以下皆为ICC AVR 平台下的讨论,对AVR 系列所有型号的单片机皆有效。
至于其他平台,可据此方案自行修改和移值。
该方案的实现方法其实很简单:
首先定义N 个宏,分别调用1 ~ N 个汇编空操作指令,如:
#define NOP_1 asm(nop)//延时一个时钟周期。
C语言延时程序
C51精确延时程序一、、看了网上延时程序的帖子挺多,我也说点。
用keil调试,void yanshi( uint n ){uchar data i="0";for(i=0;i<N;I++);return;}延时时间=12*(n*12+17)/fosc用keil测时功能很容易得到这个关系,很精确,偏差不过几us.可以自己编一些延时程序,也可以很方便的得到关系式,只是系数不同.二、、//我看到的地方也是从别的地方转贴,所以我不知道原作者是谁,但相信这么成熟的东西转一下他也不会见意。
看到了个好帖,我在此在它得基础上再抛抛砖!有个好帖,从精度考虑,它得研究结果是:void delay2(unsigned char i){while(--i);}为最佳方法。
分析:假设外挂12M(之后都是在这基础上讨论)我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay2(0):延时518us 518-2*256=6delay2(1):延时7us(原帖写“5us”是错的,^_^)delay2(10):延时25us 25-20=5delay2(20):延时45us 45-40=5delay2(100):延时205us 205-200=5delay2(200):延时405us 405-400=5见上可得可调度为2us,而最大误差为6us。
精度是很高了!但这个程序的最大延时是为518us 显然不能满足实际需要,因为很多时候需要延迟比较长的时间。
那么,接下来讨论将t分配为两个字节,即uint型的时候,会出现什么情况。
void delay8(uint t){while(--t);}我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay8(0):延时524551us 524551-8*65536=263delay8(1):延时15usdelay8(10):延时85us 85-80=5delay8(100):延时806us 806-800=6delay8(1000):延时8009us 8009-8000=9delay8(10000):延时80045us 80045-8000=45delay8(65535):延时524542us 524542-524280=262如果把这个程序的可调度看为8us,那么最大误差为263us,但这个延时程序还是不能满足要求的,因为延时最大为524.551ms。
STC12系列单片机C语言的延时程序
STC12系列单片机C语言的延时程序本举例所用CPU 为STC12C5412 系列12 倍速的单片机,只要修改一下参数值其它系例单片机也通用,适用范围宽。
共有三条延时函数说明如下:函数调用分两级:一级是小于10US 的延时,二级是大于10US 的延时//====================小于10US 的【用1US 级延时】====================//----------微秒级延时---------for(i=X;i>X;i--) 延时时间=(3+5*X)/12 提示(单位us, X 不能大于255)//================大于10US0;Ms--)for(i=26;i>0;i--);}i=[(延时值-1.75)*12/Ms-15]/4 如想延时60US 则i=[(60-1.75)*12/6-15]/4=25.375≈26; 修改i 的值=26,再调用上面的【10US 级延时函数】Delay10us(6); 则就精确延时60US;如果想延时64US 可以用这二种函数组合来用: Delay10us(6); for(i=9;i>X;i--) 共延时64US//============== 对于大于20Ms 的可用中断来实现程序运行比较好===============中断用定时器0, 1Ms 中断:void timer0(void) interrupt 1{ TL0=(0xffff-1000+2)% 0x100;TH0=(0xffff-1000+2)/0x100; //每毫秒执行一次if(DelayMs_1>0) DelayMs_1--;//大于20Ms 延时程序}函数调用void DelayMs(uint a)//延时 a 乘以1(ms)的时间。
{ DelayMs_1=a; while(DelayMs_1);}如果延时50Ms 则函数值为DelayMs(50)tips:感谢大家的阅读,本文由我司收集整编。
C及汇编延时程序讲解
有个好帖,从精度考虑,它得研究结果是:void delay2(unsigned char i){while(--i);}为最佳方法。
分析:假设外挂12M(之后都是在这基础上讨论)我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay2(0):延时518us 518-2*256=6delay2(1):延时7us(原帖写“5us”是错的,^_^)delay2(10):延时25us 25-20=5delay2(20):延时45us 45-40=5delay2(100):延时205us 205-200=5delay2(200):延时405us 405-400=5见上可得可调度为2us,而最大误差为6us。
精度是很高了!但这个程序的最大延时是为518us 显然不能满足实际需要,因为很多时候需要延迟比较长的时间。
那么,接下来讨论将t分配为两个字节,即uint型的时候,会出现什么情况。
void delay8(uint t){while(--t);}我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay8(0):延时524551us 524551-8*65536=263delay8(1):延时15usdelay8(10):延时85us 85-80=5delay8(100):延时806us 806-800=6delay8(1000):延时8009us 8009-8000=9delay8(10000):延时80045us 80045-8000=45delay8(65535):延时524542us 524542-524280=262如果把这个程序的可调度看为8us,那么最大误差为263us,但这个延时程序还是不能满足要求的,因为延时最大为524.551ms。
那么用ulong t呢?一定很恐怖,不用看编译后的汇编代码了。
那么如何得到比较小的可调度,可调范围大,并占用比较少得RAM呢?请看下面的程序:/*--------------------------------------------------------------------程序名称:50us 延时注意事项:基于1MIPS,AT89系列对应12M晶振,W77、W78系列对应3M晶振例子提示:调用delay_50us(20),得到1ms延时全局变量:无返回:无--------------------------------------------------------------------*/void delay_50us(uint t){uchar j;for(;t>0;t--)for(j=19;j>0;j--);}我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay_50us(1):延时63us 63-50=13delay_50us(10):延时513us 503-500=13delay_50us(100):延时5013us 5013-5000=13delay_50us(1000):延时50022us 50022-50000=22赫赫,延时50ms,误差仅仅22us,作为C语言已经是可以接受了。
FOR循环实现C语言精确延时
for实现C语言精确延时C语言最大的缺点就是实时性差,我在网上到看了一些关于延时的讨论,其中有篇文章51单片机Keil C延时程序的简单研究,写得不错,他是用while(--i);产生DJNZ来实现精确延时,后来有人说如果while里面不能放其它语句,否则也不行,用do-while就可以,具体怎样我没有去试.所有这些都没有给出具体的实例程序来.还看到一些延时的例子多多少少总有点延时差.为此我用for循环写了几个延时的子程序贴上来,希望能对初学者有所帮助.(晶振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--);}产生的汇编:C:0x08007F0F MOV R7,#0x0FC:0x08027ECA MOV R6,#0xCAC:0x08047D51MOV R5,#0x51C:0x0806DDFE DJNZ R5,C:0806C:0x0808DEFA DJNZ R6,C:0804C:0x080A DFF6DJNZ R7,C:0802C:0x080C22RET计算分析:程序共有三层循环一层循环n:R5*2=81*2= 162us DJNZ2us二层循环m:R6*(n+3)=202*165= 33330us DJNZ2us+R5赋值1us=3us三层循环:R7*(m+3)=15*33333= 499995us DJNZ2us+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--);}产生的汇编C:0x08007F05MOV R7,#0x05C:0x08027E84MOV R6,#0x84C:0x08047D96MOV R5,#0x96C:0x0806DDFE DJNZ R5,C:0806C:0x0808DEFA DJNZ R6,C:0804C:0x080A DFF6DJNZ R7,C:0802C:0x080C22RET三.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--);}产生的汇编C:0x08007F05MOV R7,#0x05C:0x08027E04MOV R6,#0x04C:0x08047DF8MOV R5,#0xF8C:0x0806DDFE DJNZ R5,C:0806C:0x0808DEFA DJNZ R6,C:0804C:0x080A DFF6DJNZ R7,C:0802C:0x080C22RET四.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:0x08007F05MOV R7,#0x05C:0x08027E04MOV R6,#0x04C:0x08047D74MOV R5,#0x74C:0x08067CD6MOV R4,#0xD6C:0x0808DCFE DJNZ R4,C:0808C:0x080A DDFA DJNZ R5,C:0806C:0x080C DEF6DJNZ R6,C:0804C:0x080E DFF2DJNZ R7,C:0802C:0x081022RET在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.。
Keil C51精确延时程序(C语言)
Keil C51精确延时程序程序说明如下:振荡频率:12MHz机器周期=12/振荡频率=12/12000000=1us#include <reg52.h>void delay1(unsigned char i){ while(--i);}说明:delay1程序为:延时时间=(2*i+2)*机器周期。
i=1~255。
void delay2(unsigned char i){ while(i--);}说明:delay2程序为:延时时间=(6*i+2)*机器周期。
i=1~255。
void main (void){unsigned char m;delay1(10); //赋值并调延时程序delay1说明:本句为赋值并调用Delayus1:延时时间=(1+2)*机器周期。
全部延时时间为:延时时间=(1+2+2*i+2)*机器周期。
i=1~255。
本例:延时时间=(1+2+2*10+2)*1us=25usdelay2(10); //赋值并调延时程序delay2说明:本句为赋值并调用Delayus2:延时时间=(1+2)*机器周期。
全部延时时间为:延时时间=(1+2+6*i+2)*机器周期。
i=1~255。
本例:延时时间=(1+2+6*10+2)*1us=65usm=10; //赋值,m=1~255while(--m) ; //计算,延时时间=2*m*机器周期说明:本两句为赋值并计算。
全部延时时间为:延时时间=(1+2*m)*机器周期。
m=1~255。
本例:延时时间=(1+2*10)*1us=25uswhile(1);}。
C51中精确的延时与计算的实现
C51中精确的延时与计算的实现C51由于其可读性和可移植性很强,在单片机中得到广泛的应用,但在某些时候由于C51编写的程序对在有精确时间要求下,可能就得要用汇编语言来编写,但在C51是否也能实现时间的精确控制呢?答案是肯定的。
在C51中要实现对时间的精确延时有以下几种方法其一:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒,就插入几个这样的函数。
其二:对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。
在选择C51中循环语句时,要注意以下几个问题第一、定义的C51中循环变量,尽量采用无符号字符型变量。
第二、在FOR循环语句中,尽量采用变量减减来做循环。
第三、在do…while,while语句中,循环体内变量也采用减减方法。
这因为在C51编译器中,对不同的循环方法,采用不同的指令来完成的。
下面举例说明:unsigned char I;for(i=0;i255;i++);unsigned char I;for(i=255;i0;i--);其中,第二个循环语句C51编译后,就用DJNZ指令来完成,相当于如下指令:MOV 09H,#0FFHLOOP: 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,jfor(i=255;i0;i--)for(j=255;j0;j--);或unsigned char i,ji=255;do{j=255;do{j--}while(j);i--;}while(i);或unsigned char i,ji=255;while(i){j=255;while(j){j--};i--;}这三种方法都是用DJNZ指令嵌套实现循环的,由C51编译器用下面的指令组合来完成的MOV R7,#0FFHLOOP2: MOV R6,#0FFHLOOP1: DJNZ R6,LOOP1DJNZ R7,LOOP2这些指令的组合在汇编语言中采用DJNZ指令来做延时用,因此它的时间精确计算也是很简单,假上面变量i的初值为m,变量j的初值为n,则总延时时间为:m×(n×T+T),其中T为DJNZ指令执行时间。
C语言精确微秒级的延时
65535-(UБайду номын сангаасNT)(SYSCLK/1000000) * (UINT)(time_us) 定 时 器 需 要 TM_LODAE 指令周期才会溢出。该单片机的一个指令周期就是一个时 钟周期
TMR2H = TM_LODAE>>8; TMR2L = TM_LODAE&0x00FF;置定时器寄存器 的初值
TR2 = 1; 启动单片机计时
while (!TF2H); 等待定时器 2 寄存器溢出
TR2 = 0;停止计时
//-----------------------------------------------------------------------------
void Delay_us (unsigned char time_us)
{ unsigned long int TM_LODAE; TR2 = 0; // Stop timer TF2H = 0; // Clear timer overflow flag TM_LODAE = 65535-(UINT)(SYSCLK/1000000) * (UINT)(time_us); // TMR2 = -( (UINT)(SYSCLK/1000000) * (UINT)(time_us) ); TMR2H = TM_LODAE>>8; TMR2L = TM_LODAE&0x00FF; TR2 = 1; // Start timer while (!TF2H); // Wait till timer overflow occurs TR2 = 0; // Stop timer
C 语言精确微秒级的延时
在使用 C 语言编程时延时程序是非常常见的,但是实现一个精确 的延时是不太容易的,在给一个朋友的公司产品做维护时,发现一段 代码,可以实现微妙级的延时。看起来代码非常简单。但是我以前没 有想到过。我们一起来看看这段代码。
C及汇编延时程序讲解
有个好帖,从精度考虑,它得研究结果是:void delay2(unsigned char i){while(--i);}为最佳方法。
分析:假设外挂12M(之后都是在这基础上讨论)我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay2(0):延时518us 518-2*256=6delay2(1):延时7us(原帖写“5us”是错的,^_^)delay2(10):延时25us 25-20=5delay2(20):延时45us 45-40=5delay2(100):延时205us 205-200=5delay2(200):延时405us 405-400=5见上可得可调度为2us,而最大误差为6us。
精度是很高了!但这个程序的最大延时是为518us 显然不能满足实际需要,因为很多时候需要延迟比较长的时间。
那么,接下来讨论将t分配为两个字节,即uint型的时候,会出现什么情况。
void delay8(uint t){while(--t);}我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay8(0):延时524551us 524551-8*65536=263delay8(1):延时15usdelay8(10):延时85us 85-80=5delay8(100):延时806us 806-800=6delay8(1000):延时8009us 8009-8000=9delay8(10000):延时80045us 80045-8000=45delay8(65535):延时524542us 524542-524280=262如果把这个程序的可调度看为8us,那么最大误差为263us,但这个延时程序还是不能满足要求的,因为延时最大为524.551ms。
那么用ulong t呢?一定很恐怖,不用看编译后的汇编代码了。
那么如何得到比较小的可调度,可调范围大,并占用比较少得RAM呢?请看下面的程序:/*--------------------------------------------------------------------程序名称:50us 延时注意事项:基于1MIPS,AT89系列对应12M晶振,W77、W78系列对应3M晶振例子提示:调用delay_50us(20),得到1ms延时全局变量:无返回:无--------------------------------------------------------------------*/void delay_50us(uint t){uchar j;for(;t>0;t--)for(j=19;j>0;j--);}我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:delay_50us(1):延时63us 63-50=13delay_50us(10):延时513us 503-500=13delay_50us(100):延时5013us 5013-5000=13delay_50us(1000):延时50022us 50022-50000=22赫赫,延时50ms,误差仅仅22us,作为C语言已经是可以接受了。
C语言延时子程序准确设置
C语言延时子程序准确设置
在给单片机写程序的时候往往需要一个微秒或者毫秒的延时子程序,但是C语言不同于汇编,很难根据语句确定准确的延时时间,经过各种查资料得到一种简单实用的方法:通过keil下断点调试确定时间。
就是编写一个延时子程序,然后在延时程序处和while(1)设置断点,运行程序,在调试模式下就可以获得该延时子程序的准确延时时间。
1,编写如下源程序:
#include
void delay_ms(unsigned intms)
{
unsigned int i;
unsigned char j;
for(i=0;i
{
for(j=0;j<200;j++);
for(j=0;j<102;j++);
}
}
void main (void)
{
delay_ms(1);
while(1);
}
2,下图位置设置断点
3,进入运行模式,开始运行(1处所示),程序会在延时子程序前的断点处停下,此时记录程序运行时间,2处所示。
4,再次点运行(1处所示),此时程序会在第二个断点处,也就是while(1)停下,这时候程序刚刚运行完延时子程序,读取此时的程序运行时间,如2所示,,二者想减就是延时子程序运行时间。
如下图:
0.00143989-0.00042209=0.0010178,约等于1mS,ok,这样就得到你所写的延时子程序的延时时间,准确的哦,可以在你得到的运行时间的基础上更改数值来得到希望的延时时间。
当然记得设置晶振为你所需要的,我这里是11.0592。
c语言延时程序的计算方法经典
for(k=81;k>0;k--);
}
下面是用了8.0000MHZ的晶振的几个延时程序(用定时0的工作模式1):
(1)延时0.9MS
void delay_0_9ms(void)
{
TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/
TH0=0xfd;
Loop2: djnz r6, loop2; djnz双周期指令
Djnz r7, loop1,
延时时间=T+i*T+i*j*2T+i*2T
下面几个是单片机的延时程序(包括asm和C程序,都是我在学单片机的过程中用到的),在单片机延时程序中应考虑所使用的晶振的频率,在51系列的单片机中我们常用的是11.0592MHz和12.0000MHz的晶振,而在AVR单片机上常用的有8.000MHz和4.000MH的晶振所以在网上查找程序时如果涉及到精确延时则应该注意晶振的频率是多大。
{
unsigned char i,j,k;
for(i=5;i>0;i--)
for(j=132;j>0;j--)
for(k=150;k>0;k--);
}
500ms延时子程序程序:(12MHZ)
void delay500ms(void)
{
unsigned char i,j,k;
for(i=15;i>0;i--)
DJNZ R7,HERE
CLR TR0 ;定时器要软件清零
SETB EX0
RET
C语言延时程序:
10ms延时子程序(12MHZ)
void delay10ms(void)
{
单片机C语言的精确延时程序设计
PUBLIC _delay3
RSEG ?PR?_delay3?DLY
_delay3:
DJNZ R7, ¥ 4 s
RET
4s
END
嵌入汇编的方法如下
void delay4(unsigned char vd)
{ #pragma asm
DJNZ R7, ¥
#pragma endasm
}
编译后的形式
汇编时代常用的延时指令为
MOV R7 DDLY
DJNZ R7 ¥
产生最小 4 s 的延时 仿造的 C 程序如下
void delay1(ndly)
{for( ndly>0 ndly--)
}
生成的汇编代码与 D J N Z 无关 是如下形式的 其
中无关的编译注释已删除
RSEG ?PR?_delay1?DLY2
法 在生成目标代码时 会有所不同 开发人员必须研 究它生成的汇编语言代码 来保证时间的准确性 这也 许是除了使用嵌入汇编或直接编写汇编函数的唯一方 法 其实在单片机的 C 编译器中 已经有足够底层操作 方面的扩展 所以这里只考虑纯 C 语言的方法
3 延时程序设计
以德国 Keil 公司的 C 5 1 编译器为例 目前它已被公 认为业界的标准 以下讨论均假设 5 1 单片机时钟晶振 为 6 M H z 以小模式下编译 这时程序指令执行的最小 单位是 2 s 如果使用非英特尔且内核优化过的单片 机 应切换回普通模式 或仔细研究它的时序 以 D S 1 8 B 2 0 为例 临时在程序中需要延时 2 s 那么可以 用下述程序
以上代码调用一次也有 14 s 之多 还是无法使用
也就是说 采用 f o r 形式的语句 生成的汇编代码都是
C语言精确延时子程序
C语言精确延时子程序C语言精确延时子程序晶振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--);}产生的汇编:C:0x0800 7F0F MOV R7,#0x0FC:0x0802 7ECA MOV R6,#0xCAC:0x0804 7D51 MOV R5,#0x51C:0x0806 DDFE DJNZ R5,C:0806C:0x0808 DEFA DJNZ R6,C:0804C:0x080A DFF6 DJNZ R7,C:0802C:0x080C 22 RET计算分析:程序共有三层循环一层循环n:R5*2 = 81*2 = 162us DJNZ 2us二层循环m:R6*(n+3) = 202*165 = 33330us DJNZ 2us + 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--);}产生的汇编C:0x0800 7F05 MOV R7,#0x05 C:0x0802 7E84 MOV R6,#0x84 C:0x0804 7D96 MOV R5,#0x96 C:0x0806 DDFE DJNZ R5,C:0806 C:0x0808 DEFA DJNZ R6,C:0804C:0x080C 22 RET三. 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--);}产生的汇编C:0x0800 7F05 MOV R7,#0x05 C:0x0802 7E04 MOV R6,#0x04 C:0x0804 7DF8 MOV R5,#0xF8C:0x0808 DEFA DJNZ R6,C:0804 C:0x080A DFF6 DJNZ R7,C:0802 C:0x080C 22 RET四. 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:0x0800 7F05 MOV R7,#0x05C:0x0802 7E04 MOV R6,#0x04C:0x0804 7D74 MOV R5,#0x74C:0x0806 7CD6 MOV R4,#0xD6C:0x0808 DCFE DJNZ R4,C:0808C:0x080A DDFA DJNZ R5,C:0806C:0x080C DEF6 DJNZ R6,C:0804C:0x080E DFF2 DJNZ R7,C:0802C:0x0810 22 RET在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.五. 1ms延时子程序程序:void delay1ms(void)unsigned char i,j,k; for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=23;k>0;k--); }六. 4ms延时子程序程序:void delay1ms(void) {unsigned char i,j,k; for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=98;k>0;k--); }七. 8ms延时子程序程序:void delay1ms(void) {unsigned char i,j,k; for(i=5;i>0;i--)for(j=4;j>0;j--)for(k=198;k>0;k--); }八. 20ms延时子程序程序:void delay1ms(void) {unsigned char i,j,k;for(i=5;i>0;i--)for(j=12;j>0;j--) for(k=165;k>0;k--); }。
c语言延时语句
c语言延时语句第一篇:c语言延时语句C语言程序延时Keil C51的编程语言常用的有2种:一种是汇编语言;另一种是C 语言。
用汇编语言写单片机程序时,精确时间延时是相对容易解决的。
比如,用的是晶振频率为12 MHz的AT 89C51,打算延时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程序中可使用不同类型的变量来进行延时设计。
经实验测试,使用unsigned char类型具有比unsigned int更优化的代码,在使用时应该使用unsigned char作为延时变量。
有人说如果while里面不能放其它语句,否则也不行,用do-while 就可以,具体怎样我没有去试.所有这些都没有给出具体的实例程序来.还看到一些延时的例子多多少少总有点延时差.为此我用for循环写了几个延时的子程序贴上来,希望能对初学者有所帮助.(晶振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 DJNZ 赋值 1us = 3us2us + R5 三层循环: 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语言常用语句1、putchar函数:putchar函数(字符输出函数)的作用是向终端输出一个字符。
c语言的延时函数
c语言的延时函数c语言中的延时函数是一种非常常用的编程方法,主要用于控制程序在某些场景下的运行速度。
在很多情况下,我们需要让程序暂停执行一段时间,以等待外部条件满足或等待其他设备的响应等等。
而这个时候,延时函数就非常有用了。
在c语言中,延时函数的实现主要是通过循环来完成的。
我们可以通过循环执行一些无用的操作,从而达到控制程序执行时间的目的。
下面我们来看一个简单的例子,实现一个延时函数:```cvoid Delay(unsigned int ms){unsigned int i, j;for(i = 0; i < ms; i++)for(j = 0; j < 1000; j++);}```上面的代码实现了一个简单的延时函数,它的参数是一个unsigned int类型的变量ms,表示需要延时的时间(以毫秒为单位)。
函数内部通过两层循环来控制程序的执行时间,循环次数为ms * 1000次。
这个函数看起来非常简单,但它确实非常实用。
不过需要注意的是,延时函数有时候也会带来一些问题。
首先,延时函数会占用CPU的执行时间。
在延时函数执行的过程中,CPU会一直处于忙碌状态,这会导致其他任务无法被及时执行。
如果延时时间过长,会影响系统的整体性能。
其次,延时函数的精度有时也不是很高。
在实际使用中,延时函数的执行时间并不是完全准确的,因为CPU的工作状态有很多不确定性因素,比如操作系统的调度、硬件设备的中断等等。
因此,我们在使用延时函数时,需要注意这点。
除了上面的问题以外,延时函数还有一些其他方面的注意事项。
比如,延时时间过短或过长都会导致系统出现异常。
因此,在使用延时函数时,我们需要事先了解系统的性能特点,并根据实际情况来选择适当的延时时间。
另外,延时函数也不是在所有的程序中都适用的。
在一些实时性要求较高的系统中,通常不能使用延时函数,因为这会影响系统的时序要求。
在这种情况下,我们通常需要使用硬件定时器或者其他更加高级的调度方式来控制程序的执行。
C语言精确延时方法
C语言精确延时方法有些特殊的应用会用到比较精确的延时(比如DS18B20等),而C不像汇编,延时精准度不好算。
本人经过反复调试,对照KEIL编译后的汇编源文件,得出了以下几条精确延时的语句(绝对精确!本人已通过实际测试),今天贴上来,希望对需要的朋友有所帮助。
sbit LED = P1^0; // 定义一个管脚(延时测试用)unsigned int i = 3; // 注意i,j的数据类型,unsigned char j = 3; // 不同的数据类型延时有很大不同//-----------------各种精确延时语句-----------------------------------while( (i--)!=1 ); // 延时10*i个机器周期i = 10; while( --i ); // 延时8*i+2个机器周期i = 10; while( i-- ); // 延时(i+1)*9+2个机器周期j = 5; while( --j ); // 延时2*j+1个机器周期j = 5; while( j-- ); // 延时(j+1)*6+1个机器周期i = 5;while( --i ) // 延时i*10+2个机器周期,在i*10+2个机器周期if( LED==0 ) break; // 内检测到LED管脚为低电平时跳出延时i = 5;while( LED ) // 每隔10个机器周期检测一次LED管脚状态,当LEDif( (--i)==0 ) break;// 为低时或者到了10*i+2个机器周期时跳出延时//--------------------------------------------------------------------例如18b20的复位函数(12M晶振)://************************************************************* **********// 函数功能:18B20复位// 入口参数:无// 出口参数:unsigned char x: 0:成功 1:失败//************************************************************* **********unsigned char ow_reset(void){unsigned char x=0; // 12M晶振 1个机器周期为1usDQ = 1; // DQ复位j = 10; while(--j);// 稍做延时(延时10*2+1=21个机器周期,21us)DQ = 0; // 单片机将DQ拉低j = 85; while(j--);// 精确延时(大于480us) 85*6+1=511usDQ = 1; // 拉高总线j = 10; while(j--);// 精确延时10*6+1=61usx = DQ; // 稍做延时后,return x; // 如果x=0则初始化成功 x=1则初始化失败j = 25; while(j--);// 精确延时25*6+1=151us}//************************************************************* ********************再如红外解码程序:(先说传统红外解码的弊端:程序中用了while(IR_IO);while(!IR_IO);这样的死循环,如果管脚一直处于一种状态,就会一直执行while,造成“死机”现象。
关于单片机C语言的精确延时
for(i = 0; i < 600; i++); } } /********************************************************************************************
/******************************************************************************************** void main (void){ //主程序 while(1){
LED = ~LED; //取LED相反状态 DELAY_MS(1000); //修改这里的数值看看会有什么变化 }
} /******************************************************************************************** - 应用实例
可将其模板下载到本地硬盘,在编写新程序的时候复制、粘贴到工程当 中,然后根据情况写入具体内容。
- 使用说明
data unsigned char cou = 0; // 定义软计数器,放在程序最前面的寄存 器定义部分
/********************************************************************************************
c语言 延时函数
c语言延时函数一、概述延时函数在程序设计中是非常常用的一种函数,它可以让程序在执行到该函数时暂停一定时间,以达到控制程序执行速度的目的。
C语言中提供了多种实现方式,本文将详细介绍其中两种:使用系统提供的函数和自己编写实现。
二、使用系统提供的函数1. sleep函数sleep函数是C语言标准库中提供的一个延时函数,其原型如下:```unsigned int sleep(unsigned int seconds);```该函数接受一个参数seconds,表示要延时的秒数。
在调用该函数后,程序会暂停seconds秒钟,然后继续执行下一条语句。
注意:sleep函数只能精确到秒级别,并且在暂停期间程序会进入睡眠状态,无法响应其他事件。
2. usleep函数usleep函数也是C语言标准库中提供的一个延时函数,其原型如下:```int usleep(useconds_t usec);```该函数接受一个参数usec,表示要延时的微秒数。
在调用该函数后,程序会暂停usec微秒,然后继续执行下一条语句。
注意:usleep函数可以精确到微秒级别,并且在暂停期间程序不会进入睡眠状态。
三、自己编写实现1. 使用循环实现延时使用循环实现延时的原理是在一个循环中不停地执行空语句,以达到占用CPU时间的目的。
具体实现代码如下:```void delay(unsigned int ms){unsigned int i, j;for(i = 0; i < ms; i++)for(j = 0; j < 110; j++);}```该函数接受一个参数ms,表示要延时的毫秒数。
在调用该函数后,程序会占用CPU时间ms毫秒,然后继续执行下一条语句。
注意:使用循环实现延时会占用大量CPU时间,可能会影响其他进程的运行。
2. 使用系统调用实现延时使用系统调用实现延时的原理是通过操作系统提供的定时器功能来实现。
具体实现代码如下:```#include <sys/time.h>void delay(unsigned int ms){struct timeval tv;_sec = ms / 1000;_usec = (ms % 1000) * 1000;select(0, NULL, NULL, NULL, &tv);}```该函数接受一个参数ms,表示要延时的毫秒数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
c语言中的精确延时程序举例
我在网上到看了一些关于延时的讨论,其中有篇文章51单片机Keil C 延时程序的简单研究,作者:InfiniteSpace Studio/isjfk 写得不错,他是用while(--i);产生DJNZ 来实现精确延时,后来有人说如果while里面不能放其它语句,否则也不行,用do-while就可以,具体怎样我没有去试.所有这些都没有给出具体的实例程序来.还看到一些延时的例子多多少少总有点
延时差.为此我用for循环写了几个延时的子程序贴上来,希望能对初学者有所帮助.(晶振12 MHz,一个机器周期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--); }
产生的汇编: C:0x0800 7F0F MOV R7,#0x0F
C:0x0802 7ECA MOV R6,#0xCA
C:0x0804 7D51 MOV R5,#0x51
C:0x0806 DDFE DJNZ R5,C:0806
C:0x0808 DEFA DJNZ R6,C:0804
C:0x080A DFF6 DJNZ R7,C:0802 C:0x080C 22 RET
计算分析: 程序共有三层循环一层循环n:R5*2 = 81*2 = 162us DJNZ 2us 二层循环m: R6*(n+3) = 202*165 = 33330us DJNZ 2us + 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--); }
产生的汇编
C:0x0802 7E84 MOV R6,#0x84
C:0x0804 7D96 MOV R5,#0x96
C:0x0806 DDFE DJNZ R5,C:0806
C:0x0808 DEFA DJNZ R6,C:0804
C:0x080A DFF6 DJNZ R7,C:0802
C:0x080C 22 RET
三. 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--); }
产生的汇编C:0x0800 7F05 MOV R7,#0x05 C:0x0802 7E04 MOV R6,#0x04
C:0x0804 7DF8 MOV R5,#0xF8
C:0x0806 DDFE DJNZ R5,C:0806
C:0x0808 DEFA DJNZ R6,C:0804
C:0x080A DFF6 DJNZ R7,C:0802
C:0x080C 22 RET
四. 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:0x0802 7E04 MOV R6,#0x04
C:0x0804 7D74 MOV R5,#0x74
C:0x0806 7CD6 MOV R4,#0xD6
C:0x0808 DCFE DJNZ R4,C:0808
C:0x080A DDFA DJNZ R5,C:0806
C:0x080C DEF6 DJNZ R6,C:0804
C:0x080E DFF2 DJNZ R7,C:0802
C:0x0810 22 RET 在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.。