【51单片机系列】51单片机的中断系统使用总结二

文章目录


四、串口通信相关介绍

80C51系列单片机的串口结构如下图,A是发送或接收的串行数据;有两个独立的缓冲器SBUF,上面的SBUF是发送缓冲器,下面的SBUF是接收缓冲器;由TH1和TL1可以计算出T1溢出率,SMOD确定波特率是否倍增,通过设置控制寄存器实现串口中断。

4.1、与串口通信相关的寄存器

串口通信时除了串行口的控制寄存器SCON和控制波特率的位SMOD外,还需要定时器1确定溢出率。为了开启串口中断还需要IE.4的ES位打开串口中断允许。

  • SCON-串口控制寄存器

SCON是一个特殊功能寄存器,用来设定串行口的工作方式、接收/发送控制以及设置状态标志,各位结构如下:

|----------|-----|-----|---------|---------|-------------------|-------------------|---------|---------|
| 位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| 字节地址:98H | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
| SCON | 工作方式选择位 || 多机通信控制位 | 允许串行接收位 | 方式2或方式3中是发送数据的第9位 | 方式2或方式3中是接收数据的第9位 | 发送中断标志位 | 接收中断标志位 |

SM0SM1是串口通信工作方式选择位,有4种工作方式:

SM0 SM1 工作方式 说明 波特率
0 0 0 移位寄存器 f O S C / 12 f_{OSC}/12 fOSC/12
0 1 1 10位异步收发器,含8位数据 可变
1 0 2 11位异步收发器,含9位数据 f O S C / 64 f_{OSC}/64 fOSC/64 或 f O S C / 32 f_{OSC}/32 fOSC/32
1 1 3 11位异步收发器,含9位数据 可变

SM2是多机通信控制位,主要用于方式2和方式3。

当接收机的SM2=1时利用收到的RB8来控制是否激活RI,RB8=0时不激活RI,收到的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走。

当SM2=0时,不论收到的RB8为0和1,均可以使收到的数据进入SBUF,并激活RI。

工作方式0时,SM2必须是0;工作方式1时,如果SM2=1,只有接收到有效停止位时,RI置1。

REN是允许串行接收位,软件置REN=1,则启动串行口接收数据;软件置REN=0,禁止接收数据。

TB8,方式2和方式3中,是发送数据的第9位,可以用软件规定作用,可以用作数据的奇偶校验位,或者在多机通信中,作为地址帧和数据帧的标志位。方式0和方式1中,该位未使用。

RB8,方式2和方式3中,是接收到数据的第9位,作为奇偶校验位或地址帧/数据帧的标志位。方式1中,如果SM2=0,RB8是接收到的停止位。

TI是发送中断标志位。方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发送中断申请。在中断处理程序中,用软件将其清0,取消此中断申请。

RI是接收中断标志位。方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发送中断申请。在中断处理程序中,用软件将其清0,取消此中断申请。

  • PCON.7-与波特率倍增有关的位

PCON中有一个位SMOD与串行口工作有关,PCON结构如下:

7 6 5 4 3 2 1 0
字节地址:97H SMOD

SMOD是波特率倍增位。在串行口方式1、方式2、方式3时,波特率与SMOD有关。当SMOD=1时,波特率提高一倍。复位时SMD=0。

4.2、波特率计算

串口通信时,收发双方对发送或接收数据的速率要有约定。串口编程方式有四种工作方式,其中方式0和方式2的波特率是固定的,方式1和方式2的波特率是固定的,方式1和方式3的波特率是可变的,由定时器T1的溢出率来决定。

串口通信的四种工作方式对应三种波特率。由于输入的时钟来源不同,所以,各种方式的波特率计算公式也不相同。

方式0的波特率= f O S C / 12 f_{OSC} / 12 fOSC/12。

方式2的波特率= ( 2 S M O D / 64 ) ⋅ f O S C (2^{SMOD}/64) \cdot f_{OSC} (2SMOD/64)⋅fOSC。

方式1的波特率= ( 2 S M O D / 32 ) ⋅ ( T 1 溢出率 ) (2^{SMOD} / 32) \cdot (T1溢出率) (2SMOD/32)⋅(T1溢出率)。

方式3的波特率= ( 2 S M O D / 32 ) ⋅ ( T 1 溢出率 ) (2^{SMOD} / 32) \cdot (T1溢出率) (2SMOD/32)⋅(T1溢出率)。

T1作为波特率发生器时,最典型的用法是使T1工作在自动重装的8位定时器方式,即定时器的工作方式2,并置TCON的TR1=1,以启动定时器。此时溢出率取决于TH1中的计数值。

T1溢出率计算公式:

T 1 溢出率 = f O S C / { 12 × [ 256 − T H 1 ] } T1溢出率 = f_{OSC} / \{ 12 \times [256 - TH1 ]\} T1溢出率=fOSC/{12×[256−TH1]}

单片机应用中,常用的晶振频率是12MHz和11.0592MHz,选用的波特率也相对固定。可以使用软件计算初值。

51单片机波特率初值计算软件:

链接:https://pan.baidu.com/s/1x5R4GzN5RAJmXt0-Qner3A?pwd=8051

提取码:8051

打开软件,设置定时器方式、晶振频率、波特率、SMOD,然后点确定,在上方的黑色框中会显示定时器初值。

4.3、如何实现串口通信

串口通信使用51单片机的RXD(P3.0引脚)和TXD(P3.1引脚),当RXD接收数据或TXD发送数据时,向CPU申请中断,CPU响应串口中断进入中断处理函数中接收或发送SBUF中的数据。

中断响应的三个条件:①中断源有中断请求;②此中断源的中断允许位为1;③CPU开中断。

第一个条件:中断源有中断请求。对于串口来说,在发送数据结束或接收数据结束时,硬件会置TI或RI为1,向CPU申请中断。要发送或接收数据,需要确定波特率,即确定定时器1的工作方式TMOD、计数初值THx和TLx;要使定时器1工作,需要启动计数器TR1;同时还要确定数据发送或接收的控制方式SCON。

第二个条件:此中断源的中断允许位为1,设置串口中断允许位ES=1。

第三个条件:CPU开中断,设置CPU总中断允许位EA=1。

4.3.1、串口通信工作方式0使用

串口通信在工作方式0时为同步移位寄存器方式,这种方式用于单片机外接移位寄存器,用来扩展I/O口。

方式0以8位数据为1帧,没有起始位和停止位,先发送或接收最低位。波特率固定,为 f O S C / 12 f_{OSC}/12 fOSC/12。

(1) 方式0输出

方式0输出的工作原理:当单片机执行将写入发送缓冲器SBUF的指令时,产生一个正脉冲,串口开始把SBUF中的8位数据以 f O S C / 12 f_{OSC}/12 fOSC/12的固定波特率从RXD引脚串行输出,低位在先,TXD引脚输出同步移位脉冲,当8位数据发送完,中断标志位TI置1。

(2)方式0输出使用示例

方式0输出的典型应用是串口外接串行输入/并行输出的同步移位寄存器74LS164,实现并行输出端口的扩展。

Proteus中设计串口工作在方式0,通过74LS164芯片的输出控制8只外接LED发光二极管亮灭的接口电路。串口被设置在方式0输出时,串行数据由RXD端(P3.0)送出,移位脉冲由TXD(P3.1)端送出。在移位脉冲的作用下,串口发送缓冲器的数据逐位地从RXD端串行地移入74LS164芯片中。

proteus设计原理图如下:

74LS164芯片的8脚为同步脉冲输入端;9脚为控制端,当9脚为低电平时,允许串行数据由RXD端向74LS164芯片的串行数据输入端输入,此时74LS164芯片的8位并行输出端关闭,当9脚为高电平时,串行数据输入端关闭,允许74LS164芯片中的8位数据并行输出。

