1. 首先附上代码例子
#include <AT89X52.H>
#define uint unsigned int
#define uchar unsigned char
uint i,j;
main(){
i=0;
j=0;
EA=1; //中断总开关开
ET0=1;//定时器T0中断允许
ET1=1;//定时器T1中断允许
TR0=1;// 启动定时器T0
TR1=1;// 启动定时器T1
TMOD=0x11;//使用定时器T0的模式1 定时器T1的模式1
TH0=(65536-50000)/256; //定时器T0的高8位赋初值
TL0=(65536-50000)%256; //定时器T0的高8位赋初值
TH1=(65536-50000)/256; //定时器T1的高8位赋初值
TL1=(65536-50000)%256; //定时器T1的高8位赋初值
P0=0x00; //打开所有P0口的LED灯
P1=0xff; //关闭所有P1口的LED灯
while(1); //无限循环,
}
/**************************************************************
函数功能:定时器T0中断服务程序
**************************************************************/
void int1(void) interrupt 1 //“interrupt”声明函数为中断服务函数
{
i=i+1;
if(i==40){
P0=~P0; //P0口的LED灯取反
i=0;
}
TH0=(65536-50000)/256; //定时器T0的高8位重新赋初值
TL0=(65536-50000)%256; //定时器T0的高8位重新赋初值
}
/**************************************************************
函数功能:定时器T1中断服务程序
**************************************************************/
void int2(void) interrupt 3 //“interrupt”声明函数为中断服务函数
{
j=j+1;
if(j==40){
P1=~P1; //P1口的LED灯取反
j=0;
}
TH1=(65536-50000)/256; //定时器T1的高8位重新赋初值
TL1=(65536-50000)%256; //定时器T1的高8位重新赋初值
}
问题一:数码管常常会遇到显示不出数字,有时,当你在中断加一个条件时,就不能显示了,删掉就可以
解决:中断里的这两行代码必须放在最结尾,则可以显示正常
TH1=(65536-50000)/256; //定时器T1的高8位重新赋初值
TL1=(65536-50000)%256; //定时器T1的高8位重新赋初值
2.定时器初始化部分
EA=1; //中断总开关开
ET0=1;//定时器T0中断允许
ET1=1;//定时器T1中断允许
TR0=1;// 启动定时器T0
TR1=1;// 启动定时器T1
TMOD=0x11;//使用定时器T0的模式1 定时器T1的模式1
下面细说下为什么要这么配置
3.中断寄存器
首先分为6个大部分
IE – 中断允许控制寄存器(重点)
IP – 中断优先级控制寄存器
TMOD – 定时器工作方式寄存器(重点)
TCON – 定时器控制寄存器(重点)
SCON – 串口控制寄存器
THx/TLx – 定时器初值寄存器(重点)
3.1中断允许控制寄存器 IE
序号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
符号 | EA | - | ET2 | ES | ET1 | EX1 | ET0 | EX0 |
EA -全局中断允许位,当此位是1时中断可用。(重要)
ET2-定时器/计数器2中断允许位
ES -串口中断允许位
ET1-定时器/计数器1中断允许位
EX1-外部中断1允许位
ET0-定时器/计数器0中断允许位 (重要)
EX0-外部中断0允许位
要使用定时器中断,需要将IE寄存器中的EA位设置为1,以及需要将ETx(x = 0,1,2)设置为1
3.2定时器控制寄存器 TCON
该寄存器用于控制中断,如控制定时器的启动,停止、判断定时器的溢出和中断情况。
序号 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
符号 | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
TF1 定时器1溢出标志位
TR1 定时器1运行控制位,将该位置1时启动定时器1(重要)
TF0 定时器0溢出标志位
TR0 定时器0运行控制位,将该位置1时启动定时器0 (重要)
IE1 外部中断1请求标志
IT1 外部中断1触发方式选择位
IE0 外部中断0请求标志
IT0 外部中断0触发方式选择位
3.3定时器初值寄存器 THx/TLx
以定时器T0为例,其的工作原理是,每当晶振产生一次脉冲,就将该寄存器TL0加一,当TL0加满溢出后,将TL0清空,TH0加一,TH0计满后产生定时中断。即TH0与TL0组成了一个16位的计数器,这个计数器可以从0x0000(0)加到0xffff(65535)。
常见的有2种设计方式:
第一种
TH0=(65536-50000)/256; //定时器T0的高8位赋初值
TL0=(65536-50000)%256; //定时器T0的高8位赋初值
TH1=(65536-50000)/256; //定时器T1的高8位赋初值
TL1=(65536-50000)%256; //定时器T1的高8位赋初值
50000就是我们设置的时间,比如机械周期是1us,那么
50000*1us=50ms
这种方法很直观,我比较喜欢用这种
第二种
TH0 = 0x3c;//高位
TL0 = 0xb0; //低位
首先把高低位拼在一起
THTL=0x3cb0
需要转换成10进制
THTL =15536
求出我们设定的时间值
65536-15536=50000
如果想要修改时间,也需要反推到源头,十分麻烦,当然也许有其他见解,有待补充。
TH0代表我选用的是定时器0。
4.定时器工作方式寄存器 TMOD
一共有四种模式
可以看到 TO受低四位控制,T1受高四位控制。
举个例子
TMOD=0x11;//使用定时器T0的模式1 定时器T1的模式1
根据上面,可以知道
T0定时器采用01工作方式
T1定时器采用01工作方式
如果你没开启定时器1,就置零
TR1=0;// 关闭定时器T1
TMOD=0x01;
下面详细说下四种方式
方式0:13位定时器/计数器,TH0的高8位,TL0的低5位
方式1:16位定时器/计数器,TH0的高8位,TL0的低8位
方式2:自动重装的8位计数器,TL0用于计数,TH0用于备份
方式3:被分为TH0和TL0两个独立的8位计数器(只有T0可以在方式3下工作)
5.时钟周期/机器周期计算:
6.中断服务程序的格式
中断写法
void 函数名() interrupt 中断号 using 工作组
{
//所要执行内容
}
1.中断服务函数要写在主函数后面,且不需要声明 。
2.中断服务函数无返回值,所以用void
3.函数名可以随便起
4.interrupt后的中断号由下表的重点服务号确定
5.using 工作组可省略不写
举个例子
void int1(void) interrupt 1 //“interrupt”声明函数为中断服务函数
{
i=i+1;
if(i==40){
P0=~P0; //P0口的LED灯取反
i=0;
}
TH0=(65536-50000)/256; //定时器T0的高8位重新赋初值
TL0=(65536-50000)%256; //定时器T0的高8位重新赋初值
}
1对应的是T0 – 定时器/计数器0中断