单片机延时程序

f9a
单片机延时程序(适合初学者)
下面几个是单片机的延时程序(包括asm和C程序,都是我在学单片机的过程中用到的),在单片机延时程序中应考虑所使用的晶振的频率,在51系列的单片机中我们常用的是11.0592MHz和12.0000MHz的晶振,而在AVR单片机上常用的有8.000MHz和4.000MH的晶振所以在网上查找程序时如果涉及到精确延时则应该注意晶振的频率是多大。

软件延时:(asm)

晶振12MHZ,延时1秒
程序如下:
DELAY:MOV 72H,#100
LOOP3:MOV 71H,#100
LOOP1:MOV 70H,#47
LOOP0JNZ 70H,LOOP0
NOP
DJNZ 71H,LOOP1
MOV 70H,#46
LOOP2JNZ 70H,LOOP2
NOP
DJNZ 72H,LOOP3
MOV 70H,#48
LOOP4JNZ 70H,LOOP4

定时器延时:

晶振12MHZ,延时1s,定时器0工作方式为方式1

DELAY1:MOV R7,#0AH ;; 晶振12MHZ,延时0.5秒
AJMP DELAY
DELAY2:MOV R7,#14H ;; 晶振12MHZ,延时1秒
DELAY:CLR EX0
MOV TMOD,#01H ;设置定时器的工作方式为方式1
MOV TL0,#0B0H ;给定时器设置计数初始值
MOV TH0,#3CH
SETB TR0 ;开启定时器
HERE:JBC TF0,NEXT1
SJMP HERE
NEXT1:MOV TL0,#0B0H
MOV TH0,#3CH
DJNZ R7,HERE
CLR TR0 ;定时器要软件清零
SETB EX0
RET

C语言延时程序:


void delay_18B20(unsigned int i)
{
while(i--);
}


void Delay10us( ) //12mhz
{
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
}

/*****************11us延时函数*************************/
//
void delay(uint t)
{
for (;t>0;t--);
}



1ms延时子程序(12MHZ)

void delay1ms(uint p)//12mhz
{ uchar i,j;
for(i=0;i<p;i++)
{
for(j=0;j<124;j++)
{;}
}
}

10ms延时子程序(12MHZ)

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延时子程序(12MHZ)


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--);

}

200ms延时子程序(12MHZ)

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--);

}

500ms延时子程序程序: (12MHZ)
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--);
}

下面是用了8.0000MHZ的晶振的几个延时程序(用定时0的工作模式1):

(1)延时0.9MS

void delay_0_9ms(void)
{
TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/
TH0=0xfd;
TL0=0xa8;
TR0=1; /*启动定时器*/
while(TF0=
=0);
TR0=0;
}

(2)延时1MS

void delay_1ms(void)
{
TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/
TH0=0xfd;
TL0=0x65;
TR0

=1; /*启动定时器*/
while(TF0==0);
TR0=0;
}

(3)延时4.5ms

void delay_4_5ms(void)
{
TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/
TH0=0xf4;
TL0=0x48;
TR0=1; /*启动定时器*/
while(TF0==0);
TR0=0;
}

在用定时器做延时程序时如果懒得计算定时器计数的初始值可以在网上找一个专门用来做延时的小软件,我在用着感觉很实用,如果找不到的话可以留言,留下自己的邮箱我给发过去;如果上面的延时中有错误敬请指正。









Keil C51程序设计中几种精确延时方法

2009年07月28日 星期二 下午 11:15

延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。

1 使用定时器/计数器实现精确延时

单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。本程序中假设使用频率为12 MHz的晶振。最长的延时时间可达216=65 536 μs。若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。

在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。使用定时器/计数器延时从程序的执行效率
fc1
和稳定性两方面考虑都是最佳的方案。但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。

2 软件延时与时间计算

在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。下面介绍几种软件延时的方法。

2.1 短暂延时

可以在C文件中通过使用带_NOP_( )语句的函数实现,定义一系列不同的延时函数,如Delay10us( )、Delay25us( )、Delay40us( )等存放在一个自定义的C文件中,需要时在主程序中直接调用。如延时10 μs的延时函数可编写如下:

void Delay10us( ) {
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
_NOP_( );
}

Delay10us( )函数中共用了6个_NOP_( )语句,每个语句执行时间为1 μs。主函数调用Delay10us( )时,先执行一个LCALL指令(2 μs),然后执行6个_N
OP_( )语句(6 μs),最后执行了一个RET指令(2 μs),所以执行上述函数时共需要10 μs。 可以把这一函数