当串口将8位串行数据发送完毕后,申请中断,在中断处理函数中,单片机向串口输出下一个8位数据。

首先需要设置串口通信在方式0的中断响应条件,即串口通信初始化,代码如下:

c 复制代码
// 串口中断初始化函数
void UsartInit()
{
	// 1. 确定串口控制方式,工作在方式0,RI不受RB8控制,禁止接收数据
	SCON=0x00;
	// 2. 打开串并口中断允许位
	ES=1;
	// 3. 打开CPU总中断允许位
	EA=1;
}

串口发送完一帧数据后,申请中断,在中断处理函数中,向串口输出下一帧数据,即串口中断处理函数代码如下:

c 复制代码
// 串口中断处理函数
void Usart() interrupt 4
{
	// 判断TI是否置1,一个字节串行发送完毕
	if(TI)
	{
		CTRL=1;  // 允许74LS164并行输出,流水点亮二极管
		SBUF=sendByte;  // 向SBUF写入数据,启动串行发送
		delay(500);
		
		CTRL=0;  // 允许串行写入,关闭并行输出
		sendByte=_crol_(sendByte, 1);
		SBUF=sendByte;  // 再次发送点亮数据
			
	}
	// 数据处理结束,置TI和RI为0
	TI=0;
	RI=0;
}

在主函数中,首先调用串口初始化函数,然后需要设置74LS164的控制引脚为低电平,允许串行数据输入,最后再向SBUF中发送数据,启动串行发送。代码如下:

c 复制代码
void main()
{
	UsartInit();
	CTRL=0;  // 串行口向74LS164发送数据
	// CPU向SBUF中写入数据,启动串行发送
	SBUF=sendByte;
	while(1);
}

全局变量sendByte声明:u8 sendByte=0x01;

仿真结果:

(3) 方式0输入

方式0输入时,REN作为串行口允许接收控制位,REN=0时禁止接收,REN=1时允许接收。

当向SCON寄存器写入控制字(设置方式0、REN=1,RI=0)时,产生一个正脉冲,串行口开始接收数据。

RXD引脚是数据输入端,TXD为移位脉冲信号输出端,接收器以 f O S C / 12 f_{OSC}/12 fOSC/12的固定波特率采样RXD引脚的数据信息,当接收完8位数据时,中断标志RI置1,表示一帧数据接收完毕,可以进行下一帧数据的接收。

方式0输入时序图如下:

(4) 方式0输入使用示例

如下原理图,单片机的串口外接一片8位并行输入、串行输出的同步移位寄存器74LS165,从而实现了扩展一个8位并行输入口。将接在74LS165的8各开关S0 ~ S7的状态通过串行口的方式0输入方式读入到单片机内。

74LS165芯片的1脚SH/LD为控制端,SH/LD=0时,允许74LS165芯片并行输入数据,关闭串行输出端;当SH/LD=1时,关闭并行输入端,可向单片机串行发送数据。

当P3.2引脚连接的开关k合上时,通过外部中断0控制开关S0 ~ S7的状态数字量并行是否允许读入,使用一个连接在P1.0引脚的LED灯显示是否可以读入的状态,LED灯亮可以读入,LED不亮则不允许读入。采用中断方式对S0 ~ S7状态进行读取,由单片机的P2口控制对应的开关按下的二极管发光点亮。

Proteus设计原理图如下:

软件设计,首先设置中断响应条件,这里需要CPU接收数据,所以应该置REN=1,串口中断初始化函数如下:

c 复制代码
// 串口通信方式0输入初始化
void UsartInit()
{
	// 1. 设置工作方式0,允许接收数据
	SCON=0x10;
	// 2. 打开串口中断允许位
	ES=1;
	// 3. 打开CPU总中断允许位
	EA=1;
}

串口中断处理函数如下:

