已知某51单片机系统的晶振频率为12MHz,请编写汇编程序,使用定时器T0,采用中断的方式实现20毫秒定时。其中,定时器T0的中断入口地址为000BH。
求出初值是45536,TL0=0E0H,TH0=0B1H,之后汇编程序不太确定
那么计算思路是这样的:
1. 首先要知道1s=1000ms,1ms=1000us。
2. 由公式可得:(216-0)× 12 ÷ 11.0592=71ms,定时时间最大只能算到71ms,而0.5s=500ms,距离需要的时间还差429ms,剩下的怎么办?
3. 所以,这个时候我们需要退一步计算,算个5ms再循环个100次,这样就可以得到5ms*100=500ms(0.5s)。
5ms的定时时间先换算成us单位就是5000us
公式:(216-X)× 12 ÷ 11.0592=5000(us)
得 X=60928
把十进制60928转换为16进制=0xee00,分配高8位TH=0xee,低8位TL=0x00,
初始值这样就算好了。
转换进制不熟练的同学可以用win10自带的计算器进行转换。
#include<reg51.h>
char i=100; //用来循环100次,5ms*100=500ms,500ms=0.5s
void Timer0Init(void) //5毫秒@11.0592MHz 定时器T0 子程序
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x00; //低8位
TH0 = 0xEE; //高8位
//高8位与低8位共同组成初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //允许定时器T0开启中断
EA = 1; //开启总中断
}
void main() //主程序
{
P2=0Xff; //led初始化
Timer0Init(); //调用定时器的初始化子程序
while(1); //等待定时器进入中断
}
void T0_timer0() interrupt 1 //定时器0 进入中断程序
{
TH0=0xEE; //这里需要重新赋初始值,保证每次进入中断函数都是5ms
TL0=0x00;
i--; //i=100开始循环自减
if(i<=0) //判断(i从100减到0的时候就执行下面程序)
{
i=100; //进来就重置循环次数,保证出去可以重新开始计算
P2=~P2; //取反,i从100减到0刚好是0.5s,取反亮一次
} //亮完后i已经等于100,不满足if判断条件,重新开始定时
}
//end
当然,有更方便的计算方式,在烧录软件找到定时计算器,选好定时器、工作方式、时钟以及定时长度(初始值),就能自动得到初始值了
上图四个疑问
1、
定时长度:
看上面公式,我们用到定时器方式一是16位,既216,最大只能算出71ms,我们定时单位是ms的话超出71是没有办法计算的,所以这就是为什么不直接输入500ms的原因。
我们可以输入5ms算出初始值然后循环100次再运行
也可以输入50ms得到初始值循环10次再运行,结果都是一样的。
2、
选择定时器:
定时器0和定时器1都可以选择,只是有优先级设置——通过IP寄存器设定,但只有高和低两种,同等优先级时,先响应定时器0。
只使用一个定时器时,随便选一个就行。
3、
定时器模式:
1.模式分8、13、16位(具体看下表 定时器模式表),因为我们选择了方式一(216),所以在模式中选择16位。
2.自动重载与无自动重载区别:无自动重载(下表方式0和方式1)特点是计数溢出后计数器全为0,在使用循环定时/计数时会影响精度。自动重载就是为了解决该问题而设计的。
注意:89c52是没有 16位重载 的,选择的时候具体要看单片机手册,这里选 16位 即可。
4、
定时器时钟:
标准8051单片机为12T。
STC12系列有1T和12T,具体看芯片手册,这里不多赘述。
另外,软件里面的程序也是可以直接使用的,只是要稍微修改一下。
删除不用的(AURX)
加入开启条件:
ET0 = 1; //允许定时器T0中断。选择定时器1时改为ET1=1;
EA = 1; //开启总中断
(具体可看上面的代码)
用软件里的定时功能计算减去了我们自己写和计算的步骤,方便快捷准确,没用过的可以试一下哦。
定时器模式表:
选择相应的方式:
方式0 :213,(不常用)
方式1 :216 ,(最常用)
方式2 :28,(常用)
方式3 :现在基本上没人用了,稍微了解下即可