当作基本延时函数,在其他函数中调用,即嵌套调用\[4\],以实现较长时间的延时;但需要注意,如在Delay40us( )中直接调用4次Delay10us( )函数,得到的延时时间将是42 μs,而不是40 μs。这是因为执行Delay40us( )时,先执行了一次LCALL指令(2 μs),然后开始执行第一个Delay10us( ),执行完最后一个Delay10us( )时,直接返回到主程序。依此类推,如果是两层嵌套调用,如在Delay80us( )中两次调用Delay40us( ),则也要先执行一次LCALL指令(2 μs),然后执行两次Delay40us( )函数(84 μs),所以,实际延时时间为86 μs。简言之,只有最内层的函数执行RET指令。该指令直接返回到上级函数或主函数。如在Delay80μs( )中直接调用8次Delay10us( ),此时的延时时间为82 μs。通过修改基本延时函数和适当的组合调用,上述方法可以实现不同时间的延时。

2.2 在C51中嵌套汇编程序段实现延时

在C51中通过预处理指令#pragma asm和#pragma endasm可以嵌套汇编语言语句。用户编写的汇编语言紧跟在#pragma asm之后,在#pragma endasm之前结束。

如:#pragma asm

汇编语言程序段

#pragma endasm

延时函数可设置入口参数,可将参数定义为unsigned char、int或long型。根据参数与返回值的传递规则,这时参数和函数返回值位于R7、R7R6、R7R6R5中。在应用时应注意以下几点:

◆ #pragma asm、#pragma endasm不允许嵌套使用;
◆ 在程序的开头应加上预处理指令#pragma asm,在该指令之前只能有注释或其他预处理指令;
◆ 当使用asm语句时,编译系统并不输出目标模块,而只输出汇编源文件;
◆ asm只能用小写字母,如果把asm写成大写,编译系统就把它作为普通变量;
◆ #pragma asm、#pragma endasm和 asm只能在函数内使用。

将汇编语言与C51结合起来,充分发挥各自的优势,无疑是单片机开发人员的最佳选择。

2.3 使用示波器确定延时时间

利用示波器来测定延时程序执行时间。方法如下:编写一个实现延时的函数,在该函数的开始置某个I/O口线如P1.0为高电平,在函数的最后清P1.0为低电平。在主程序中循环调用该延时函数,通过示波器测量P1.0引脚上的高电平时间即可确定延时函数的执行时间。方法如下:

sbit T_point = P1^0;
void Dly1ms(void) {
unsigned int i,j;
while (1) {
T_point = 1;
for(i=0;i<2;i++){
for(j=0;j<124;j++){;}
}
T_point = 0;
for(i=0;i<1;i++){
for(j=0;j<124;j++){;}
}
}
}
void main (void) {
Dly1ms();
}

把P1.
0接入示波器,运行上面的程序,可以看到P1.0输出的波形为周期是3 ms的方波。其中,高电平为2 ms,低电平为1 ms,即for循环结构“for(j=0;j<124;j++)

{;}”的执行时间为1 ms。通过改变循环次数,可得到不同时间的延时。当然,也可以不用for循环而用别的语句实现延时。这里讨论的只是确定延时的方法。

2.4 使用反汇编工具计算延时时间

用Keil C51中的反汇编工具计算延时时间,在反汇编窗口中可用源程序和汇编程序的混合代码或汇编代码显示目标应用程序。为了说明这种方法,还使用“for (i=0;i<DlyT;i++) {;}”。在程序中加入这一循环结构,首先选择build taget,然后单击start/stop debug session按钮进入程序调试窗口,最后打开Disassembly window,找出与这部分循环结构相对应的汇编代码,具体如下:

C:0x000FE4CLRA//1T
C:0x0010FEMOVR6,A//1T
C:0x0011EEMOVA,R6//1T
C:0x0012C3CLRC//1T
C:0x00139FSUBBA,DlyT //1T
C:0x00145003JNCC:0019//2T
3f1

C:0x00160E INCR6//1T
C:0x001780F8SJMPC:0011//2T