c 复制代码
// 串口中断处理函数
void Usart() interrupt 4
{
	if(!LED){
		CTRL_74LS165=0;  // 读入并行数据
		delay(1000);
		CTRL_74LS165=1;  // 向CPU发送串行数据
		
		RI=0;
		receiveByte=SBUF;
		
		GPIO_LED=receiveByte;
	}
}

其中LED在外部中断0处理函数中进行取反操作。

主函数调用串口中断初始化函数UsartInit和外部中断0初始化函数Int0Init后进入while(1);即可。

仿真结果如下,可以看到,当没有按下按键K,直接按S0~S7,连接到P2口的LED不会亮;当按下按键K后,再按S0 ~ S7,对应的LED会亮。

4.3.2、串口通信工作方式1使用

串口通信的工作方式1为双机通信方式,如下图所示。SM0SM1设置为01时,串口通信设置为方式1的双机串行通信,TXD脚和RXD脚分别用于发送和接收数据。

方式1收发一帧数据为10位,1位起始位(0)+8位数据位+1位停止位(1)。先发送或接收最低位。

方式1时串口波特率可变,波特率计算方式为: 2 S M O D 32 × T 1 溢出率 \frac{2^{SMOD}}{32} \times T1溢出率 322SMOD×T1溢出率,其中SMOD是寄存器PCON的最高位的值。

(1) 方式1发送

串口以方式1输出时,数据位由TXD端输出,发送一帧信息。当CPU执行写数据到发送缓冲器SBUF的命令后,就启动发送。

如上图是方式1发送时序图。先发送起始位,由TXD引脚输出,然后接着输出8位数据位,数据位全部发送完毕后,串口发送中断标志位TI置1,向CPU申请中断。

(2) 方式1接收

串口以方式1(SM0SM1=01)接收时(REN=1),数据从RXD引脚输入。当检测到起始位的负跳变,开始接收。

接收时,定时控制信号有两种,一种是接收移位时钟,它的频率和传送的波特率相同,另一种是位检测器采样脉冲,它的频率是接收移位时钟的16倍。也就是在1位数据器件,有16个采用脉冲,以波特率的16倍速率采样RXD引脚状态。

当采样到RXD端从1到0负跳变时,就启动接收检测器。接收的值是3次连续采样(第7、8、9个脉冲时采样),取两次相同的值,以确认是否是真正的起始位的开始,这样能够比较好地消除干扰引起的影响,保证可靠无误地开始接收数据。

当确认起始位有效时,开始接收一帧信息。接收每一位数据时,也都进行3次连续采样,接收的值是3次采样中至少两次相同的值,以保证接收到的数据位的准确性。

当一帧数据接收完毕后,必须同时满足以下两个条件,这次接收才真正有效。

  1. 当RI=0时,即上一帧数据接收完成时,RI=1发出的中断请求已被响应,SBUF中的数据已被取走,说明接收SBUF已空。
  2. SM2=0或收到的停止位=1(方式1时,停止位已进入RB8),则将接收到的数据装入SBUF和RB8(装入的是停止位),且中断标志RI置1。

如果不同时满足这两个条件,收到的数据不能装入SBUF,这表示该帧数据将丢失。

(3)方式1使用示例------双机通信

方式1可用来实现双机通信。两个单片机利用串口进行串行通信:串行通信的波特率由按键设定,可选的波特率为1200bps、2400bps、4800bps、9600bps。在工作方式1下进行全双工串行通信。

本示例通过按键得到设定的波特率,载入到T1的计数器中。运行时将数据0xaa从主机传输到从机,并显示到从机的LED上,从而验证串口通信的实现。

在实际的硬件实现中,如果串口通信线路过长,考虑采用MAX232进行电平转换,以延长传输距离。

为减少波特率的计算误差,采用11.0592MHz的晶振。

Proteus中两个单片机之间的串口通信接口设计原理电路如下图所示:

软件设计,因为是双机通信,有两个单片机,所以需要编写两份代码。其中一个单片机发送消息,另一个单片机接收消息。这里把发送消息的称为主机,接收消息的称为从机。

首先两个单片机的P1.0连接到K1,P1.1连接到K2,P1.2连接到K3,P1.3连接到K4,两份代码的按键扫描函数是一样的,如下:

c 复制代码
sbit K1=P1^0;
sbit K2=P1^1;
sbit K3=P1^2;
sbit K4=P1^3;

// 按键扫描函数,返回按下的按键序号,K1~K4序号为0~3,初始运行时如果没有按下按键,默认使用K2指示的波特率
uchar KeyScan()
{
	uchar keyscan_num, temp;
	
	P1=0xff;
	temp=P1;
	if(~(temp & 0xff))  // 当没有按键按下时,temp=0xff,temp&0xff=0xff,取反后为0不会进入条件语句
	{
		if(0==K1)
		{
			keyscan_num=0;
		}
		else if(0==K2)
		{
			keyscan_num=1;
		}
		
		else if(0==K3)
		{
			keyscan_num=2;
		}
		
		else if(0==K4)
		{
			keyscan_num=3;
		}
		else
		{
			keyscan_num=1;
		}
	}
	return keyscan_num;	
}

然后根据按下的按键设置对应的波特率,K1对应1200bps,K2对应2400bps,K3对应4800bps,K4对应9600bps。设置随影波特率的函数如下,在该函数中需要设置串口控制字、定时器T1工作方式、T1计数初值、打开中断允许等。

以1200bps波特率为例,另外的三个波特率只有计数初值不一样,其它都是一样的

c 复制代码
// 串口通信初始化,工作方式1,波特率为1200bps
void Init1200bps()
{
	
	// 1. 确定串口工作方式;确定定时器工作方式及计数初值
	SCON=0x50;  // 方式1 8位异步收发,允许接收数据
	PCON=0x00;  // 波特率不加倍
	TI=0;
	TMOD=0x20;  // 方式2,8位自动装载模式
	TH1=0xE8;
	TL1=0xE8;
	// 2. 打开串口中断允许位
	ES=1; 
	// 3. 打开CPU总中断允许位
	EA=1;
	// 4. 启动定时
	TR1=1;
}

各个波特率计数初值如下:

最后是主函数,master.c中的主函数中,循环获取哪个按键按下,根据按下的按键设置对应的波特率,然后发送数据。代码如下:

c 复制代码
/*
	实现功能:串口通信,方式1实现双机通信。
		主机代码:扫描按下的按键,根据按键设置波特率,发送数据
	[2024-01-12]
*/

#include <reg52.h>
#include "KeyFuncs.h"
#include "BAUDs.h"

typedef unsigned char u8;
typedef unsigned int u16;

u8 sendByte=0xaa;

void main()
{
	u8 keyPress;  // 获取哪个按键按下,使用对应的波特率
	
	while(1)
	{
		keyPress=KeyScan();
		switch(keyPress)
		{
			case 0: Init1200bps(); break;
			case 1: Init2400bps(); break;
			case 2: Init4800bps(); break;
			case 3: Init9600bps(); break;
		}
		SBUF=sendByte;  // 发送数据
		while(TI==0);  // 等待直到发送完成
		TI=0;  // TI软件清0
	}
}

slaver.c的主函数中,循环扫描按下的按键,根据按键设置对应的波特率,通过串口中断处理函数接收数据,并在LED上显示。代码如下:

c 复制代码
/*
	实现功能:串口方式1实现双机通信。
		从机代码:扫描按下的按键,根据按键设置波特率,在串口中断处理程序中接收数据。
	[2024-01-12]
*/
#include <reg52.h>
#include "KeyFuncs.h"
#include "BAUDs.h"

typedef unsigned char u8;
typedef unsigned int u16;

u8 reveiveByte;

