从单片机基础到程序框架(全集 2019pdf版).pdf - 第364页

【85.5 定时器 0 的“自身原配开关”TR0。 】 TR0: 定时 器的“ 自身 原配开 关” 。宽度 是 1 位的位 变量。 很多 初学 者会把 EA,ET0 ,TR 0 三者搞 不清 。 定时器可以 工作在 “查询 标志位” 和“中断” 这两种状态,也就是说在没有 中断的情况下 定时器也 可以单独 使用的。TR 0 是定时器 0 自身的发动 引擎,要不 要把这 个发动引擎 所产生的能 量传输到中断 的渠道,则 取决 于中 断开关…

100%1 / 836
【85.3 决定时间长度的寄存器 TH0 TL0。
TH0 TL0,T 代表定时器英文单 TIME T,H 代表高位,L 代表低位,0 代表定时 0。
TH0 一个 8 宽度的寄存器,TL0 也是一 8 宽度的寄存器,两者合并起来成为一个整体,实际
就是一个 16 位宽度的寄存器,TH0 是高 8 位,TL0 是低 8 位,它们合并后的数值范围是:0 65535。该 16
位寄存器取值越大,时中断一次的时间反倒越小,为什么?TH0 TL0 的初始值,就像一个水桶里装的水。
如果这个桶是空桶(取值为 0)“雨水”想把这个桶“滴满溢出”所需要的时间就很大。如果里面已经装了
大半的水(取值为大于 32767)“雨水”想把这个桶“滴满溢出”所需要的时间就很小。这里的关键词“滴
满溢出”的“滴”与“满溢出”“滴”的速度是由单片机晶振决定的,而“满溢出”一次就代表产生一次
断,执行完中断函数在即将返回主函数之前,我们重新装入特定容量的水(重装初值)为下一次的“滴
溢出”做准备,依次循环,从而连续不断地产生间歇的定时中断。
配置中断时间的大小是需要经验的,因为,每次定时中断的时间太长,就意味着时间的可分度太粗,
如果每次定时中断的时间太短,则会产生很频繁的中断势必会影响主函数 main()的执行效率,而且累记中
断次数的时间误差也会增大。因此,配置中断时间是需要经验的,根据经验,定时中断取 1ms 一次,是几
所有单片机项目的最佳选择,按我的理解,“1ms 定时中断一次”已经是单片机界公认的一种“标配
要配置 1ms 定时中断,TH0 TL0 如何取值?刚才提到一个形象的例子“桶,滴,满溢出”。TH0 TL0
的最大取值范围是 65535,可以理解成为最 65535“滴”如果超过 65535“滴”(比如 1“滴”后变成 65536
“滴”)就会“满溢出”从而产生一次中断(65536 是中断发生的临界值)“滴一次的时间”就刚好是单
片机执行“一次单指令的时间”“一次单指令的时间”等 12 个晶振周期,比如 12MHz 晶振,晶振周期
是(1/12000000)秒,而“一次单指令的时间”就等于 12 乘以(1/12000000)秒,等于 0.000001 秒,也就
1us。1us滴”一次,要产生 1ms 的时间就需要“滴”1000 “满溢出”的前提条件是“桶里”一共需
要装 65536 才溢出,因此,在 12MHz 晶振下要产生 1ms 的定时中断,TH0 TL0 的初值应该是 64536
(65536 减去 1000 等于 64536),而 64536 变成十六进 0xfc17,再分解到 8 TH0 0xfc,低 8 TL0
0x17。
刚才的例子是假如晶振在 12MHz 的情况下所计算出来的结果,而本教程所用的晶振是 11.0592MHz,根据
11.0592MHz 产生 1ms 的定时中断,TH0 TL0 应该取值多少?根据刚才的计算方式:
初值=[溢出值]-([0.001 秒]/([晶振周期的 12 个]*([1 秒]/[晶振频率])))
初值=65536-(0.001/(12*(1/11059200)))
初值=65536-922 (注:922 921.6 的四舍五入)
初值=64614
初值=0xfc66
初值 TH0=0xfc
初值 TL0=0x66
【85.4 中断的总开关 EA 与局部开关 ET0。
EA:中断的总开关。宽度是 1 位的位变量。此开关如果取 0,就会强行屏蔽所有的中断,因此,只要用
到中断,此开关必须取 1。
ET0门针 0 的局 1 位变关如 0会屏 0
的中断,如果取 1 允许定时器 0 中断。如果要定时器 0 产生中断,那么总开关 EA ET0 必须同时都
开(都取 1),两者缺一不可。
【85.5 定时器 0 的“自身原配开关”TR0。
TR0:定时器的“自身原配开关”。宽度 1 位的位变量。很多初学者会把 EA,ET0,TR0 三者搞不清
定时器可以工作在“查询标志位”和“中断”这两种状态,也就是说在没有中断的情况下定时器也可以单独
使用的。TR0 是定时器 0 自身的发动引擎,要不要把这个发动引擎所产生的能量传输到中断的渠道,则取决
于中断开关 EA ET0。TR0 源头开关,EA 中断总渠道开关,ET0 中断分支渠道的定时 0 关。TR0
1 表示启动定时器 0,取 0 表示关闭定时器 0。
【85.6 定时器 0 的中断函数的书写格式。
void 函数名() interrupt 1
{
...中断程序内容;
...此处省去若干代码
...中断程序内容;
...最后面的代码,要记得重装 TH0 TL0 的初值;
}
函数名可以随便取,只要不是编译器已经征用的关键字。这里的 1 是定时器 0 的中断号。不同的中断号
代表不同类型的中断,至于哪类中断对应哪个中断号,大家可以查找相关书籍和资料。本节用的定时器 0
于工作方式 1 的情况下,在即将退出中断之前,需要重装 TH0 TL0 的初始值。
【85.7 寄存器的名字来源。
前面讲的寄存器都有固定的名字,而且这些名字都是唯一的,拼写的时候少一个字母或者多一个字母,
C 编译器都会报错不让你通过,因此问题来了,初学者刚接触一款单片机的时候,如何知道某个寄存器它
定的唯一的名字?有两个来源。
第一个来源,可以打开 C 译器的某个头文件(.h 格式)查看这些寄存器的名字。比如 51 单片机可以
REG52.H 这个文件打开 REG52.H 这个件? keil 编辑界面选中 REG52.H
这几个字符,在右键弹出的菜单下点击 Open ducument“REG52.H”即可。
第二个来源是直接参考一些现成的范例程序这些范例程序网上很多,有的是原厂提供的有的是热心
网友的分享,有的是技术书籍或者学习板开发板厂家提供的
【85.8 如何快速配置寄存器。
建议一边阅读芯片的数据手册,一边参考一些现成的范例程序,这些范例程序网上很多有的是原厂提
供的,有的是热心网友的分享,有的是技术书籍或者学习板开发板厂家提供的。
【85.9 练习例程。
现在编写一个定时中断程序,让两个 LED 灯闪烁,一个是在主函数里用累计主循环次数的方式实现(P0.0
控制)另一个是在定时中断函数里用累计定时中断次数的方式实现P0.1 控制)这两个闪烁的 LED 灯,
个在 main 函数,一个是在中断函数,两路任务互不干涉独立运行,并行处理的“雏形”略显出来。
85.9.1 灌入式驱动 8 LED
#include "REG52.H"
#define CYCLE_SUM 5000 //主循环的次
#define INTERRUPT_SUM 500 //中断的次数
sbit P0_0=P0^0; //在主循环里 LED
sbit P0_1=P0^1; //在定时中断里的 LED
unsigned char Gu8CycleStep=0;
unsigned long Gu32CycleCnt=0; //累计主循环的计数
unsigned char Gu8InterruptStep=0;
unsigned long Gu32InterruptCnt=0; //累计定时中断次数的计数
void main()
{
TMOD=0x01; //设置定时器 0 为工作方式 1
TH0=0xfc; //产生 1ms 中断的 TH0 初始
TL0=0x66; //产生 1ms 中断的 TL0 初始
EA=1; //开总中断
ET0=1; //允许定时 0 的中断
TR0=1; //启动定时 0 的中断
while(1) //主循环
{
switch(Gu8CycleStep)