8051单片机实战分析(以STC89C52RC为例) | 12 - 串行口中断的使用
Posted Neutionwei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了8051单片机实战分析(以STC89C52RC为例) | 12 - 串行口中断的使用相关的知识,希望对你有一定的参考价值。
在第一篇到第九篇博文中,我们认识到了一些基于IO口输入与输出的基础电子器件使用:
《8051单片机实战分析(以STC89C52RC为例) | 01 - 点亮一个LED》
《8051单片机实战分析(以STC89C52RC为例) | 02 - LED延时约5s闪烁》
《8051单片机实战分析(以STC89C52RC为例) | 03 - LED流水灯》
《8051单片机实战分析(以STC89C52RC为例) | 04 - 蜂鸣器驱动》
《8051单片机实战分析(以STC89C52RC为例) | 05 - 静态数码管驱动》
《8051单片机实战分析(以STC89C52RC为例) | 06 - 动态数码管驱动》
《8051单片机实战分析(以STC89C52RC为例) | 07 - 独立按键驱动》
《8051单片机实战分析(以STC89C52RC为例) | 08 - 矩阵按键驱动》
《8051单片机实战分析(以STC89C52RC为例) | 09 - LED点阵显示数字》
但现在我们要开始回到8051单片机内部,通过实战来认识它们的工作原理,你会发现通过它们可以去开发一些更有意思的东西!
这篇博文带领大家认识一下STC89C52RC单片机定时器中断的使用。
如果你不了解什么是中断,建议你先看这篇:
《STC89C52RC单片机额外篇 | 01 - 认识中断、中断源以及中断优先级》
如果你不了解什么是串口通信,建议你先看这篇:
《STC89C52RC单片机额外篇 | 02 - 认识串行通信、波特率以及数据包》
1 中断系统结构
以下这张图是从中断引脚到中断入口所经过的通道:
从图中不难看出RX
与TX
引脚经过了SCON、IE、IP
这些寄存器,因此我们在写程序时得把这些寄存器功能配置好,CPU才会按照我们的想法只执行!下面分别对这些寄存器进行介绍(稍微了解一下即可,忘记的时候再查)。
1.1 SCON寄存器
SCON(Serial Control Register),中文叫串行口控制寄存器,SCON寄存器是用于控制串行通信的方式选择、接收和发送,指示串口的状态。
首先介绍SCON
寄存器位SM0/SM1
,它们用于设置工作方式:
其余SCON
寄存器位的用途:
SCON寄存器位 | 作用 |
---|---|
SM2 | 多机通信控制位。多机通信是工作于方式2和方式3,SM2 位主要用于方式2和方式3。接收状态,当串行口工作于方式2或3,以及SM2=1 时,只有当接收到第9位数据(RB8 )为1时,才把接收到的前8位数据送入SBUF ,且置位RI 发出中断申请,否则会将接收到的数据放弃。当SM2=0 时,就不管第9位数据是0还是1,都会将数据送入SBUF ,并发出中断申请。工作于方式0时,SM2 必须为0。 |
REN | 允许接收位。REN 用于控制数据接收的允许和禁止,REN=1 时,允许接收,REN=0 时,禁止接收。 |
TB8 | 发送数据位8。在方式2和方式3中,TB8是要发送的——即第9位数据位。在多机通信中同样亦要传输这一位,并且它代表传输的地址还是数据,TB8=0 为数据,TB8=1 时为地址。 |
RB8 | 接收数据位8。在方式2和方式3中,RB8 存放接收到的第9位数据,用以识别接收到的数据特征。 |
TI | 发送中断标志位,它是可寻址标志位。方式0时,发送完第8位数据后,由硬件置位,其它方式下,在发送或停止位之前由硬件置位,因此,TI=1 表示帧发送结束,TI 可由软件清“0”。 |
RI | 接收中断标志位,它是可寻址标志位。接收完第8位数据后,该位由硬件置位,在其他工作方式下,该位由硬件置位,RI=1 表示帧接收完成。 |
要注意的是在串口中断处理时,TI,RI
都需要软件清"0",硬件置位后不可能自动清0,此外,在进行缓冲区操作时,需要ES=0
,以防止中断出现。ES
寄存器位位于接下来介绍的IE
寄存器。
1.2 IE寄存器
IE(Interrupt Enable),中文叫中断允许寄存器,它的作用是控制所有中断源的开放或禁止,以及每个中断源是否被允许。
各寄存器位的作用如下:
IE寄存器位 | 作用 |
---|---|
EA | EA = 0 时,所有中断禁止(即不产生中断);EA = 1 时,各中断的产生由个别的允许位决定 |
ES | 串行口RX/TX 中断允许 |
ET1 | 定时器T1 中断允许 |
EX1 | 外中断INT1 中断允许 |
ET0 | 定时器T0 中断允许 |
EX0 | 外部中断INT0 中断允许 |
1.3 IP寄存器
IP(Interrupt Priority),中文叫中断优先级寄存器,它是用来设定各个中断源属于两级中断中的哪一级。
各寄存器位的作用如下:
IP寄存器位 | 作用 |
---|---|
PS | 串行口RX/TX 中断优先 |
PT1 | 定时器T1 中断优先 |
PX1 | 外中断INT1 中断优先 |
PT0 | 定时器T0 中断优先 |
PX0 | 外部中断INT0 中断优先 |
除此之外,还有一个波特率有关的PCON
寄存器,当然这里只用到它其中的一位。
1.4 PCON寄存器
PCON全称Power Control Register,即功率控制寄存器。
系统复位默认为SMOD=0
。当SMOD=0
时,串口方式1,2,3时,波特率正常;当SMOD=1
时,串口方式1,2,3时,波特率加倍。
2 串行口结构
注意这里的SBUF
寄存器只是逻辑上同名,但是它们物理上是分开的!另外,还需要用到TH1
与TL1
这种属于定时器T1
的寄存器,后面会了解到它们的作用!
下面列出各个工作方式的数据传输:
① 工作方式0:
② 工作方式1:
③ 工作方式2与工作方式3:
3 波特率计算
如果你不了解什么是波特率,建议你先看这篇:
《STC89C52RC单片机额外篇 | 02 - 认识串行通信、波特率以及数据包》
下面列出基于各个工作方式的波特率计算公式,对于可变波特率的设置需要用到TH1
寄存器:
当然,对于波特率,一般有几种是可供选择的,因为我们通常使用标称值:
这里我们好奇为什么晶振频率选择11.0592MHz就能减小计算误差,下面我们以9600波特率,分别代入11.0592MHz与12MHz计算一下:
我们设置定时器T1
为工作模式2,SMOD 设为1,分别看看那所要求的TH1
为何值。代入公式:
-
11.0592MHz
9600=(2÷32)×((11.0592M/12)/(256-TH1)) =》TH1=250
-
12MHz
9600=(2÷32)×((12M/12)/(256-TH1)) =》TH1≈249.49
4 代码
① 中断服务函数:
我们知道我们编写的C程序,函数的执行是从main主函数开始执行,现在有了中断,自然就产生一个中断服务函数:
从图中我们可以知道单片机在发生中断的时候,程序的执行过程会从主程序A跳到中断服务程序B,在执行完中断服务程序B后,会返回到之前主程序A被中断打断处继续执行程序。
那么我们如何指定中断服务程序?具体参考以下模板(对于函数名你可以随便写,当然最好贴近有意义的命名)。
外部中断0的中断服务函数:
void Int0() interrupt 0
{
... // 中断服务程序中要执行内容
}
定时器0的中断服务函数:
void Timer0() interrupt 1
{
... // 中断服务程序中要执行内容
}
外部中断1的中断服务函数:
void Int1() interrupt 2
{
... // 中断服务程序中要执行内容
}
定时器1的中断服务函数:
void Timer1() interrupt 3
{
... // 中断服务程序中要执行内容
}
串行口的中断服务函数:
void Serial() interrupt 4
{
... // 中断服务程序中要执行内容
}
② 下面我们写个程序,将波特率设置为4800,把发送的数据字符"1"
显示到串口调试助手SSCOM:
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
/*******************************************************************************
* 函数名 :UartInit()
* 函数功能 :设置串口
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void UartInit()
{
SCON=0x50; //设置为工作方式1
TMOD=0x20; //设置计数器工作方式2
PCON=0x80; //波特率加倍
TH1=0xF3; //计数器初始值设置,注意波特率是4800
TL1=0xF3;
ES=1; //打开接收中断
EA=1; //打开总中断
TR1=1; //打开计数器
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
UartInit(); // 串口初始化
while(1);
}
/*******************************************************************************
* 函数名 : Serial() interrupt 4
* 函数功能 : 串口通信中断函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Serial() interrupt 4
{
u8 receiveData;
receiveData=SBUF; //出去接收到的数据
RI = 0; //清除接收中断标志位
SBUF=receiveData; //将接收到的数据放入到发送寄存器
while(!TI); //等待发送数据完成
TI=0; //清除发送完成标志位
}
简要分析:
- 代码中设置波特率为4800,根据前面的表格不是应该设置
TH1=0xFA;
吗?根据前面的介绍,我们不难发现此处用到晶振频率肯定不是11.0592MHz,明显是使用12MHz。 - 注意这里把定时器T1设置为工作方式2——8 位自动重装模式,因此寄存器
TH1
与TL0
的值是一样的。 - 最后附上串口调试助手的操作:
以上是关于8051单片机实战分析(以STC89C52RC为例) | 12 - 串行口中断的使用的主要内容,如果未能解决你的问题,请参考以下文章
8051单片机实战分析(以STC89C52RC为例) | 11 - 定时器中断的使用
8051单片机实战分析(以STC89C52RC为例) | 03 - LED流水灯
8051单片机实战分析(以STC89C52RC为例) | 02 - LED延时约5s闪烁
8051单片机实战分析(以STC89C52RC为例) | 08 - 矩阵按键驱动