单片机定时器汇编
单片机汇编语言经典一百例

51单片机实用程序库4.1 流水灯程序介绍:利用P1 口通过一定延时轮流产生低电平输出,以达到发光二极管轮流亮的效果。
实际应用中例如:广告灯箱彩灯、霓虹灯闪烁。
程序实例(LAMP.ASM)ORG 0000HAJMP MAINORG 0030HMAIN:9MOV A,#00HMOV P1,A ;灭所有的灯MOV A,#11111110BMAIN1:MOV P1,A ;开最左边的灯ACALL DELAY ;延时RL A ;将开的灯向右边移AJMP MAIN ;循环DELAY:MOV 30H,#0FFHD1: MOV 31H,#0FFHD2: DJNZ 31H,D2DJNZ 30H,D1RETEND4.2 方波输出程序介绍:P1.0 口输出高电平,延时后再输出低电平,循环输出产生方波。
实际应用中例如:波形发生器。
程序实例(FAN.ASM):ORG 0000HMAIN:;直接利用P1.0口产生高低电平地形成方波////////////// ACALL DELAYSETB P1.0ACALL DELAY10CLR P1.0AJMP MAIN;////////////////////////////////////////////////// DELAY:MOV R1,#0FFHDJNZ R1,$RETEND五、定时器功能实例5.1 定时1秒报警程序介绍:定时器1每隔1秒钟将p1.o的输出状态改变1 次,以达到定时报警的目的。
实际应用例如:定时报警器。
程序实例(DIN1.ASM):ORG 0000HAJMP MAINORG 000BHAJMP DIN0 ;定时器0入口MAIN:TFLA G EQU 34H ;时间秒标志,判是否到50个0.2秒,即50*0.2=1秒MOV TMOD,#00000001B;定时器0工作于方式1MOV TL0,#0AFHMOV TH0,#3CH ;设定时时间为0.05秒,定时20次则一秒11SETB EA ;开总中断SETB ET0 ;开定时器0中断允许SETB TR0 ;开定时0运行SETB P1.0LOOP: AJMP LOOPDIN0:;是否到一秒//////////////////////////////////////// INCC: INC TFLAGMOV A,TFLAGCJNE A,#20,REMOV TFLAG,#00HCPL P1.0;////////////////////////////////////////////////// RE:MOV TL0,#0AFHMOV TH0,#3CH ;设定时时间为0.05秒,定时20次则一秒RETIEND5.2 频率输出公式介绍:f=1/ts51 使用12M晶振,一个周期是1微秒使用定时器1工作于方式0,最大值为65535,以产生200HZ的频率为例:200=1/t:推出t=0.005 秒,即5000 微秒,即一个高电12平或低电平的时间为2500 微秒。
单片机延时500ms程序汇编

单片机延时500ms程序汇编一、概述在单片机编程中,延时操作是非常常见且重要的一部分。
延时可以使程序在执行过程中暂停一段时间,以确保输入输出设备能够正常工作,或者是为了保护其他设备。
本文将介绍如何使用汇编语言编写单片机延时500ms的程序。
二、延时原理在单片机中,延时操作通常通过循环来实现。
每个循环需要一定的时间,通过控制循环次数和循环体内的指令数量,可以实现不同长度的延时。
在汇编语言中,可以使用计数器来控制循环次数,从而实现精确的延时操作。
三、汇编语言编写延时程序接下来,我们将使用汇编语言编写延时500ms的程序。
1. 设置计数器初值在程序的开头我们需要设置计数器的初值,这个初值需要根据单片机的工作频率和所需的延时时间来计算。
假设单片机的工作频率为1MHz,那么在循环500次后,就能够达到500ms的延时。
我们需要将计数器的初值设为500。
2. 循环计数接下来,我们进入一个循环,在循环中进行计数操作。
每次循环结束时,都需要检查计数器的值,当计数器减至0时,表示已经达到了500ms的延时时间,可以退出循环。
3. 优化程序为了提高程序的执行效率,可以对计数器进行优化。
例如可以通过嵌套循环的方式,减少循环的次数,从而提高延时的精度和稳定性。
四、程序示例下面是一个简单的示例程序,演示了如何使用汇编语言编写延时500ms的程序。
```org 0x00mov r2, #500 ; 设置计数器初值为500delay_loop:djnz r2, delay_loop ; 进行计数ret ; 延时结束,退出程序```五、结语通过以上的示例程序,我们可以看到如何使用汇编语言编写单片机延时500ms的程序。
当然,实际的延时程序可能会更加复杂,需要根据具体的单片机型号和工作频率进行调整,但是思路是相似的。
在实际的编程中,需要根据具体的需求和硬件环境来进行调整和优化,以实现更加稳定和精确的延时操作。
希望本文对单片机延时程序的编写有所帮助,也欢迎大家在评论区提出宝贵意见和建议。
单片机定时器程序编写

单片机定时器程序编写单片机的定时器要用到中断机制,所以在编写程序时要先开启中断,设置中断优先级和中断服务函数,然后再配置定时器。
以下是编写单片机定时器程序的步骤:1.开启中断:要想使用定时器,必须开启单片机的中断功能,可使用如下命令开启:` __enable_irq(;`。
该函数将开启全局中断。
2.设置中断优先级:中断优先级用于解决多个中断同时发生时的执行顺序问题。
一般来说,定时器中断的优先级比较低,因为可能同时有其他更重要的中断需要执行。
`NVIC_SetPriority(TIMER某_IRQn, 2);`。
上面命令将设置定时器的中断优先级为2。
3.定义中断服务函数:中断服务函数是中断发生时自动执行的一段程序。
每种中断都需要一个相应的中断服务函数。
```。
void TIMER某_IRQHandler(void)。
//中断处理程序。
}。
```。
上面代码定义了一个定时器中断服务函数。
4.配置定时器:配置定时器的过程包括选择时钟源、设定计数值、选择计数方向等。
这里我们选择外部时钟源和计数器模式。
```。
//打开定时器时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM某, ENABLE);。
//定时器参数设置。
TIM_TimeBaseInitTypeDef TIM_InitStruct;。
TIM_InitStruct.TIM_Prescaler = 16; // 预分频值。
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式。
TIM_InitStruct.TIM_Period = 999; // 溢出值。
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;。
TIM_TimeBaseInit(TIM某, &TIM_InitStruct); // 设置定时器参数。
单片机原理及应用教程(C语言版)-第6章 MCS-51单片机的定时器计数器

6.1.1 单片机定时器/计数器的结构
MCS-51单片机定时器/计数器的原理结构图
T0(P3.4) 定时器0 定时器1 T1(P3.5) 定时器2 T2EX(P1.1)
T2(P1.0)
TH0
溢 出 控 制
TL0
模 式 溢 出
TH1
控 制
TL1
模 式 溢 出
TH2
TL2
重装 捕获
RCAP 2H
RCAP 2L
6.2.2 T0、T1的工作模式
信号源 C/T设为1,为计数器,用P3.4引脚脉冲 C/T设为0,为定时器,用内部脉冲 运行控制 GATE=1,由外部信号控制运行 此时应该设置TR0=1 P3.2引脚为高电平,T0运行 GATE=0, 由内部控制运行 TR0设置为1,T0运行
6.2.2 T0、T1的工作模式
6.2.3 T0、T1的使用方法
例6-1 对89C52单片机编程,使用定时器/计 数器T0以模式1定时,以中断方式实现从P1.0引 脚产生周期为1000µ s的方波。设单片机的振荡频 率为12MHz。 分析与计算 (1)方波产生原理 将T0设为定时器,计算出合适的初值,定 时到了之后对P1.0引脚取反即可。 (2)选择工作模式 计算计数值N
6.2.1 T0、T1的特殊功能寄存器
TR1、TR0:T1、T0启停控制位。 置1,启动定时器; 清0,关闭定时器。
注意: GATE=1 ,TRx与P3.2(P3.3)的配合控制。
IE1、IE0:外部中断1、0请求标志位 IT1、IT0:外部中断1、0触发方式选择位
6.2.2 T0、T1的工作模式
6.2.1 T0、T1的特殊功能寄存器
GATE=0,禁止外部信号控制定时器/计数器。 C/T——定时或计数方式选择位 C/T=0,为定时器;C/T=1,为计数器 计数采样:CPU在每机器周期的S5P2期间,对 计数脉冲输入引脚进行采样。
51单片机定时器计数器汇编实验报告

批阅长沙理工大学实验报告年级光电班号姓名同组姓名实验日期月日指导教师签字:批阅老师签字:内容一、实验目的四、实验方法及步骤二、实验原理五、实验记录及数据处理三、实验仪器六、误差分析及问题讨论单片机定时器/计数器实验一、实验目的1、掌握51单片机定时器/计数器的基本结构。
2、掌握定时器/计数器的原理及编程方法。
二、实验仪器1、装有keil软件的电脑2、单片机开发板三、实验原理51单片机有2个16位的定时器/计数器,分别是T0和T1,他们有四种工作方式,现以方式1举例。
若定时器/计数器0工作在方式1,计数器由TH0全部8位和TL0全部8位构成。
方式1作计数器用时,计数范围是:1-65536(2^16);作定时器用时,时间计算公式是:T=(2^16-计数初值)×晶振周期×12。
四、实验内容1、计算计数初值单片机晶振频率为6MHz,使用定时器0产生周期为120000μs等宽方波连续脉冲,并由P1.0输出。
设待求计数初值为x,则:(2^16-x)×2×10^-6 = 120000×10^-6解得x=5536。
二进制表示为:00010101 10100000B。
十六进制为:高八位(15H),低八位(A0H)。
2、设置相关控制寄存器TMOD设置为xxxx0001B3、程序设计ORG 0000HAJMP MAINORG 30HMAIN: MOV P1,#0FFH ;关闭所有灯ANL TMOD,#0F0H ;置定时器0工作方式1ORL TMOD,#01H ;不影响T1的工作MOV TH0,#15H ;设置计数初始值MOV TL0,#0A0HSETB EA ;CPU开中断SETB ET0 ;定时器0开中断SETB TR0 ;定时器开始运行LOOP: JBC TF0,INTP ;如果TF0=1,则清TF0并转到INTPAJMP LOOP ;然跳转到LOOP处运行INTP: MOV TH0,#15H ;重新设置计数初值MOV TL0,#0A0HCPL P1.0 ;输出取反AJMP LOOPEND AJMP LOOPEND4、实验仿真新建工程项目文件中,并为工程选择目标器件为AT公司的AT89S51。
mcs-51单片机中汇编程序延时的精确算法。

MCS-51单片机中汇编程序延时的精确算法一、引言MCS-51单片机是一种常用的微控制器,其汇编程序编写对于工程师来说是极为重要的。
在MCS-51单片机中,延时是一种常见的需求,通过延时可以控制程序的执行速度和时间间隔。
而对于汇编程序中的延时算法,精确度的要求往往较高,特别是在一些实时系统中。
本文将针对MCS-51单片机中汇编程序延时的精确算法展开论述。
二、延时的需求在MCS-51单片机中,实现一定时间的延时是非常常见的需求。
在控制LED灯的闪烁过程中,需要一定的时间间隔来控制LED的亮灭频率;在读取传感器数据的过程中,需要一定的时间延时以确保传感器数据的准确性。
精确和可控的延时算法对于MCS-51单片机的应用来说是至关重要的。
三、常见的延时算法在MCS-51单片机的汇编程序中,常见的延时算法包括循环延时、定时器延时和脉冲宽度调制(PWM)延时等。
这些延时算法各有优缺点,需要根据具体的应用场景选择合适的算法。
1. 循环延时循环延时是一种简单而粗糙的延时算法,其原理是通过空转循环来消耗一定的CPU周期来实现延时。
这种延时算法的缺点是精度较差,受到CPU主频和编译器优化等因素的影响较大,不适合对延时精度有较高要求的场景。
2. 定时器延时定时器延时是一种利用MCS-51单片机内部定时器来实现延时的算法。
通过设置定时器的初值和计数方式,可以实现一定范围内的精确延时。
定时器延时的优点是精度高,不受CPU主频影响,适用于对延时精度要求较高的场景。
3. 脉冲宽度调制(PWM)延时脉冲宽度调制(PWM)延时是一种通过调节脉冲信号的宽度来实现延时的算法。
这种延时算法在一些特定的应用场景中具有较高的灵活性和精度。
例如在直流电机的速度调节过程中常常会采用PWM延时算法来实现精确的速度控制。
四、精确延时算法针对MCS-51单片机中汇编程序延时的精确算法,我们可以结合定时器延时和脉冲宽度调制(PWM)延时的优点,设计一种精确度较高的延时算法。
单片机汇编语言设计软件延时程序

单片机汇编语言设计软件延时程序引言:在单片机编程中,经常需要使用延时函数来控制程序的执行时间,例如等待外设初始化完成、延迟发送数据等。
本文将介绍使用汇编语言设计的延时函数。
一、延时原理在单片机中,延时的实现主要通过定时器或循环计数的方式来实现。
定时器通常会使用内部时钟源来产生时钟信号,然后通过预设的计数值来控制定时时间。
循环计数方式则是通过程序在指定循环内部执行空操作的次数来实现延时。
二、定时器延时定时器延时的实现比较简单,只需要设置定时器的计数值和相关控制寄存器即可。
1.使用定时器0延时定时器0是一种常用的定时器,可通过T0计数器、定时器控制寄存器TCON和定时器模式控制寄存器TMOD来实现。
例如,以下是一个使用定时器0的延时函数的实现示例:```assemblydelay_us PROCMOV R4,16 ; 假设使用的是12MHz的晶振,所以每个机器周期为1/12MHz=83.33ns,16个机器周期为1.33usMOVR5,FFH;设置循环的次数delay_usroutine:NOP;执行空操作,延时一个机器周期DJNZ R5,delay_usroutine ;循环R5次RETdelay_us ENDPdelay_ms PROCMOV R7,4 ; 延时1ms需要延时四次1usLOOP:CALL delay_usDJNZR7,LOOPRETdelay_ms ENDP```在上述代码中,delay_us过程使用了16次空操作进行延时,该延时约为1.33us。
delay_ms过程通过循环调用delay_us过程实现了1ms的延时。
2.使用定时器1延时定时器1是使用T1计数器、定时器控制寄存器TCON和定时器模式控制寄存器TMOD来实现的。
例如,以下是一个使用定时器1的延时函数的实现示例:```assemblydelay_us PROCMOV R4,16 ; 假设使用的是12MHz的晶振,所以每个机器周期为1/12MHz=83.33ns,16个机器周期为1.33usMOVR5,FFH;设置循环的次数delay_usroutine:NOP;执行空操作,延时一个机器周期DJNZ R5,delay_usroutine ;循环R5次RETdelay_us ENDPdelay_ms PROCMOV R7,4 ; 延时1ms需要延时四次1usLOOP:CALL delay_usDJNZR7,LOOPRETdelay_ms ENDP```在上述代码中,delay_us过程使用了16次空操作进行延时,该延时约为1.33us。
PIC单片机定时器代码

PIC 单片机定时器代码#include <pic.h>/*#define PORTAIT(add,bit)((unsigned)(&add)*8+(bit))static bit PORTA_0 @PORTAIT(PORTA,0);//PIC16F84Astatic bit PORTA_1 @PORTAIT(PORTA,1);static bit PORTA_2 @PORTAIT(PORTA,2);static bit PORTA_3 @PORTAIT(PORTA,3);static bit PORTA_4 @PORTAIT(PORTA,4);*/unsigned int ttr=0;// 无符号整型变量ttr ,并赋值0unsigned char x=0,y=0,sign_a=0;// 无符号字符型变量void key_server(); // 键值服务函数void display(unsigned int x);// 带形参的显示函数void display_set(unsigned int x);// 键值显示函数void delay_1m(); // 按键延时函数-1mvoid delay(unsigned long int k ) // 延时函数{unsigned long int i; // 无符号字符型变量ifor(i=0;i<=k;i++) // rov 语句continue; // 继续循环}void display(unsigned int x)// 带形参X 的显示函数(开始){unsigned int d=49,unit_bit,ten_bit,hund_bit,thou_bit;// 无符号整型变量 d 和位(个、十、百、千) unsigned char SEG7[10]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 并初始化unit_bit=x%10; // picc 编译器可识别的个位ten_bit=x/10%10; // picc 可识别的十位hund_bit=x/100%10; // picc 可识别的百位thou_bit=x/1000%10; // picc 可识别的千位while(d>0) // while 语句{PORTA=0x1f; //关显示PORTB=SEG7[unit_bit]; // 个位段码送 B 口RA3=0; // 显示个位delay(200); // 延时RA3=1; // 关个位显示delay(2); // 延时PORTB=SEG7[ten_bit]; //十位段码送 B 口RA2=0; // 显示十位delay(200); // 延时RA2=1; // 关十位显示delay(2); // 延时PORTB=SEG7[hund_bit]; //百位段码送 B 口RA1=0; // 显示百位delay(200); // 延时RA1=1; // 关百位显示delay(2); // 延时PORTB=SEG7[thou_bit]; // 千位段码送 B 口RA0=0; // 显示千位delay(200); /// 延时RA0=1; // 关百位显示delay(2); // 延时d--; // d 从2900 开始自减量if( RA4==0) // K1 按下?{ // 未按下退出执行上程序while(1){if( RA4==1) //按下,执行以下程序{sign_a=1; d=0;break; // 跳出循环} } } } } void main( ) // 主程序{TRISB=0x00; // A 口初始化TRISA=0x10;PORTB=0x40; INTCON=0x00;//PORTA=0x10;ttr=0; // 给ttr 赋值0while(1) // while 循环语句开始{while(x<24) // 限制时钟最大为24(时) {y=0; //给y赋值0while(y<60) // 限制时钟最大60(分){ttr=x*100+y; // 算术运算符表达式display(ttr); // 调显示函数key_server(); // 调键值服务程序y++; //分(y)自增量ttr=0; // 给ttv 赋值0}x++; //时(X)自增量}x=0; //给X 赋值0y=0; // 给Y 赋值0}}void key_server()// 键值服务程序{unsigned char k=0; // 记录按键次数变量unsigned int value=0; // 存储显示值变量while(sign_a==1){display_set(value); // 调键值显示函数if((RA4==0)&&(k==0)) //第一次按下K1 {while(1) // 设定时钟的分值{y++; // K1 未放开,分从0~59 累加if(y>59)y=0; // 分值大于59,Y 清0 value=x*100+y;//将X (时)和Y (分)按显示格式display_set(value); // 整合计算,再显示delay_1m(); // 按键延时,以便观察if(RA4==1) // 如果K1 放开{ // 进入小时设定,K=1k=1; // 小时设定开始break; // 跳出分钟设定循环}}}if((RA4==0)&&(k==1))// 第二次按下K1{ // K=1 ,进入小时设定循环x++;// 24 小时制,K1 未放开,X 一直累加到23 if(x>23) // X>23 ,X 清0x=0;value=x*100+y;// 整合计算设定值display_set(value); // 调键值显示delay_1m(); // 延时display_set(value); // 调键值显示while(1) // 重复{x++;if(x>23)x=0;value=x*100+y;display_set(value);delay_1m();display_set(value);if(RA4==1) // 如果K1 放开{sign_a=0; // 清0 设定时间标志位y=y-1;break; // 跳出设定循环返回}}}}}void display_set(unsigned int x)// 键值显示程序{thou_bit;unsigned char SEG7[10]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // 这里的注释与显示displa 的函数相似unit_bit=x%10;ten_bit=x/10%10;hund_bit=x/100%10;thou_bit=x/1000%10;while(d>0){PORTA=0x1F; //63;PORTB=SEG7[unit_bit];RA3=0;delay(200);RA3=1;delay(2);PORTB=SEG7[ten_bit];RA2=0;delay(200);RA2=1;delay(2);PORTB=SEG7[hund_bit];RA1=0;delay(200);RA1=1;delay(2);PORTB=SEG7[thou_bit];RA0=0;delay(200);RA0=1;delay(2);d--;}}void delay_1m()//按键K1,延时函数开始{unsigned long int k; // 说明语句for(k=0;k<4;k++) // for 语句{display_set(x*100+y); // 调键值显示函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
我们在学单片机时我们第一个例程就是灯的闪烁,那是用延时程序做的,现在回想起来,这样做不很恰当,为什么呢我们的主程序做了灯的闪烁,就不能再干其它的事了,难道单片机只能这样工作吗当然不是,我们能用定时器来实现灯的闪烁的功能。
例1:查询方式ORG 0000H
AJMP START
ORG 30H
START: MOV P1,#0FFH ;关所灯
MOV TMOD,#00000001B ;定时/计数器0工作于方式1
MOV TH0,#15H
MOV TL0,#0A0H ;即数5536
SETB TR0 ;定时/计数器0开始运行
LOOP: JBC TF0,NEXT ;如果TF0等于1,则清TF0并转NEXT处(LOOP:JNB TF0,$) AJMP LOOP ;不然跳转到LOOP处运行
NEXT: CPL
MOV TH0,#15H
MOV TL0,#9FH;重置定时/计数器的初值
AJMP LOOP
END
键入程序,看到了什么灯在闪烁了,这可是用定时器做的,不再是主程序的循环了。
简单地分析一下程序,为什么用JBC呢TF0是定时/计数器0的溢出标记位,当定时器产生溢出后,该位由0变1,所以查询该位就可知宇时时间是否已到。
该位为1后,要用软件将标记位清0,以便下一次定时是间到时该位由0变1,所以用了JBC指令,该指位在判1转移的同时,还将该位清0.以上程序是能实现灯的闪烁了,可是主程序除了让灯闪烁外,还是不能做其他的事啊!不对,我们能在LOOP:……和AJMP LOOP指令之间插入一些指令来做其他的事情,只要保证执行这些指令的时间少于定时时间就行了。
那我们在用软件延时程序的时候不是也能用一些指令来替代DJNZ吗是的,但是那就要求你精确计算所用指令的时间,然后再减去对应的DJNZ循环次数,很不方便,而现在只要求所用指令的时间少于定时时间就行,显然要求低了。
当然,这样的办法还是不好,所以我们常用以下的办法来实现。
程序2:用中断实现
ORG 0000H
AJMP START
ORG 000BH ;定时器0的中断向量地址
AJMP TIME0 ;跳转到真正的定时器程序处
ORG 30H
START: MOV P1,#0FFH ;关所灯
MOV TMOD,#00000001B ;定时/计数器0工作于方式1
MOV TH0,#15H
MOV TL0,#0A0H ;即数5536
SETB EA ;开总中断允许
SETB ET0 ;开定时/计数器0允许
SETB TR0 ;定时/计数器0开始运行
SJMP $
;LOOP: AJMP LOOP ;真正工作时,这里可写任意程序
TIME0:
PUSH ACC ;定时器0的中断处理程序
PUSH PSW ;将PSW和ACC推入堆栈保护
CPL
MOV TH0,#15H
MOV TL0,#0A0H ;重置定时常数
POP PSW
POP ACC
RETI
END
上面的例程中,定时时间一到,TF0由0变1,就会引发中断,CPU将自动转至000B处寻找程序并执行,由于留给定时器中断的空间只有8个字节,显然不足以写下所有有中断处理程序,所以在000B处安排一条跳转指令,转到实际处理中断的程序处,这样,中断程序能写在任意地方,也能写任意长度了。
进入定时中断后,首先要保存当前的一些状态,程序中只演示了保存存ACC和PSW,实际工作中应该根据需要将可能会改变的单元的值都推入堆栈进行保护(本程序中实际不需保存护任何值,这里只作个演示)。
上面的两个单片机程序运行后,我们发现灯的闪烁非常快,根本分辨不出来,只是视觉上感到灯有些晃动而已,为什么呢我们能计算一下,定时器中预置的数是5536,所以每计60000个脉冲就是定时时间到,这60000个脉冲的时间是多少呢我们的晶体震荡器是12M,所以就是60000微秒,即60毫秒,因此速度是非常快的。
如果我想实现一个1S的定时,该怎么办呢在该晶体震荡器濒率下,最长的定时也就是65。
536个毫秒啊!上面给出一个例程。
ORG 0000H
AJMP START
ORG 000BH ;定时器0的中断向量地址
AJMP TIME0 ;跳转到真正的定时器程序处
ORG 30H
START: MOV P1,#0FFH ;关所灯
MOV 30H,#00H ;软件计数器预清0
MOV TMOD,#00000001B ;定时/计数器0工作于方式1
MOV TH0,#3CH
MOV TL0,#0B0H ;即数15536
SETB EA ;开总中断允许
SETB ET0 ;开定时/计数器0允许
SETB TR0 ;定时/计数器0开始运行
SJMP $
;LOOP: AJMP LOOP ;真正工作时,这里可写任意程序
TIME0: ;定时器0的中断处理程序
PUSH ACC
PUSH PSW ;将PSW和ACC推入堆栈保护
INC 30H
MOV A,30H
CJNE A,#20,T_RET ;30H单元中的值到了20了吗
T_L1: CPL ;到了,取反P10
MOV 30H,#0 ;清软件计数器
T_RET: MOV TH0,#15H
MOV TL0,#9FH ;重置定时常数
POP PSW
POP ACC
RETI
END
先自己分析一下,看看是怎么实现的这里采用了软件计数器的概念,思路是这样的,先用定时/计数器0做一个50毫秒的定时器,定时是间到了以后并不是立即取反P10,而是将软件计数器中的值加1,如果软件计数器计到了20,就取反P10,并清掉软件计数器中的值,不然直接返回,这样,就变成了20次定时中断才取反一次P10,因此定时时间就延长了成了20*50即1000毫秒了。
这个思路在工程中是非常有用的,有的时候我们需要若干个定时器,可51中总共才有2 个,怎么办呢其实,只要这几个定时的时间有一定的公约数,我们就能用软件定时器加以实现,如我要实现口所接灯按1S每次,而口所接灯按2S每次闪烁,怎么实现呢对了我们用两个计数器,一个在它计到20时,取反P10,并清零,就如上面所示,另一个计到40取反P11,然后清0,不就行了吗这部份的程序如下
ORG 0000H
AJMP START
ORG 000BH ;定时器0的中断向量地址
AJMP TIME0 ;跳转到真正的定时器程序处
ORG 30H
START: MOV P1,#0FFH ;关所灯
MOV 30H,#00H ;软件计数器预清0
MOV TMOD,#00000001B ;定时/计数器0工作于方式1
MOV TH0,#3CH
MOV TL0,#0B0H ;即数15536
SETB EA ;开总中断允许
SETB ET0 ;开定时/计数器0允许
SETB TR0 ;定时/计数器0开始运行
SJMP $
;LOOP: AJMP LOOP ;真正工作时,这里可写任意程序
TIME0: ;定时器0的中断处理程序
PUSH ACC
PUSH PSW ;将PSW和ACC推入堆栈保护
INC 30H
INC 31H ;两个计数器都加1
MOV A,30H
CJNE A,#20,T_NEXT ;30H单元中的值到了20了吗
T_L1: CPL ;到了,取反P10
MOV 30H,#00H;清软件计数器
T_NEXT: MOV A,31H
CJNE A,#40,T_RET ;31h单元中的值到40了吗
T_L2: CPL
MOV 31H,#0 ;到了,取反P11,清计数器,返回
T_RET: MOV TH0,#15H
MOV TL0,#9FH ;重置定时常数
POP PSW
POP ACC
RETI
END
您能用定时器的办法实现前面讲的流水灯吗试试看。