51单片机学习笔记8 中断系统及定时器

51单片机学习笔记8 中断系统及定时器

首页休闲益智我的世界1.16.210.51更新时间:2024-05-11
一、中断的概念

中断是一种事件驱动的机制,允许单片机在执行程序的过程中暂时中断当前的任务,转而处理来自外部的优先级更高的事件。
当中断事件发生时,单片机会立即跳转到中断服务程序(ISR),执行相关的处理代码,然后返回到原来的程序继续执行。

二、51单片机的中断1. 51单片机的中断源

51单片机中的中断源可以是外部硬件引脚的电平变化(外部中断),也可以是单片机内部的定时器/计数器溢出、串口接收等(内部中断)。

不同的51单片机中断源可能有所不同。一般51单片机至少有 5个中断:外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断。

而STC89C51RC/RD 的系列单片机提供了8个中断请求源,分别是:

在 中颖的SH79F6442中,提供了27个中断源,其中有5个外部中断、3个定时器中断,另外还有4个PCA中断、4个EUART中断、系统时钟监控中断、1个SPI中断、ADC中断、3路PWM中断、LED中断、TWI中断、CRC中断、LPD中断。

2. 中断的优先级

51单片机中,不同中断源之间存在优先级关系,当多个中断同时发生时,优先级高的中断会先得到响应。
可以通过设置中断优先级和中断允许位来控制不同中断源之间的优先级和允许状态。
下图是来自《STC89Cxx中文参考手册.pdf》 里的中断说明:

3. 中断结构

下图也是摘自《STC89Cxx中文参考手册》,其结构


上图的解读,整体是以列的方式从左往右看,数据从最左侧是中断源,经过中断允许控制寄存器(开关),到中断优先级控制寄存器,再流向处理程序。

靠上的中断优先级更高。

4. 外部中断解读

中断信号传递流程:

  1. INT0 中断信号通过IT0(TCON控制寄存器第0位)引脚,来选择触发方式(0:低电平触发或 1:下降沿触发);
  2. 触发中断后,将IE0(TCON寄存器第1位,中断标志)置1;
  3. 判断EX0(IE中断允许寄存器第0位)如果是1,就是INT0使能,中断可以继续向后传递;
  4. 如果全局总中断EA(IE中断允许寄存器第7位)打开,中断可以继续传递;
  5. 中断优先级控制寄存器IP判断哪个中断先触发;
  6. 触发CPU的中断服务函数。

从上面的流程可以看出,IE.EX0即使失能状态,也可以通过TCON.IE0读取中断信号。

外部中断INT1对应P3.3引脚,工作流程与INT0类似。

5. 定时器中断
  1. 有计数信号进入T0;
  2. 计数溢出时,触发 TF0(TCON计数器寄存器,TF0溢出中断标志);
  3. 如果ET0(IE中断第1位,T0的溢出中断允许位),继续传递;
  4. 如果全局总中断EA(IE中断允许寄存器第7位)打开,继续传递;
  5. 中断优先级控制器IP判断优先级;
  6. 触发CPU中断服务函数。
6. 串口中断
  1. 当接收到数据或发送完成时,串口硬件会设置RI/TI标志位,表示接收到了数据;
  2. 如果 ES(IE寄存器的第4位,串行口中断允许位)被设置,允许串口中断继续传递;
  3. 如果全局总中断 EA(IE寄存器的第7位,全局中断允许位)被打开,则允许中断继续传递;
  4. 中断优先级控制器IP判断优先级;
  5. 触发中断服务函数;
三、中断相关寄存器1. IE 中断允许寄存器

IE 地址为 A8H,格式如下:

编号

作用

EA

7

全局中断允许位

6

无效位,保留

ET2

5

定时器/计数器2中断允许位

ES

4

串行口中断允许位

ET1

3

定时器/计数器1中断允许位

EX1

2

外部中断1允许位

ET0

1

定时器/计数器0中断允许位

EX0

0

外部中断0允许位

2. TCON 中断请求标志

编号

作用

TF1

7

定时器/计数器1溢出标志位

TR1

6

定时器/计数器1运行控制位

TF0

5

定时器/计数器0溢出标志位

TR0

4

定时器/计数器0运行控制位

IE1

3

外部中断1标志位

IT1

2

外部中断1触发方式选择位

IE0

1

外部中断0标志位

IT0

0

外部中断0触发方式选择位

3. IP 中断优先级

编号

作用

7

无效位,保留

PT2

6

