c语言中的精确延时程序举例

合集下载

C语言里如何编写精确的微量延时

C语言里如何编写精确的微量延时

C 语言里如何编写精确的微量延时
众所周知,相比于其他编程语言,C 语言在编写嵌入式编程中有着绝对的优势。

但它总也有缺点的:它的时序性比较差,不容易编写精准的延时。

而在编写嵌入系统驱动程序时,常常需要比较精确的软件延时,这使得C 语言的劣势暴露了出来,一般都只能通过嵌入汇编的方式实现。

例如,在1MHZ 工作频率下需要延时10us,就需要嵌入10 句空操作指令,显然在书写上比较难堪。

本文提出一种简化书写的延时方案,使用带参数的宏构来造微小时间片,可以实现完全精确的软件延时,大大方便了驱动程序及软件模拟通信协议的编写。

说明:以下皆为ICC AVR 平台下的讨论,对AVR 系列所有型号的单片机皆有效。

至于其他平台,可据此方案自行修改和移值。

该方案的实现方法其实很简单:
首先定义N 个宏,分别调用1 ~ N 个汇编空操作指令,如:
#define NOP_1 asm(nop)//延时一个时钟周期。

C语言延时程序

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语言的延时程序

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及汇编延时程序讲解

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语言精确延时

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精确延时程序(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是否也能实现时间的精确控制呢?答案是肯定的。

在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语言精确微秒级的延时

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 语言编程时延时程序是非常常见的,但是实现一个精确 的延时是不太容易的,在给一个朋友的公司产品做维护时,发现一段 代码,可以实现微妙级的延时。看起来代码非常简单。但是我以前没 有想到过。我们一起来看看这段代码。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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 在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.。

相关文档
最新文档