单片机C语言的精确延时程序设计
单片机延时1小时的程序
单片机延时1小时的程序摘要:1.单片机延时程序背景及应用2.单片机延时1 小时的程序实现方法3.程序代码及注释4.程序测试与优化5.总结正文:1.单片机延时程序背景及应用单片机(Microcontroller Unit,简称MCU)是一种集成度较高的微处理器,广泛应用于嵌入式系统中。
在实际应用中,单片机往往需要执行一些耗时较长的操作,例如数据传输、通讯协议处理等。
为了保证系统的稳定运行,需要对这些操作进行延时处理。
本文将介绍一种实现单片机延时1 小时的程序。
2.单片机延时1 小时的程序实现方法实现单片机延时1 小时的程序,通常可以采用以下两种方法:方法一:使用定时器/计数器定时器/计数器是单片机内部的一种功能模块,可以实现对系统运行时间的测量和控制。
通过设置定时器/计数器的初值和计数周期,可以实现不同时间的延时。
方法二:利用软件循环在程序中通过无限循环实现延时,每循环一次,延时时间减少相应的执行时间。
这种方法的延时时间取决于循环次数,需要占用较多的CPU 资源。
3.程序代码及注释以下是一个使用定时器/计数器实现单片机延时1小时的程序代码示例(以STC89C52为例):```c#include <reg52.h>#include <intrins.h>sbit LED = P1 ^ 0; // 定义LED 端口void delay(unsigned int ms) // 延时函数原型声明{unsigned int i, j;for (i = ms; i > 0; i--)for (j = 114; j > 0; j--);}void main(){TMOD = 0x01; // 定时器方式1TH0 = (65536 - 45872) / 256;TL0 = (65536 - 45872) % 256;EA = 1; // 开总中断ET0 = 1; // 开定时器0 中断TR0 = 1; // 启动定时器0while (1){P1 = _crol_(P1, 1); // LED 左右移动delay(50000); // 延时50ms}}void timer0() interrupt 1 // 定时器0 中断服务函数{TH0 = (65536 - 45872) / 256;TL0 = (65536 - 45872) % 256;}```4.程序测试与优化将编写好的程序烧写到单片机中,通过观察LED 的状态变化,验证延时效果。
单片机精确延时计算和中断定时
单片机精确延时计算和中断定时单片机精确延时计算和定时中断一.延时1. 10ms延时程序(for循环嵌套)*************************************************************** ****** 文件名称:void delay_10ms()功能:10ms延时参数:单片机晶振12MHz*************************************************************** ****** void delay_10ms(){unsigned int i, j;for(i=0;i<10;i++){for(j=0;j<124;j++);}}i 和j 定义为int整型时,for循环执行时间为8个机器周期,当i 和j 定义为char 字符型时,for 循环执行时间3个机器周期。
“;”一个机器周期,每次调用for循环2个机器周期。
则执行本段延时程序是内循环时间t1=8*124+3个机器周期,其中“8”执行for循环指令时间;“124”为for循环次数;“3”为每次调用for循环指令的时间。
外循环t2=t1*10+8*10+3其中“10”为for循环次数;“8”为一次for循环指令调用和执行时间;“10”为调用for循环次数,3为调用for循环指令时间。
所以本程序延时t=((8*124)+3)*10+8*10+3=10033=10.033ms≈10ms。
注意:变量为整型时,每次调用for循环需要3个机器周期的调用时间,执行for循环判断需要8个机器周期的执行时间;字符型变量时,每次调用for循环需要2个机器周期的调用时间,执行for循环判断需要3个机器周期的执行时间。
程序运行到第一个断点所用时间0.00038900s,运行到第二个断点所用时间为0.01042800s,则执行delay_10ms()函数所用时间为0.010428-0.000389=0.010039s= 10.039ms≈10ms。
单片机延时程序怎么写(二)2024
单片机延时程序怎么写(二)引言概述:在单片机编程中,延时程序是非常常见且必要的一部分。
在上一篇文章中,我们已经介绍了如何使用循环来实现延时。
然而,这种方法可能不是最佳的选择,特别是在需要准确延时的情况下。
在本文中,我们将介绍一种更加精确和高效的延时程序编写方法。
正文内容:一、使用定时器来实现延时1. 配置定时器的基本参数,如计数模式、计数频率等。
2. 设置定时器的初值和重载值,用于设定延时的时间。
3. 启动定时器开始计时。
4. 等待定时器计时完毕,即延时时间到达。
5. 定时器计时完毕后,关闭定时器并清除中断标志。
二、使用硬件延时器来实现延时1. 硬件延时器是一种特殊的定时器,可以实现更高精度的延时。
2. 配置硬件延时器的时钟源和计数模式。
3. 设置硬件延时器的初值和重载值,用于设定延时的时间。
4. 启动硬件延时器开始计时。
5. 等待硬件延时器计时完毕,即延时时间到达。
三、使用外部晶振来实现延时1. 外部晶振可以提供更准确的时钟信号,从而实现更精确的延时。
2. 连接外部晶振到单片机的时钟输入引脚。
3. 配置单片机的时钟源为外部晶振。
4. 根据外部晶振的频率设置延时时间。
5. 使用循环检测的方法等待延时时间到达。
四、使用软件延时函数来实现延时1. 软件延时函数是一种基于循环的延时实现方法。
2. 根据单片机的时钟频率和所需延时时间计算循环次数。
3. 使用循环进行延时,每次循环耗时固定。
4. 根据所需延时时间和循环耗时计算实际应该循环的次数。
5. 注意考虑单片机的优化设置,避免编译器优化影响延时准确性。
五、延时程序的优化技巧1. 选择合适的延时方法,根据实际需求和要求选择最合适的延时实现方法。
2. 考虑延时时间的准确性,根据需求选择合适的时钟源和计数模式等参数。
3. 避免使用不必要的中断和其他程序操作,以确保延时程序的准确性。
4. 根据硬件特性和需求进行延时函数的优化,提高程序的执行效率。
5. 针对不同的延时需求,编写相应的延时函数库,方便重复使用和维护。
单片机C51精确延时程序的设计与实现
2利用K e i l C 5 1 的软件仿真调试功能实现精确延时设计
这里设计一个1 毫秒延 时函数如下 , 该函数利用循环语句实现 延时 , 修改f o r 循环结束判 断条件 的循环次数 , 然后通过K e l f 软件 仿 真测量其运行 时间 , 如此反复 修改循环 次数并仿真运行 , 最 终获得 准确的循环次数值 。 本 函数 中设置P r  ̄e c t / o p t i o n s f o r Ta r g e t 子菜单 中的晶振为
A, #0 x0 0
R5
C: 0 x 0 0 3 B C: O xO 0 3 C C: 0 x O 0 3 F C: O x 0 0 4 0 C: 0 x 0 0 4 2
CJ NE I NC S J MP RE T
R5, #0 x0 0 , C: 0 0 4 0
C: 0 x 0 0 2 6 C: 0 x 0 0 2 7 C: 0 x 0 0 2 8 C: 0 x 0 0 2 A C: 0 x 0 0 2 B C: o ) 【 o o 2 C
C: 0 x0 0 2 E C: 0 x 0 0 2 F C: 0 x 0 0 3 0 M OV
设计开发
1 1 戴 目 q j 0 术
单片机 C 5 1 精确延时程序的设计与实现
鲁杰爽
( 湖北职业技术学院 湖北孝感 4 3 2 0 0 0 )
摘要: 本文 阐述 了在单 片i  ̄ K e i l C 5 1 开发 环境 中, 利用c 5 1 语言 实现 精确延 时程序设 计的 方法, 并 实例 分析 了延 时 时间的计算 方法 。 关键 词: 单 片机 c 5 1 语 言 软件 延 时 程序 设计 中图分类号: T P 3 1 5 文 献标识 ̄ L q : A 文章 编号 : 1 0 0 7 . 9 4 1 6 ( 2 0 1 4 ) 0 9 — 0 1 7 4 一 O<r e g5 1 . h>
51单片机C语言精确延时程序(超级准)
51单片机 C语言精确延时程序(超级准)
51单片机C语言精密延时程序 程序如下: void delayms(unsigned char t) { unsigned char j; unsigned char i; do { j=3; do { i=165; do { --i; } while(i!=0); --j; } while(j!=0); --t; } while(t!=0); } 该程序延时时基为1ms,所以最大延时时间是255ms 下面是反编译的汇编程序 C:0x0031 7E03 MOV R6,#0x03 C:0x0033 7DA5 MOV R5,#0xA5 C:0x0035 DDFE DJNZ R5,C:0035 C:0x0037 DEFA DJNZ R6,C:0033 C:0x0039 DFF6 DJNZ R7,delayms(C:0031) C:0x003B 22 RET 延时时间计算公式如下: ((R5*2 + 2+1)*R6+2+1)R7
假设R7=1,上式为(165*2+3)*3+2+1 =1002us!!!!! 以上程序使用的晶振是12MHz,如果使用的是其他频率的晶振只需计算出1ms的机器周期 数,代入5*2 + 2+1)*R6+2+1,选择合适的R
C8051F单片机C程序精确延时的方法
编译情况相同。3种循环语句在Keil C51中具有不同编 译特点的原因在于它们的流程不同。do—while语句是先 执行后判断,while和for语句都是先判断后执行。进行
多层循环时,使用do—while语句具有更大的优势:编译的 汇编代码就如直接用汇编语言编写的程序,结构紧凑,编
译效率高,条件转移控制循环次数的过程简单。因此,虽
C8051F单片机是完全集成的混合信号系统级芯片 (S0c),其MCU系统控制器的内核是CIP一51微控制器。 CIP一51的指令集与标准8051指令集完全兼容。CIP一 51采用流水线指令结构,指令时序与标准805l不同: 70%指令的执行时间为l或2个系统时钟周期;所有指令 时序都以时钟周期计算;大多数指令执行所需的时钟周期 数与指令的字节数一致;条件转移指令在不发生转移时和 发生转移时的时钟周期数不同。同标准8051相比, C8051F单片机实现程序延时的方法更复杂些。
void SingleCircle(unsigned char t){ unsigned char X=t,Y 5 tl
t基金项目:福建省教育厅科技硬目(jB07277)。
do(
;
}while(一一t); while(x一一);
for(;y--一;); }
使用Keil C51 V7.50编译器编泽,得到的汇编代码如 下:
2丁+(7l+3)T·(X一1)+(,l+2)T=ZT+(行+3)T·X一1’
同理,可得Delay函数的延时时间: {2T+[2T+(咒+3)T·x—T+3T]·y一丁+3丁)·
£一1’+5丁={[4y+(咒+3)X·y+4]·£+4}·T 其中,5丁为返回指令RET的时钟周期数。考虑调用De- lay函数的LCALL指令(时钟周期数为4T)和参数传递的 MOV指令(时钟周期数为2n,则总延时时间t且为
单片机定时器延时程序
单片机定时器延时程序一、引言在单片机的应用中,定时器是一个非常重要的模块。
通过使用定时器,我们可以实现各种定时功能,如延时、计时等。
本文将介绍单片机定时器的延时程序,通过编写代码实现定时功能的延时操作。
二、定时器的基本原理单片机中的定时器是通过计数器的方式实现的。
定时器有一个时钟源,每个时钟周期计数器加1。
当计数器的值达到预设值时,就会触发定时器中断,并执行相应的中断服务程序。
通过改变计数器的预设值,我们可以实现不同的定时功能。
三、编写延时程序在单片机中,我们可以通过设置定时器的预设值来实现延时功能。
下面是一个简单的延时程序示例:```c#include <reg52.h>void delay(unsigned int ms){unsigned int i, j;for(i=0; i<ms; i++)for(j=0; j<1234; j++);}void main(){while(1){// 延时1秒delay(1000);// 执行其他操作}}```上述代码中,我们定义了一个delay()函数,用来实现延时操作。
delay()函数的参数ms表示延时的毫秒数。
通过for循环的嵌套,我们可以控制延时的时间。
在主函数中,我们可以调用delay()函数来实现延时操作。
在上述代码中,我们设置延时1秒,然后执行其他操作。
通过不断调用delay()函数,我们可以实现不同的延时功能。
四、延时精度问题在实际应用中,我们经常会遇到延时精度的问题。
由于单片机的时钟源和延时程序本身的执行时间误差,可能导致延时时间不准确。
为了提高延时精度,我们可以通过以下几种方法来解决:1. 使用定时器的中断功能:通过设置定时器的中断,可以在延时结束时触发中断,从而提高延时精度。
2. 调整延时参数:根据实际情况,可以适当调整延时参数,以达到所需的延时时间。
3. 使用外部时钟源:在一些对延时精度要求较高的应用中,可以使用外部时钟源来提高延时精度。
51单片机c语言延时
51单片机c语言延时51单片机(8051微控制器)是一种广泛使用的嵌入式系统芯片,其编程语言包括C语言和汇编语言等。
在C语言中,实现51单片机延时的方法有多种,下面介绍其中一种常用的方法。
首先,我们需要了解51单片机的指令周期和机器周期。
指令周期是指单片机执行一条指令所需的时间,而机器周期是指单片机执行一个操作所需的时间,通常以微秒为单位。
在C语言中,我们可以使用循环结构来实现延时。
#include <reg51.h> // 包含51单片机的寄存器定义void delay(unsigned int time) // 延时函数,参数为需要延时的微秒数{unsigned int i, j;for (i = 0; i < time; i++)for (j = 0; j < 1275; j++); // 1275个机器周期,约等于1ms}void main() // 主函数{while (1) // 无限循环{// 在这里添加需要延时的代码P1 = 0x00; // 例如将P1口清零delay(1000); // 延时1秒P1 = 0xFF; // 将P1口清零delay(1000); // 延时1秒}}在上面的代码中,我们定义了一个名为delay的函数,用于实现延时操作。
该函数接受一个无符号整数参数time,表示需要延时的微秒数。
在函数内部,我们使用两个嵌套的循环来计算延时时间,其中外层循环控制需要延时的次数,内层循环控制每个机器周期的时间(约为1微秒)。
具体来说,内层循环执行了约1275次操作(具体数值取决于编译器和单片机的型号),以实现约1毫秒的延时时间。
需要注意的是,由于单片机的指令周期和机器周期不同,因此我们需要根据具体的单片机型号和编译器进行调整。
在主函数中,我们使用一个无限循环来不断执行需要延时的操作。
例如,我们将P1口的所有引脚清零,然后调用delay函数进行1秒钟的延时,再将P1口清零并再次调用delay函数进行1秒钟的延时。
单片机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语言延时程序计算
2 软件延时与时间计算
在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。下面介绍几种软件延时的方法。
2.1 短暂延时
可以在C文件中通过使用带_NOP_( )语句的函数实现,定义一系列不同的延
单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。本程序中假设使用频率为12 MHz的晶振。最长的延时时间可达216=65 536 μs。若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
80us 1 1 48 0
90us 1 1 55 +0.5
}
延时时间 a的值 b的值 c的值 延时误差(us)
10us 1 1 1 -0.5
1ms 1 3 219 -1.5
2ms 2 3 220 +3
900us
9 1 63 -1.5
60us 1 1 35 +0.5
70us 1 1 42 +1
在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。
300us 3 1 63 +1.5
单片机C语言延时计算
单片机C语言延时计算单片机是一种集成电路芯片,内部集成了微处理器、存储器、输入输出接口等主要部件。
C语言是常用的单片机编程语言,可以通过编写C程序来实现单片机的控制和功能。
在单片机编程中,延时是一种常用的操作,用于控制程序执行过程中的时间间隔。
延时的实现方法有多种,可以使用循环遍历、定时器、外部中断等方式。
在循环遍历的延时方法中,可以通过设定一个循环次数来实现延时。
具体的延时时间与循环的次数成正比关系。
例如,在一个8位单片机中,循环一次大约需要4个机器周期,因此可以通过适当设置循环次数来达到需要的延时时间。
但是,使用循环遍历的延时方法会占用CPU资源,可能会影响其他任务的执行。
另一种常用的延时方法是使用定时器。
单片机内部通常集成了一个或多个定时器,可以通过设置定时器的初值和工作模式来实现精确的延时。
例如,可以通过设置定时器的计数值和工作频率来计算出延时的时间。
在定时器工作期间,单片机可以继续执行其他任务,不会占用过多的CPU资源。
除了循环遍历和定时器方法外,还可以使用外部中断的方式来实现延时。
具体的实现方法是通过外部信号触发中断,并在中断处理程序中实现延时功能。
这种方法可以根据外部信号的频率和工作模式来调整延时时间。
在单片机编程中,为了提高代码的可读性和可重用性,可以将延时操作封装成函数。
例如,可以定义一个名为delay的函数,函数的参数为延时的时间(单位为毫秒),函数内部通过循环遍历、定时器或外部中断的方式实现延时。
延时的时间计算可以考虑单片机的工作频率、机器周期以及延时的时间要求。
单片机的工作频率可以由时钟源来决定,一般可以通过设置分频系数来调整。
机器周期是单片机执行一条指令所需的时间,通过单片机的数据手册可以查到相关的数据。
根据单片机的工作频率和机器周期,可以计算出所需的循环次数或定时器计数值。
在使用延时功能时需要注意延时时间的准确性和可调性。
准确性是指延时的实际时间与预期时间之间的误差,通过调整循环次数或定时器计数值可以实现较高的准确性。
PIC单片机C语言延时程序和循环子程序
PIC单片机C语言延时程序和循环子程序
PIC单片机C语言延时程序和循环子程序
很多朋友说C 中不能精确控制延时时间,不能象汇编那样直观。
其实不然, 对延时函数深入了解一下就能设计出一个理想的框价出来。
一般的我们都用
for(x=100;--x;){;}此句等同与x=100;while(--x){;};
或for(x=0;x 来写一个延时函数。
在这里要特别注意:X=100,并不表示只运行100 个指令时间就跳出循环。
可以看看编译后的汇编:
x=100;while(--x){;}
汇编后:
movlw 100
bcf 3,5
bcf 3,6
movwf_delay
l2 decfsz _delay
goto l2
return
从代码可以看出总的指令是是303 个,其公式是8+3*(X-1)。
注意其中循环周期是X-1 是99 个。
这里总结的是x 为char 类型的循环体,当x 为int 时候,其中受X 值的影响较大。
建议设计一个char 类型的循环体,然后再用一个循环体来调用它,可以实现精确的长时间的延时。
C51单片机中的C语言精确延时的资料和例子
在网上搜了一些关于C51单片机C语言的精确延时(相对)的例子和方法现总结如下:1,_nop_() 适用于us级的少量延时标准的C语言中没有空语句。
但在单片机的C语言编程中,经常需要用几个空指令产生短延时的效果。
这在汇编语言中很容易实现,写几个nop就行了。
在keil C51中,直接调用库函数:#include<intrins.h> //声明了void _nop_(void);_nop_(); //产生一条NOP指令作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
NOP指令为单周期指令,可由晶振频率算出延时时间,对于12M晶振,延时1uS。
2,一般延时大于10us一,定义的C51中循环变量,尽量采用无符号字符型变量。
二,在FOR循环语句中,尽量采用变量减减来做循环。
三,在do…while,while语句中,循环体内变量也采用减减方法这因为在C51编译器中,对不同的循环方法,采用不同的指令来完成的例:unsigned char i;for(i=255;i>0;i--);用keil C51编译后MOV09H,#0FFHLOOP: DJNZ09H,LOOP指令相当简洁,也很好计算精确的延时时间。
3,延时更长,达到MS级,这时需要嵌套循环循环嵌套的方法常用于达到ms级的延时。
对于循环语句同样可以采用for,do…while,while结构来完成,每个循环体内的变量仍然采用无符号字符变量。
例:unsigned char i,jfor(i=255;i>0;i--)for(j=255;j>0;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--;}下面给出有关在C51中延时子程序设计时要注意的问题(一些经验之谈)1、在C51中进行精确的延时子程序设计时,尽量不要或少在延时子程序中定义局部变量,所有的延时子程序中变量通过有参函数传递。
c51的精确延时
注:1.编译软件为"Keil uVision3"(Keil uVision2也试用)。用其他编译软件的话就不准了。
2.需要包含头文件<intrins.h>
3.所有函数的延时时间都是在12Mhz晶振下计算的,如用其他晶振需进行换算。
4.函数的执行时间为“函数的参数”乘以精确到的时间。例如delayms(unsigned char n)函数,其精确度为1ms,如果写入语句delayms(4),那就是延时4ms。
用c语言为单片机编程无疑十分节约时间,可在很短的时间内开发出较高效的代码,对于程序的维护和扩充也较汇编语言方便许多。
但c语言也有它的不足之处,那就是在时间的精确控制上。要想用c实现精确的延时,只能把c的函数编译成汇编语言,然后按照汇编语言计算其执行时间。本人就按照这种方法,编写了几个51单片机的c语言精确延时函数。
(2)精确到100us的延时(12MHz)
void delay100us(unsigned char n)
{ unsigned char i;
for(;n;n--)
{ _nop_();
for(i=46;i;i--);
}
}
(3)精确的半毫秒延时函数(12MHz)
5.计算出来的延时时间不包括函数调用与返回的时间。如果函数的精确度较高,且参数较小,那么实际延时时间就可能与计算的时间差很远。
(1)精确到2us的延时(12MHz)
void delayus(unsigned char n)
{ while(--n);
}
void delay1_2ms(unsigned char n)
{ unsigned char i;
关于单片机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语言下的各类延时程序做了下总结。
由于单
片机C语言下利用软件延时不容易做到精确的定时,所以很多人在编写延时子
程序的时候不能好好的把握延时的具体时间。
C语言下,延时程序主要有以下
几种:
一:
void delay(unsigned char k){
unsigned char i,k; //定义变量 for(i=0;ik;i++); //for循环语句
}
该程序在Keil环境下,会先将C语言转化成汇编语言,那么我们就可以根据
汇编语言来计算出精确的时间,转化具体步骤如下:
CLR A ;指令1 MOV R7,A ;指令2 LOOP: INC R7 ;指令3 CJNE R7,k,LOOP ;指令4
这里,指令1,指令2和指令3各消耗1个机器周期,指令4消耗两个机器
周期(可查此表得知:51hei/mcuteach/1312.html),而在12M的晶振下一个机
器周期是1us,在这个过程中,指令1和指令2分别执行1次,即消耗1+1us,
而指令3和指令4分别执行了k次,那么这样加起来,这个延时子程序所消耗
的具体时间就是t=1+1+(1+2)*k=3k+2us。
呵呵,这样说来,如果我们定义的k为100的话,这个延时子程序的精确时
间就是302us。
二:
void delay(unsigned char i){while(--i){;}}
同样的道理,将其反汇编,可以看到,只有一条语句:DJNZ i,$;。
在单片机Keil C开发环境中设计精确的延时函数
张宏,等:在单片机KeilC开发环境中设计精确的延时函数图1KeilC语言延时的实现机制Fig.1Thede】ayfunctionwithKeilC表1循环体for(;i!一O;i一~)转换成的汇编代码Table1TheASMcodeofloop“for(;I>Oi一一)”可以看出,完成一次主循环的需要6个机器周期,在循环次数分别是o、1、z、3……情况下,延时函数所需的机器周期分别是3、9、15、21…….如果要调用该延时函数,需要使用delay(x)语句,其中x是延时函数主循环的次数。
决定了延时时间的长短.该语句经KeilC转换后成的汇编代码如表2.表2调用该延时函数转换成的汇编代码Table2TheASMcodeofcallingthefunction分析该语句可知,调用延时函数需要3个时钟周期来完成.如果调用延时函数时设定循环的处始值是i,可以得该延时函数的延长时间6i+3+3.该循环延时函数的延时精度是6个机器周期,假如系统使用的晶振是12MHz,则延时时间是(6i+6)/12微秒,同样道理,循环体是for(a=i;a!=O;a一一)的延时函数与此类似.2.2使用while(一一i)语句实现精度为2微秒级的延时函数如果要实现微秒级的延时精度,可以使用下面的函数代码:voiddelayl(unsignedchari){while(~一i);)循环体while(一一i)生成的汇编源代码以及机器周期数如表3.可以看出,完成一次主循环的需要2个机器周期,在循环次数分别是o、1、2、3……情况下,延时函数所需的机器周期分别是2、4、6、8…….要调用该延时函数,由表2可知需要3个时钟周期.如果调用延时函数时设定循环个数的初始值是i,可65徐州工程学院学报2007年第8期以得该延时函数的延长时间2i+2+3.假定系统使用的晶振是12MHz,则延时时间是(2i+5)/12微秒.该循环延时函数的的延时精度是2个机器周期.表3whiIe(一一il生成的汇编代码Table3TheASMcodeofloop“wh订e(一一i)”3使用一noD一()语句设计任意延时精度的延时函数一nop一()语句是KeilC语言中自己带的一个函数,其功能是相当于汇编语句中的NOP指令.该语句的功能是,例如有下面C语言语句:……一nop一();一nop一();……则编译成的汇编代码为:……N()PN()P……如果在第一个延时函数中加入一nop一()语句,就可以增加主循环的运行周期.因此将一nop一()语句与延时循环程序结合起来,可以设计任意的延时时间.分析下面实例代码:Voiddelay(unsignedchari){for(;i!=0;i一一){一nop一();一nop一();)}该代码是在延时函数代码的循环体里面加入两个一nop一()语句,编译生成的汇编代码以及机器周期数如表4.表4加入两个一nop()语句后的延时函数汇编代码Table4TheASMcodeaddedtwonop()line可以看出,因为C语言循环体加入两个nop()语句,因此汇编代码比原来多两个机器周期,完成一次主循环需要8个机器周期,在循环次数分别是O、1、2、3……情况下,延时函数所需的机器周期分别是3、11、19、27…….调用该延时函数,由表2可知需要3个时钟周期.假设调用延时函数时设定循环的初始值是i,可以得该延时函数的延长时间8i+3+3.该循环延时函数的的延时精度是8个机器周期.假定系统使用的晶振是12MHz,则延时时间是(8i+6)/12微秒.通过灵活使用nop()函数,可以灵活设计出任意精度延时函数,达到满意的延时效果.在Keilc语言中,使用nop()语句需要在程序的前面加上“#include<INTRINS.h>”语句.每一个nop()语句编译后需要一个字节的程序空间.4结语上面程序在KeiluVision7.o版本中实现.对Ke订C的编译原理的深入理解,通过恰当的语法运用,合理的语句运用,KeilC语言是可以达到满意的延时效果的.这样既可以发挥C语句的优点,又可以对外围元件进行实时的控制.66在单片机Keil C开发环境中设计精确的延时函数作者:张宏, 邢文生, ZHANG Hong, XING Wen-sheng作者单位:焦作大学,河南,焦作,454000刊名:徐州工程学院学报英文刊名:XUZHOU INSTITUTE OF TECHNOLOGY年,卷(期):2007,22(8)被引用次数:1次1.李建忠单片机原理及应用 20032.金炯泰如何使用KEIL 8051 C编译器 20023.范风强单片机语言C51应用实战集锦 20034.徐爱钧Keil Cx51 V7.0单片机高级语言编程与uVision2应用实践 20041.期刊论文邢文生.李希臣.XING Wensheng.LI Xichen nRF2401的ShockBurstTM模式及其单片机Keil C语言实现-电子工程师2007,33(1)nRF2401是单片2.4 GHz的无线收发一体芯片,只需少量外围元件便可组成射频收发电路,通过SPI接口与单片机进行通信,有功耗低、内置CRC(循环冗余校验)、有可设置地址等优点.文中主要介绍其常用的ShockBurstTM收发模式以及与单片机的硬件连接实现,并介绍单片机模拟SPI接口、nRF2401的配置实现和无线收发数据的实现.单片机采用51系列W77LE58,软件使用Keil C语言.该系统可用于点对点及点对多点的无线数据传输,传输速率最高可达到1 Mbit/s.2.学位论文周天威智能临床生化分析仪器的研究与设计2007生化分析仪是临床医学中重要的检测仪器。
单片机C程序延时精度研究
(AT89C51)单片机C程序延时精度研究(转载)2009-10-13 10:11(AT89C51)单片机C程序延时精度研究在单片机应用中,经常会遇到需要短时间延时的情况,一般都是几十到几百μs,并且需要很高的精度(比如用单片机驱动DS18B20时,误差容许的范围在十几μs以内,不然很容易出错);而某些情况下延时时间较长,用计时器往往有点小题大做。
另外在特殊情况下,计时器甚至已经全部用于其他方面的定时处理,此时就只能使用软件定时了[1]。
1 C语言程序延时Keil C51的编程语言常用的有2种:一种是汇编语言;另一种是C 语言。
用汇编语言写单片机程序时,精确时间延时是相对容易解决的。
比如,用的是晶振频率为12 MHz的AT89C51,打算延时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语言在大多数情况下,其机器代码生成效率和汇编语言相当,但可读性和可移植性却远远超过汇编语言,且C 语言还可以嵌入汇编程序来解决高时效性的代码编写问题。
就开发周期而言,中大型软件的编写使用C 语言的开发周期通常要比汇编语言短很多,因此研究C语言程序的精确延时性能具有重要的意义[3]。
C程序中可使用不同类型的变量来进行延时设计。
经实验测试,使用unsigned char类型具有比unsigned int更优化的代码,在使用时应该使用unsigned char作为延时变量。
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,造成“死机”现象。
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在精确延时的计算当中,最容易让人忽略的是计算循环外的那部分延时,在对时间要求不高的场合,这部分对程序不会造成影响.。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
法 在生成目标代码时 会有所不同 开发人员必须研 究它生成的汇编语言代码 来保证时间的准确性 这也 许是除了使用嵌入汇编或直接编写汇编函数的唯一方 法 其实在单片机的 C 编译器中 已经有足够底层操作 方面的扩展 所以这里只考虑纯 C 语言的方法
3 延时程序设计
以德国 Keil 公司的 C 5 1 编译器为例 目前它已被公 认为业界的标准 以下讨论均假设 5 1 单片机时钟晶振 为 6 M H z 以小模式下编译 这时程序指令执行的最小 单位是 2 s 如果使用非英特尔且内核优化过的单片 机 应切换回普通模式 或仔细研究它的时序 以 D S 1 8 B 2 0 为例 临时在程序中需要延时 2 s 那么可以 用下述程序
val=val>>1
delay(10)
//因为写时间必须匹配
D0 = 1;
}
delay(2);
}
完整的 1 8 B 2 0 数据采集程序见本刊网站 w w w . d p j .
c o m . c n 其中包含了 CRC 校验高级语言的运 用大大提高了开发效率 在用 C 等高级语言编写这类时 间要求严格的程序时 分析最终的目标汇编代码是无法 避免的 在现代带有集成开发环境的编译器中 有软件 仿真 或有硬件调试功能 都给精确定时程序的开发带 来方便 充分发挥软件工具的潜力 才能真正在各种环 境下发挥高级语言带来的最大好处 效率
生成的汇编语言代码不是 LCALL delay1; LCALL delay2;
它被编译器优化 在调用 delay1 进入并执行该函数 返回前直接跳入 d e l a y 2 执行 类似于 delay1
LJMP delay 2;
由 delay 2 执行 RET 返回 这样连续调用两个函数时
就变成一次调用加跳转 结果会省去 2 s 解决了延
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
}
编译后的形式
EXPERIENCE EXCHANGE 经验交流
单片机 C 语言的精确延时程序设计
东北电力学院 盛文利
现在单片机的开发中 C 语言以其方便 灵活 逻 辑性强 易于维护和可移植性好等强大优势 占据了单 片机开发的主要地位 过去 由于单片机 C 语言本身存 在的缺陷 加之单片机工程项目本身都不大 C 语言在 单片机中的应用没有被重视 在 C 语言环境下 只需关 心程序的逻辑关系 实现细节则由编译器完成 这为快 速开发提供了条件 也大大减小了开发工作量 但同 时 实现细节就不被控制了 这个问题对于经常重视实 现细节的单片机 就必须要得到解决 好在一般的 C 语 言编译器都提供嵌入汇编 与汇编互调用和汇编级的代 码察看等功能 现以 Keil C51(见参考文献[1])下的单总线 器件程序开发为例 说明解决方法
_nop_()
//2 s
_nop_()
//2 s
_nop_()
//2 s
D0 = 1
/ / 恢复高电平
_nop_()
//2 s
_nop_()
//2 s
if(D0) value|=0x80 _nop_(); //2 s
delay(10)
/ / 等待
}
} while(vd);
}
编译后
RSEG ?PR?_delay5?DLY3
_delay5:
USING0
?C0003:
D J N Z R7,?C0003
RET
看来 do-while 是和 DJNZ 相对应编译的
4 调用时间和某些细节
除了直接插入 _ n o p _ ( ) 语句的短时间延时 在稍长 时间的多变延时程序中 往往需要调用上节讨论的延时 函数来完成延时 其中以汇编语言函数和 do-wh i l e 最易
return(value);
}
写 1 字节的程序
void write_byte(unsigned char val)
{ unsigned char i
for (i=0 i<8 i++) {
D0 = 0
// 把DQ拉低启动
delay(1)
//为4时不能读
D0 = val&0x01
#include< intrins.h> void somefunc(void) { _nop_() }
如果要延时 64 s 甚至 640 s 那么不可能在程序 中重复上述 _ n o p _ ( ) 虽然这并不会出错 可以利用它 来构建延时程序 精确定时的问题就变为延时程序的精 度问题 首先讨论空操作延时
3.1 空操作延时及延时函数
注意到 D S 1 8 B 2 0 最小时隙除大于 1 s 的外 最小 的就是 1 5 s 而数据的读或写也包含在这 1 5 s 中 由于定时器的延时要对定时器进行初始化 不易得到小 的延时 只能用于复位脉冲 即在 4 8 0  ̄ 9 6 0 s 之间的 延时 程序实现接近 9 6 0 s 的延时 TH0 = -950/256; TL0 = -950%256; TMOD= TMOD|0x01 TR0 = 1;
_delay4:
M O V vd?040,R7
2s
DJNZ R7, ¥
RET
END OF _delay4
注意 这里用于参数传递的 R 7 被复制保存起来了
这样在调用时 比汇编书写的函数多出 2 s
除此之外 还是可以编出全 C 的类似函数
void delay5(unsigned char vd)
{ do {vd--;
汇编时代常用的延时指令为
MOV R7 DDLY
DJNZ R7 ¥
产生最小 4 s 的延时 仿造的 C 程序如下
void delay1(ndly)
{for( ndly>0 ndly--)
}
生成的汇编代码与 D J N Z 无关 是如下形式的 其
中无关的编译注释已删除
RSEG ?PR?_delay1?DLY2
{ for (vd=0 vd<10 vd++)
}
生成的汇编代码如下
RSEG ?PR?_delay2?DLY2
_delay2:
USING0
CLR A
2s
M O V R7,A
2s
?C0002:
INC R7
2s
C J N E R7,#0AH,?C0002 4 s
?C0005:
RET
4s
; END OF _ delay2
初始化时序时间裕度大 容易实现 读写脉冲对时 序要求相对严格 尤其在慢速的 M C S - 5 1 下 指令的运 行在 s 级 读写时序在 15 s 的后一小部分 大约 4 s 不同批次的芯片会有少许差距 有的会允许你的时序有 少许误差 有的则非常严格
2 C 语言编译器
在用汇编语言编写程序时 很容易控制时间 因为 我们知道每条语句的执行时间 每段宏的执行时间以及 每段子程序加调用语句所消耗的时间 在单片机的 C 语 言开发中 C 语言编译器都对标准 C 作了针对单片机特 点的扩展 但对于不同的单片机 不同的 C 语言编译器 在将源程序翻译成目标机器语言时 会有不同的编译方
参考文献
1 Keil Software Keil uVision2 Reference Keil Electronik GmbH/Keil Software Inc 1995
2 DALLAS MAXIM 产品资料光盘 6.0版, 2002 收稿日期 2004-06-01
时问题 再根据参考文献[ 2 ] 可写出读字节程序
unsigned char read_byte(void)
{ unsigned char i
unsigned char value = 0
for (i=0 i<8 i++)
{ value>>=1;
//2 s
D0 = 0
/ / 把DQ拉低启动
列单片机进行产品开发工程技术人员的硬件和软件设计参考书 部分内容对其它类型单片机的开发也具有一定的参考价值
69 2004.10 Microcontrollers & Embedded Systems
万方数据
单片机C语言的精确延时程序设计
定时器启动后 单片机可以作其它事情 如复位看 门狗或 L E D 扫描
调用的短延时函数必须精确地受到控制 先作一个
67 2004.10 Microcontrollers & Embedded Systems
万方数据
经验交流
EXPERIENCE EXCHANGE
几 s 的延时实验程序 以观察它实际的延时时间 在
以上代码调用一次也有 14 s 之多 还是无法使用
也就是说 采用 f o r 形式的语句 生成的汇编代码都是
先减 再比较 还是与 D J N Z 无关 也就不能产生短
延时
3.2 短延时程序编写
首先想到的是用汇编语言函数或嵌入汇编的方法 汇编语言函数实现方法如下
N A M E DLY
?PR?_delay3?DLY SEGMENT CODE
?PR?_delay4?DLY SEGMENT CODE
?DT?_delay4?DLY SEGMENT DATA OVERLAYABLE PUBLIC
_delay4
RSEG ?DT?_delay4?DLY2
?_delay4?BYTE:
vd?040: DS 1
RSEG ?PR?_delay4?DLY2
1 单总线协议器件