定时器/计数器2中断优先级位

PS

5

串行口中断优先级位

PT1

4

定时器/计数器1中断优先级位

PX1

3

外部中断1优先级位

PT0

2

定时器/计数器0中断优先级位

PX0

1

外部中断0优先级位

0

无效位,保留

这里对寄存器简单介绍,更详细地说明可以参考本文对应的开源代码里的《STC89Cxx中文参考手册》。

四、中断号

下面是关于中断号的说明:

中断号

描述

0

外部中断0

1

定时器/计数器0 溢出中断

2

外部中断1

3

定时器/计数器1 溢出中断

4

串行口通信中断

5

定时器/计数器2 溢出中断

6-7

保留

五、代码实现

硬件连接:

按键 :

LED:


其中按键3是在P3.2引脚,中断0。

1. 按键事件切换LED亮的状态key_utils.c

#include "key_utils.h" #include <reg52.h> #include "common_utils.h" sbit KEY3 = P3^2; sbit LED1 = P2^0; /** * @brief 按键中断初始化 */ void key3_init(void){ IT0 = 1; // 下降沿触发 EX0 = 1; // 开启外部中断0 EA = 1; // 开启总中断 } void exti0() interrupt 0{ delay_10us(500); if(KEY3 == 0){ LED1 = !LED1; } } main.c

#include <reg52.h> #include "led_utils.h" #include "common_utils.h" #include "key_utils.h" #include "types.h" /** * @brief 主函数 */ main() { // 关闭所有led led_all_off(); key3_init(); while(1) { } } 六、定时/计数器结构

1. 寄存器介绍TMOD

TMOD用于控制定时器/计数器的工作模式和计数方式,寄存器各位功能:

Bit: 7 6 5 4 3 2 1 0 ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │ GATE │ C/T │ M1 │ M0 │ GATE │ C/T │ M1 │ M0 │ └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ T1 T1 T0 T0 T1 T1 T0 T0

TMOD 寄存器各位的功能
分成2组,高4位、低4位,分别控制定时器1、定时器0的工作模式。

TCON

TCON 用于控制定时器/计数器的工作状态和中断标志位,各位功能:

Bit: 7 6 5 4 3 2 1 0 ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │ TF1 │ TR1 │ TF0 │ TR0 │ IE1 │ IT1 │ IE0 │ IT0 │ └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘

TCON 寄存器各位的功能

2. 定时器/计数器工作方式0(1)工作特点

也称为13位定时器模式,结构图如下:


其特点是:

计数由TL0的低5位和TH0的高8位组成,低5位溢出时向TH0进位,TH0 溢出时,TCON.TF0 置位。

(2)门控位说明(3)C/T

控制计数还是定时模式,即开关:

3. 工作方式1

工作方式1称为16位定时器模式:

4. 工作方式2

5. 工作方式3

工作方式只适应用于T0,也称为两个8位定时器/计数器分开工作模式,其特点:

七、定时器代码实现1. 定时器配置步骤
  1. 选择定时器
  2. 选择工作模式
  3. 设置定时器初值
  4. 选择时钟源
  5. 中断使能
  6. TR0或TR1置位,启动定时器
  7. 中断处理
2. 计时器初值计算

使用开源仓库里的51定时器计算工具计算,晶震频率根据开发板实际频率填写。

3. 示例

本示例每秒LED闪烁一次:

timer_utils.c

#include "timer_utils.h" #include <reg51.h> #include "types.h" sbit LED1 = P2^0; /** * @brief 定时器 0 初始化函数 */ void timer1_init(void){ // 选择为定时器 0 模式,工作方式 1 TMOD |= 0X01; // 给定时器赋初值,定时 1ms TH0 = 0XFC; TL0 = 0X66; // 打开定时器 0 中断允许 ET0 = 1; // 打开总中断 EA = 1; // 打开定时器 TR0 = 1; } // 定义静态变量 i static u16 i; /** * @brief 定时器 0 中断函数 */ void timer1() interrupt 1 { // 定时器重新赋初值,定时 1ms TH0 = 0XFC; TL0 = 0X66; i ; if(i == 1000) { i =0 ; LED1 = !LED1; } } main.c

#include <reg52.h> #include "led_utils.h" #include "common_utils.h" #include "types.h" #include "timer_utils.h" /** * @brief 主函数 */ main() { // 关闭所有led led_all_off(); time0_init(); while(1) { } }

本文代码开源地址:
https://gitee.com/xundh/learn51

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved