目录
一、 定时器相关
1、 本质原理
简单的说就是每经过一个机器周期,计数的寄存器加1。
2、 相关概念:
🔖晶振(晶体振荡器):各种电子产品里面必不可少的频率元器件。(例如我使用的单片机的系统时钟频率是:11.0592MHZ)
🔖时钟周期:也称震荡周期。系统时钟频率的倒数。
🔖机器周期:机器周期也称为CPU周期,完成一个基本操作所需要的时间。一般一个机器周期由若干个时钟周期组成。(12T、6T…例如:12T的机器周期 12×0.090422 = 1.085 μs —> 即:定时器计数加1所需的时间1.085μs)
3、定时器的相关寄存器
📓TL0/1、TH0/1
默认从0开始计数,最多能计65536(16位2^16),也就是能计时1.085×65536=71105.475 μs = 71 ms = 0.071s
📓如何计算定时10ms计数寄存器初值
✒️10 ms需要计数多少次?(已知计数1次,需要1.085 μs)
解:设10 ms需要计数x次。
1.085 μs = 0.001085 ms 。由题意得0.001085x = 10,解得x = 9216
即10 ms需要计数9216次,从65536-9216 = 56320(DC00)开始计数,经过10ms刚好到16位最大值。此时,TL0 = 0x00(低8位);TH0 = 0xDC(高8位);
📓定时器控制寄存器TCON
✒️bit5(TF0):当溢出的时候,硬件会修改bit5(TF0)位上的数据(置1)
✒️bit4(TR0):置1时,定时器开始计数
📓定时器模式寄存器TMOD
✒️TMOD寄存器的各位信息如表所示,可以看出,定时器0和1有4种操作模式,通过TMOD的M1和M0选择。定时器0和1的模式0、1和2相同,模式3不同(芯片手册所述)
模式0 | 13位定时器 |
模式1 | 16位定时器 |
模式2 | 8位自动重装模式 |
模式3 | 两个8位定时器 |
✒️如16位定时器,需配置TMOD的M1和M0分别为0和1
📓定时器demo1(每1秒LED闪烁)
#include "reg52.h"
#include <intrins.h>
sbit led = P3^6;
void main(){
int cnt = 0;
led = 1;
//配置定时器0模式为16位定时器
TMOD = 0x01;
//定义计数初值,10ms(100次 = 1s)
TL0 = 0x00;TH0 = 0xDC;
//开启定时
TR0 = 1;
TF0 = 0; //溢出时,系统自动修改TF0的值为1(每修改一次10ms == 100次1s)
while(1){
if(TF0 == 1){ //溢出时,cnt+1,重新设置TL0和TH0的值
TF0 = 0; //不用中断,需要软件清零TF0
cnt++;
TL0 = 0x00;
TH0 = 0xDC;
if(cnt == 100){ //溢出100次(到1s)cnt重新计数并翻转LED状态
cnt = 0;
led = !led;
}
}
}
}
4、定时器的使用总结
①设置定时模式TMOD
②设置计数寄存器初值TL0、TH0(需要计算)
③TCON寄存器的bit4/TR0(置1)开始计数,溢出时bit5/TF0会被系统置1
④再次计数时需要重置TL0(低8bit)和TH0(高8bit)
二、初识中断—定时器中断
1、中断( interrupt)
📓什么是中断系统?
当CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作去处理该紧急事件,处理完后再回到原来被中断的工作中,这个过程成为中断系统。规定:CPU总是响应优先级最高的中断请求。
📓中断次序号
✒️C语言编程,中断次序号就是中断号
(如:void time0Interupt(void) interupt 1; //定时器0中断)
📓中断相关寄存器
✒️bit7(EA):CPU的总中断允许控制位。置1开放中断;置0屏蔽所有中断申请。
✒️bit1(ET0):定时器0的溢出中断允许控制位,置1开放。
三、C语言——位运算
📓左移和右移(<< 和 >>)
m左移n位 | m << n; | m * 2^n |
m右移n位 | m >> n; | m / 2^n |
📓按位与和按位或( & 和 | )
按位与 | TCON &= ~(0x1<<5); | TCON的bit5置0 |
按位或 | TCON |= 0x1<<4; | TCON的bit4置1 |
📓作用(好处)
不改变寄存器其他位的值,而实现对某个位或者某些位操作(只操作想要的位),在demo1中,直接赋值的写法可能会覆盖到其他位原来的值。
四、中断实现两个LED的闪烁demo2(类似双线程)
#include "reg52.h"
#include <intrins.h>
/***************************************************
****demo2:中断实现两个LED的闪烁(类似双线程)******
****************************************************/
sbit led1 = P3^7;
sbit led2 = P3^6;
int cnt = 0;
void time0Init(){
//① 设置定时模式TMOD
TMOD |= 0x1<<0;
TMOD &= ~(0x1<<1);
//② 设置计数寄存器初值TL0、TH0(需要计算)--定义50ms
TL0 = 0xFC;
TH0 = 0x4B;
//③ TCON寄存器的bit4/TF0(置1),溢出标识bit5/TR0(置0)
TCON |= (0x01<<4);
TCON &= ~(0x01<<5);
}
void interruptInit(){
//①允许总中断
IE |= 0x01<<7;
//②允许定时器0溢出中断
IE |= 0x01<<1;
}
void interruptHandle() interrupt 1 {
//当定时器0溢出,调用此中断处理函数 -- 重新清零,cnt+1直到20(1s)后led1亮
cnt++;
TL0 = 0xFC;
TH0 = 0x4B;
while(cnt == 20){
cnt=0;
led1 = ~led1;
}
}
void Delay500ms() //软件延时0.5s{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do{
do{
while (--k);
} while (--j);
} while (--i);
}
void main(){
int cnt = 0;
led1 = 1;
led2 = 0;
time0Init();
interruptInit();
while(1){
led2 = ~led2;
Delay500ms();
}
}
✒️当定时器每一次溢出时,调用中断处理函数void interruptHandle(),该函数重新清零,并cnt+1,每当cnt==20(1s),LED1状态翻转,实现1s亮灭一次LED1;主函数中使用软件延时,实现LED2每0.5s亮灭一次。(类似于双线程)
说明:由于笔者水平有限,文中不可避免有所错漏,敬请各读者斧正