可以看出,0x000F~0x0017一共8条语句,分析语句可以发现并不是每条语句都执行DlyT次。核心循环只有0x0011~0x0017共6条语句,总共8个机器周期,第1次循环先执行“CLR A”和“MOV R6,A”两条语句,需要2个机器周期,每循环1次需要8个机器周期,但最后1次循环需要5个机器周期。DlyT次核心循环语句消耗(2+DlyT×8+5)个机器周期,当系统采用12 MHz时,精度为7 μs。

当采用while (DlyT--)循环体时,DlyT的值存放在R7中。相对应的汇编代码如下:

C:0x000FAE07MOVR6, R7//1T
C:0x00111F DECR7//1T
C:0x0012EE MOVA,R6//1T
C:0x001370FAJNZC:000F//2T

循环语句执行的时间为(DlyT+1)×5个机器周期,即这种循环结构的延时精度为5 μs。

通过实验发现,如将while (DlyT--)改为while (--DlyT),经过反汇编后得到如下代码:

C:0x0014DFFE DJNZR7,C:0014//2T

可以看出,这时代码只有1句,共占用2个机器周期,精度达到2 μs,循环体耗时DlyT×2个机器周期;但这时应该注意,DlyT初始值不能为0。

注意:计算时间时还应加上函数调用和函数返回各2个机器周期时间。





0

支持【windows 系统】
第一步:

1.安装[Protel.2004破解版].Protel.DXP2004.ISO
打开镜像文件,
点击其中setup文件夹下面的setup.exe安装文件(两者选其中一个就可以了)。
2.安装[Protel.2004破解版].DXP2004ServicePack1.exe
3.安装[Protel.DXP2004.sp1..sp2.电路板设计].DXP2004SP2.exe
4.[Protel.DXP2004.sp1..sp2.电路板设计].DXP2004SP2_IntegratedLibraries.exe
安装库文件

第二步:

光盘镜像里面有【crack】文件,使用方法如下:
(1)先把【keygen.exe】解压缩到任意地方,打开【keygen.exe】文
件,
出现一个DOS窗口,在Enter User Name后面输入你的计算机名字
(右键点“我的电脑”,选“属性”,计算机名字为“注册到”后

面的字符),回车;
(2)然后出现License Mode,根据个人情况在Ener 1-2后面填1或者2(第一个是单机模式,第二个是网络模式),回车;
(3)接着出现的Choose License Type选2,回车;
(4)最后出现的Time Expired当然选3(无时间限制),回车;
(5)在keygen.exe的相同目录下将生成“Protel2004.alf”文件,这个就是我们需要的注册文件.
(当硬件有任何更改时,都必须重新按照上述方法生成Protel2004.alf文件)

第三步:

打开注册机文件:“[Protel.DXP2004.sp1..sp2.电路板设计].AltiumDXP2004SP2KeyGen1.31”。
一. 运行本程序后,点击“导入模版”,先导入一个ini文件模版(如果要生成单机版的License选择Unified Nexar-Protel
License.ini;要生成网络版的License选择Unified Nexar-Protel Network License.ini),然后修改里面的参数:

1) ransactorName=Your Name(将“Your Name”替换为你想要注册的用户名)

2) SerialNumber=0000000(如果你只有一台计算机,那么这个可以不用修改,如果有两台以上的计算机且连成
局域网,那么请保证每个License文件中的SerialNumber为不同的值,例如:SerialNumber=0000001;
SerialNumber=0000002...)

3) UserCount=x(要生成单机版的License不用修改;要生成网络版的License请修改x为需要受权的用户数量,默
认为1000用户)

其它参数普通用户不必修改。

修改完成后点击“生成协议文件”,【任意输入一个文件名】(文件后缀为.alf)保存,程序会在相应目录中生成1个
License文件。

二. 点击“替换密钥”,选取DXP.exe【注意:是DXP.exe】(在DXP 2004安装目录里,默认路径为C:\Program Files\Altium2004\),程序会
自动替换文件中的公开密钥。如果要使用网络版的License,还必须同时替换DXPSecurityService.exe
(在DXP 2004安装目录里,默认路径为C:\Program Files\Altium2004\)文件中的公开密钥,操作步骤同上。
(对文件修改前请手工做好备份,以防万一。)。此时要把【刚才】生成的文件复制到“C:\Program Files\Altium2004\)”目录下

三. 将用【crack】破解文件生成的License文件拷贝至DXP 2004安装目录里(默认路径为C:\Program Files\Altium2004\)
或者在DXP的使用许可管理中添加生成的License文件,网络版的License文件在
Altium DXP Security Service中。
安装完毕。



