C51 6.串口
前言
C51内部自带UART(通用异步收发器),可实现单片机的串口通信。
祝愉快
1.硬件电路(UART)
- UART为全双工、异步、点对点通信
- 发送端TXD,接收端RXD
- TXD和RXD要交叉连接
- 单向传输数据时可以只用一根线通信
- 当电平标准不一致时,要加电平转换芯片(C51标准为TTL)
2.串口模式图
串口
C51手册的图
我们简化为如下
- 我们要打开定时器1,当定时器1的TH1、TL1溢出时,我们推出TI或RI。
- SBUF为串口数据缓存寄存器,物理上是两个独立的寄存器,但是占用相同的地址。
- 写操作时,写入的是发送寄存器。
- 读操作时,读取的是接收寄存器。
- 我们其实操作的就是SBUF寄存器。
串口和中断系统
打开中断就可以了。
3.串口相关寄存器
SCON
-
SM0/FE:为1时,用于帧错误检测。当检测到一个无效停止位时,通过UART接收器设置该位。必须由软件清零。为0时,和SM1一起指定串行通信的工作方式
-
其中SM0、SM1按如下组合确定串口的工作模式,我们常用方式1
-
-
SM2:允许方式2或方式3多机通信控制位。
-
REN:允许/禁止串行接收控制位。由软件置位,1为允许,可启动串行接收器RxD,开始接收数据。0则为禁止。
-
TB8:在方式2或方式3,它为要发送的第9位数据,按需要由软件置位或清零。
-
RB8:在方式2或方式3,是接收到的第9位数据。在方式1,若SM2=0,则RB8是接收到的停止位。方式0不用RB8。
-
TI:发送中断请求标志位。在方式0,当串口发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后必须用软件复位,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,必须用软件复位。
-
RI:接收中断请求标志位。在方式0,当串口发送数据第8位结束时,由内部硬件自动置位,即RI=1,向主机请求中断,响应中断后必须用软件复位,即RI=0。在其他方式中,则在停止位的中间时刻由内部硬件置位,必须用软件复位。
PCON
SBUF
SADEN和SADDR
- SADEN为从机地址掩模寄存器(地址为B9H,复位值为00H)
- SADDR是从机地址寄存器(地址为A9H,复位值为00H)
4.串口工作模式1:8位UART 波特率可变
当SM0、SM1为“01”时,串行通信以模式1工作。此模式为UART格式,一帧信息为10位:1位起始位,8位数据位(低位在先)和1位停止位,波特率可变。
TxD为发送信息,RxD为接收端接收信息,串口为全双工接受/发送串行口。
时序图
5.C代码
发数据
#include <REGX52.H>
/**
* @brief 串口初始化,4800bps@12.000MHz
* @param 无
* @retval 无
*/
void UART_Init()
{
SCON=0x40; //配置串口 0100 0000
PCON |= 0x80; //配置串口 10xx xxxx
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
/**
* @brief 串口发送一个字节数据
* @param Byte 要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte; //对SBUF写操作
while(TI==0); //保持TI为0
TI=0; //TI被硬件置1了,我们手动置0
}
收数据
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
void main()
{
UART_Init(); //串口初始化
while(1)
{
}
}
void UART_Routine() interrupt 4 //中断号4
{
if(RI==1) //如果接收标志位为1,接收到了数据
{
P2=~SBUF; //读取数据,取反后输出到LED 对SBUF读操作
UART_SendByte(SBUF); //将受到的数据发回串口
RI=0; //接收标志位清0 接收完成后RI被硬件置1,我们手动对RI清0
}
}
子函数
#include <REGX52.H>
/**
* @brief 串口初始化,4800bps@12.000MHz
* @param 无
* @retval 无
*/
void UART_Init()
{
SCON=0x50;
PCON |= 0x80;
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA=1;
ES=1;
}
/**
* @brief 串口发送一个字节数据
* @param Byte 要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;
while(TI==0);
TI=0;
}
/*串口中断函数模板
void UART_Routine() interrupt 4
{
if(RI==1)
{
RI=0;
}
}
*/
总结
UART内容很多,想更加了解可以去看看手册。
本文基本没讲时序图,有兴趣可以自行了解。
C语言层面比硬件方面简单很多,我们关注TI、RI,然后对SBUF进行读写就可以了。