void main()
{
	u8 keyPress;  // 获取哪个按键按下,使用对应的波特率
	
	while(1)
	{
		keyPress=KeyScan();
		switch(keyPress)
		{
			case 0: Init1200bps(); break;
			case 1: Init2400bps(); break;
			case 2: Init4800bps(); break;
			case 3: Init9600bps(); break;
		}
		while(RI==0);  // 等待直到接收数据
	}
}

// 接收到数据进入串口中断处理程序
void ReceiveDat() interrupt 4
{
	P2=SBUF;  // 将接收到的数据作用到P2口,P2口连接了8个LED
	RI=0;  // RI软件清0
}

仿真结果:

4.3.3 串口通信工作方式2使用

串口通信工作于方式2和方式3时,被定义为9位的异步通信接口。每帧数据均为11位,1位起始位+8位数据位(先低位)+1位可编程位+1位停止位。

方式2的波特率计算公式为: 2 S M O D 64 × f O S C \frac{2^{SMOD}}{64} \times f_{OSC} 642SMOD×fOSC

(1) 方式2发送

方式2在发送前,先根据通信协议由软件设置TB8(如双击通信时的奇偶校验位或多机通信时的地址/数据的标志位),然后将要发送的数据写入SBUF,即可启动发送过程。

串口能够自动把寄存器SCON中的TB8取出,并装入到第9位数据位的位置,再逐一发送出去。发送完毕,使TI置1。

(2) 方式2接收

当串行口的SCON寄存器的SM0SM1=10B,且REN=1时。允许串行口以方式2接收数据。

接收时,数据由RXD端输入,接收11位信息。当位检测逻辑采样到RXD引脚从1到0的负跳变,并判断起始位有效后,便开始接收一帧信息。

在接收完第9位数据后,需要满足以下两个条件,才能将接收到的数据送入接收缓冲器SBUF。

  1. RI=0,意味着接收缓冲器为空。
  2. SM2=0或接收到的第9位数据位RB8=1。

当满足上述两个条件时,接收到的前8位数据送入SBUF,第9位数据送入RB8,且RI置1.如果不满足这两个条件,接收到的信息将被丢弃。

4.3.4 串口通信工作方式3使用

SM0SM1=11时,串口被定义在方式3,方式3为波特率可变的9位异步通信方式,除了波特率外,方式3和方式2相同。

方式3的波特率计算: 2 S M O D 32 × T 1 溢出率 \frac{2^{SMOD}}{32} \times T1溢出率 322SMOD×T1溢出率。

相关推荐
时空自由民.22 分钟前
无人机系统耗电,低功耗管理问题解决方法(chatgpt)
单片机·嵌入式硬件·无人机
时空自由民.27 分钟前
无人机系统耗电,低功耗管理问题解决方法(腾讯元宝)
单片机·嵌入式硬件·无人机
清风6666662 小时前
基于单片机的双档输出数字直流电压源设计
单片机·mongodb·毕业设计·nosql·课程设计
牛马大师兄2 小时前
STM32独立看门狗IWDG与窗口看门狗WWDG知识梳理笔记
笔记·stm32·单片机·嵌入式硬件·嵌入式·看门狗
夜月yeyue2 小时前
STM32 Flash 访问加速器详解(ART Accelerator)
linux·单片机·嵌入式硬件·uboot·bootloard
A9better2 小时前
嵌入式开发学习日志37——stm32之USART
stm32·嵌入式硬件·学习
国科安芯6 小时前
ASP4644芯片低功耗设计思路解析
网络·单片机·嵌入式硬件·安全
充哥单片机设计6 小时前
【STM32项目开源】基于STM32的智能厨房火灾燃气监控
stm32·单片机·嵌入式硬件
CiLerLinux13 小时前
第四十九章 ESP32S3 WiFi 路由实验
网络·人工智能·单片机·嵌入式硬件
时光の尘13 小时前
【PCB电路设计】常见元器件简介(电阻、电容、电感、二极管、三极管以及场效应管)
单片机·嵌入式硬件·pcb·二极管·电感·三极管·场效应管