步进电机实验
#include<reg51.h> //头文件
#define uchar unsigned int //宏定义,为方便编程
#define uint unsigned int
#define MOTORSTEP P1 //宏定义,定义P1口为步进电机驱动端口
uchar code step[]={0x03,0x09,0x0c,0x06}; //步进电机驱动值数组
v
oid delay() //步进电机每一步间延迟函数
{
uchar i=4000;
while(i--);
}
char code SST516[3] _at_

0x003b; //仿真插入代码
main() //主函数
{
uchar i=0;
while(1)
{
for(i=0;i<4;i++) //4步一个循环
{
MOTORSTEP=step[i]; //取值赋给P1驱动口
delay(); //延迟
}
}
}


程序清单:

# include "reg51.h"

# include "intrins.h"

# define disdata P1

# define discan P3

# define uchar unsigned char

# define uint unsigned int

sbit DQ =P3^7;

sbit DIN =P1^7;

uint h;



uchar code ditab[16]=

{0X00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};

uchar code dis_7[12]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};

uchar code scan_con[4]={0xfb,0xf7,0xef,0xdf};

uchar data temp_data[2]={0x00, 0x00,};

uchar data display[5]={0x00,0x00,0x00,0x00,0x00};



void delay(uint t)

{

for(;t>0;t--);

}

scan()

{

char k;

for(k=0;k<4;k++)

{

disdata=dis_7[display[k]];

if(k==1){DIN=0;}

discan=scan_con[k];delay(90);discan=0xff;

}

}

ow_reset(void)

{

char presence=1;

while(presence)

{

while(presence)

{

DQ=1;_nop_();_nop_();

DQ=0;

delay(50);

DQ=1;

delay(6);

presence=DQ;

}

delay(45);

presence =~DQ;

}

DQ=1;

}



void write_byte(uchar val)

{

uchar i;

for(i=8;i>0;i--)

{

DQ=1;_nop_();_nop_();

DQ=0;_nop_();_nop_();_nop_();_nop_();_nop_();

DQ=val&0x01;

delay(6);

val=val/2;

}

DQ=1;

delay(1);

}



uchar read_byte(void)

{

uchar i;

uchar value=0;

for(i=8;i>0;i--)

{

DQ=1;_nop_();_nop_();

value >>=1;

DQ=0;

_nop_();_nop_();_nop_();_nop_();

DQ=1;_nop_();_nop_();_nop_();_nop_();

if (DQ)value|=0x80;

delay(6);

}

DQ=1;

return(value);

}



read_temp()

{

ow_reset();

write_byte(0xcc);

write_byte(0xbe);

temp_data[0]=read_byte();

temp_data[1]=read_byte();

ow_reset();

write_byte(0xcc);

write_byte(0x44);

}



work_temp()

{

uchar n=0;

if(temp_data[1]>127)

{temp_data[1]=(256-temp_data[1]);

temp_data[0]=(256-temp_data[0]);n=1;}

display[4]=temp_data[0]&0x0f;display[0]=ditab[display[4]];

display[4]=((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4) ;

display[3]=display[4]/100;

display[1]=display[4]%100;

display[2]=display[4]/10;

display[1]=display[4]%10;



if(!display[3]){display[3]=0x0a;

if(!display[2]){display[2]=0x0a;}}

if(n){display[3]=0x0b;}

}



main ()

{

disdata=0xff;

discan=0xff;

for(h=0;h<4;h++){display[h]=8;}

ow_reset();

write_byte(0xcc);

write_byte(0x44);

for(h=0;h<500;h++)

{scan();}

while(1)

{

read_temp();

work_temp();

for(h=0;h<500;h++)

{scan();}

}

}

本程序经调试通过。

五.调试
及性能分析

系统调试以程序为主。硬件调试首先检查电路的焊接是否正确,然后用万用表测试

或通电检测。软件调试以编程序并进行硬件的正确性检验。由于DS18B20与单片机采用串行数据传送,因此,对DS18B20进行读/写编程时必须严格地保证读/写时序,否则将无法读取测量结果。本程序采用单片机C语言编写,用Keil C51编译器编程调试。软件调试到能显示温度值,而且在有温度变化时(例如用手去接触),显示温度能改变就基本完成本设计。


https://www.360docs.net/doc/ac9886740.html,/

相关文档
最新文档