概述
定时器/计数器
51的定时器/计数器有2个分别是T1和T0,52系列的单片机有3个定时器/计数器,T0和T1是通用定时器/计数器,定时器/计数器2(简称T2)是集定时、计数和捕获三种功能于一体,功能更强。
首先看一下这个简单点的功能,我在实验中用到的定时器的作用是高精度延时的作用,之前使用的通过while和for循环的延时方法都只是大概的时间,而定时器则可以精确设定时间在1微秒(10^-6)左右(以晶振频率为11.0592MHZ来说),其最大的时间取值为0.071,可见已经可以达到钟表的误差水准了。
定时器/计数器0和1的方式控制寄存器TMOD:
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
TMOD | GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
T1和T0分别代表单片机两个计数器
GATE:门控制位。当门控制位GATE=1时,定时器/计数器的运行受外部引脚输入电平的控制。其中INT0引脚控制T0,INT1引脚控制T1.当控制引脚为高电平且TR0或TR1置1时,相应的定时器/计数器才被选通。当门控制位GATE=0时,只要TR0或TR1置1,相应的定时器/计数器就被选通,此时不受外部引脚的控制。
C/T:该位为0的时候,用作定时器,该位为1的时候,用做计数器。
M1 | M0 | 工作模式 | 功能说明 |
0 | 0 | 模式0 | 13位定时器/计数器 |
0 | 1 | 模式1 | 16为定时器/计数器 |
1 | 0 | 模式2 | 自动重新装入的8位定时器/计数器 |
1 | 1 | 模式3 | T0分成两个8位计数器,T1停止计数 |
模式1:16位的计数器。(TH1,TL1)
模式2:自动装载8位计数器。主要应用在串口波特率发生器。
模式3:将16位计数器分成两个独立的8位计数器TL0和TH0.定时器/计数器的工作模式3只适用于 T0.
模式0&模式3:几乎不用。
特殊功能寄存器TCON
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
TCON | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
溢出标志位TF1/TF0:当定时器T1/T0溢出时,硬件自动将TF0/TF1置1,并申请中断。当进入中断服务程序时,硬件又将自动清零TF1/TF0.
启/停控制位TR1/TR0:该位由软件置位和复位。当GATE为0时,TR0/TR1置位为1时T0/T1开始计数,TR1/TR0复位为0时T1/T0停止计数;当GATE为1时,TR1/TR0为1时且INT1/INT0输入高电平时,T1/T0开始计数。
TCON和TMOD复位后都会自动变成0x00.
T2的控制寄存器T2CON和T2MOD及其程序访问
1、控制寄存器T2CON
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
T2CON | TF2 | EXF2 | RCLK | TCLK | EXEN2 | TR2 | C/T | CP/RL2 |
C/T2(D1):定时器/计数器2的定时或计数功能选择位。当C/T2=1时,选择计数器工作方式,下降沿触发,计数脉冲来自于外引脚T2CLK;当C/T2=0时,选择为定时器工作方式,做波特率发生器是,对f(osc)/2计数,不做波特率发生器时,对f(osc)/12计数。C/T2位须由软件置位或复位。
TR2(D2):定时器/计数器2的启动停止控制位。当软件置位TR2为1时,启动T2开始计数;复位TR2为0时,停止计数。
EXEN2(D3):定时器/计数器2的 外部触发允许标志位。当EXEN2=1时,如果T2不是正在工作在串口通信端口的时钟,则在T2EX引脚(P1.1)上的负跳变将触发捕获或重新再装入,并置EXF2位为1,请求中断;当EXEN2=0时,在T2EX引脚(P1.1)上的负跳变对T2不起作用。
TCLK(D4):串行口发送时钟标志位。当TCLK=1时,串行通信端使用T2的回0溢出信号作为串行口1和3的发送时钟;当TCLK=0时,使用T1的回0溢出信号作为发送时钟。TCLK位须由软件置位或复位。
RCLK(D5):串行口接受时钟标志位。当RCLK=1时,串行口通信端使用T2的回0溢出信号作为串行口1和3的接收时钟;当RCLK=0时,使用T1的回0溢出脉冲作为接收时钟。RCLK位须由软件置位或复位。
EXF2(D6):定时器/计数器2回外部中断请求标志位。当EXEN2=1时且T2EX引脚上出现负跳变而引起捕获或重新再装入时,则EXEN2置位,并向CPU申请中断,此时若允许T2中断,CPU将响应中断,并转向中断服务程序,EXF2也必须由软件复位。
TF2(D7):定时器/计数器2的溢出中断请求标志位。当T2计数溢出复位为0时,由内部硬件置位TF2,并申请中断。但在波特率发生器方式下,当RCLK位或TCLK置位为1时,T2计数溢出将不对TF2置位,此时必须由软件复位。
定时器/计数器2的工作模式:
RCLK+TCLK | CP/RL2 | TR2 | 工作模式 |
0 | 0 | 1 | 16为自动再装入 |
0 | 1 | 1 | 16位捕获 |
1 | - | 1 | 波特率发生器 |
- | - | 0 | 工作停止 |
2、控制寄存器T2MOD:
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
T2MOD | - | - | - | - | - | - | T2OE | DCEN |
T2OE:T2输出启动位。
DCEN:置位为1时,允许T2加1计数或减1计数。
使用定时器的方法:
第一:赋值TMOD寄存器,用来指定定时/计数器的工作模式。
第二:赋值TH0、TL0或TH1、TL1,设置计数寄存器的初值,精确设定好定时时间。
第三:如果需要使用中断,则可以对IE赋值,启动定时器中断。
第四:设置特殊功能寄存器TCON,对TR0、TR1置位,通过打开TR来让定时器进行工作。(也可设置为中断模式)
设定初值:
(2^位数-X)*12/晶振频率=时间。
X--->0xXXXX.
例:TH1 = 0xb8; TL1 = 0X00;
12(65536 – x) /11059200 = 0.02s
例:小灯的1秒间隔闪烁
#include<reg52.h>
typedef unsigned int uint16;
typedef unsigned char uint8;
sbit LED=P0^0;
void main()
{
uint16 num=0;
TMOD=0x01;//设置使用定时器T0的模式1,此时不受外部输入引脚的控制
TH0=0xB8;//设置TH0
TL0=0x00;//设置TL0
TR0=1;//开始定时
while(1)
{
if(TF0==1)
{
这里只介绍了定时器的一种情况,其他的应该差不多一样,计数器的功能还没遇到,暂时先这样吧。
中断:
中断请求标志及其访问:
1、TCON的中断标志
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
位地址 | 8F | 8E | 8D | 8C | 8B | 8A | 89 | 88 |
位符号 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
TF0:定时器/计数器T0的溢出标志位。当定时器/计数器T0产生溢出时,单片机将自动置TF0=1。此时,CPU响应中断,转向相应的中断服务程序,并自动置TF0=0.
IE1:外部中断1请求标志位。当单片机INT1端口的中断信号有效的时候,单片机将自动置IE1=1请求中断。CPU响应中断请求,转向对应的中断服务程序,并自动置IE1=0.
IT1:外部中断1的中断触发方式控制位。当IT1=0的时候,为低电平触发方式;当IT1=1的时候,为下降沿触发方式。
IE0:外部中断0请求标志位。当单片机INT0端口的中断信号有效的时候,单片机将自动置IE0=1请求中断。CPU响应中断请求,转向对应的中断服务程序,并自动置IE0=0.
IT0:外部中断0的中断触发方式控制位。当IT0=0的时候,为低电平触发方式;当IT0=1的时候,为下降沿触发方式。
2、SCON的中断标志:
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
位地址 | 9F | 9E | 9D | 9C | 9B | 9A | 99 | 98 |
位符号 | - | - | - | - | - | - | TI | RI |
TI:串行接口发送数据中断请求标志位。当单片机的串行接口发送完一个数据后,硬件自动置TI=1。此时,CPU响应中断,转向相应的中断服务程序,注意此时不会自动TI清零,须在软件中置TI=0。
中断允许标志及其访问:
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
符号 | EA | EC | ET2 | ES | ET1 | EX1 | ET0 | EX0 |
EA:中断允许或禁止总控制位。当置EA=0时,单片机将禁止所有中断,不响应任何中断请求;当EA=1时,单片机允许各个中断,此时还需要有其他标志位确定各个中断的允许或禁止。
ES:串行中断允许或禁止控制位。当置ES=0时,禁止串行口中断;当置ES=1时,允许串行口中断。
ET1:定时器/计数器T1允许或禁止标志位。当置ET1=0时,禁止定时器/计数器T1中断;当置ET1=1时,允许定时器/计数器T1中断。
EX1:外部中断1允许或禁止标志位。当置EX1=0时,禁止外部中断1;当置EX1=1时,允许外部中断1。
ET0:定时器/计数器T0允许或禁止标志位。当置ET0=0时,禁止定时器/计数器T0中断;当置ET0=1时,允许定时器/计数器T0中断。
EX0:外部中断0允许或禁止标志位。当置EX0=0时,禁止外部中断0;当置EX0=1时,允许外部中断0。
中断优先级标志及其访问:
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
位地址 | BF | BE | BD | BC | BB | BA | B9 | B8 |
位符号 | - | - | - | PS | PT1 | PX1 | PT0 | PX0 |
PT1:定时器/计数器T1优先级设置位。当置PT1=0时,该中断源被定义为低优先级;当置PT1=1时,该中断源被定义为高优先级。
PX1:外部中断1优先级设置位。当置PX1=0时,该中断源被定义为低优先级;当置PX1=1时,该中断源被定义为高优先级。
PT0:定时器/计数器T0优先级设置位。当置PT0=0时,该中断源被定义为低优先级;当置PT0=1时,该中断源被定义为高优先级。
PX0:外部中断0优先级设置位。当置PX0=0时,该中断源被定义为低优先级;当置PX0=1时,该中断源被定义为高优先级。
中断的运行过程大概是:设置中断类型,允许中断(EA)---->满足中断标志位---->开始执行中断程序
执行顺序,如果多个同优先级的中断请求同时发出,则CPU按照一定的查询次序来决定中断执行的顺序。51系列单片机对中断的查询次序为“外部中断0---》定时器/计数器T0---》外部中断1---》定时器/计数器T1---》串行接口中断”。
如果一个低优先级的中断请求正在执行,则可以中断该服务程序,然后执行本次中断请求。如果一个高优先级或同优先级的中断请求正在执行,则当前中断请求不会立即执行。
任何正在执行的指令在未完成前,中断请求都不会响应。
如果程序正在执行读写寄存器IE和IP指令,则执行完该命令后,需要再执行一条其他指令才可以相应中断。
如果程序正在执行返回指令,则执行完该命令后,需要再执行一条其他指令才可以响应中断。
格式:例 void It0(void) interrupt (中断源)X
中断源:0(外部中断0) 1(定时器/计数器T0) 2(外部中断1) 3(定时器/计数器T1) 4(串行接口中断) 5(定时器/计数器T2) 6(PCA中断)。
例:下面是一个利用中断和定时器/计数器T0实现数码管间隔一秒加一的程序。
#include <reg52.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
code uint8 number[] = {0x3F,0x06,0x5B,0x4F,
0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,
0x39,0x5E,0x79,0x71};
uint32 i=0;
uint16 counter = 0;
sbit BCD6 = P1^5;
sbit BCD5 = P1^4;
sbit BCD4 = P1^3;
sbit BCD3 = P1^2;
sbit BCD2 = P1^1;
sbit BCD1 = P1^0;
void mdelay(void);
void init_delay(void);
void init_interrupt(void);
void show(uint32 temp);
//初始化
void init_delay()
{
TMOD = 0x01;//设置使能T0
TH0 = 0xB8;
TL0 = 0x00;
TR0 = 1;//使能定时器/计数器
}
void init_interrupt()
{
ET0 = 1;//设置定时器/计数器T0中断
EA = 1;//中断使能
}
void mdelay()
{
uint16 n = 100;
for(;n>0;n--);
}
void main(void)
{
init_delay();
init_interrupt();
while(1)
{
if(i == 50)
{
counter++;
i = 0;
}
show(counter);
}
}
//中断程序
void interrupt_timer1() interrupt 3
{
TH0 = 0xB8;
TL0 = 0x00;
i++;
}
void show(uint32 temp)
{
P0 = number[temp/100000%10];
BCD6 = 0;
mdelay();
BCD6 = 1;
P0 = number[temp/10000%10];
BCD5 = 0;
mdelay();
BCD5 = 1;
P0 = number[temp/1000%10];
BCD4 = 0;
mdelay();
BCD4 = 1;
P0 = number[temp/100%10];
BCD3 = 0;
mdelay();
BCD3 = 1;
P0 = number[temp/10%10];
BCD2 = 0;
mdelay();
BCD2 = 1;
P0 = number[temp%10];
BCD1 = 0;
mdelay();
BCD1 = 1;
}
计算初值的方法:
用C语言实现的,先要定义好定时器的初值,不管你使用多大的晶振,使用51单片机,一般都是12分频出来,也就可以得出一个机器周期,机器周期=12/n(n指晶振频率),假设你要定时的时间为M,那么定时的初值为:M/机器周期=初值;
TH0=(65536-初值)%256;
TL0=(65536-初值)/256;
将(65536-初值)所得的值化成16进制,其高位就是TH0的值,低位为TL0的值,例如用12M晶振做1ms定时计算如下:
机器周期=12/12*10^6=1us(微秒)
定时初值=(1*10^-3)/(1*10^-6)=1000;
所以:TH0=(65536-1000)%256;
TL0=(65536-1000)/256;
将65536-1000=64536化为16进制为:0xFC18,TH0=0xFC,TL0=0X18;
定好初值后要延迟一秒就定一个延时参数,这里使用1000就行了(定时为1ms)中断程序为:timer0() interrupt 1 // 1ms延时(12.0MHz)
最后
以上就是活力蜡烛为你收集整理的51单片机的中断和定时(全面)的全部内容,希望文章能够帮你解决51单片机的中断和定时(全面)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复