51 单片机-串口通信
1 串口通信
1.1 需求描述
本案例讲解如何通过串口和PC以9600波特率,无校验位、1停止位通信。最终实现PC向单片机发送字符串,单片机回复PC。本案例中采用串口1通信。
1.2 硬件设计
1.2.1 串口工作原理
串口是将数据按照比特逐一发送的通信接口。在串口通信中,最重要的参数是波特率。在单片机中,波特率等于1s内传输的比特数。
串口通信中,要将波特率调整为9600,要求1秒钟内刚好发送9600个时钟信号,需要一个9600Hz的时钟源。单片机使用串口通信时,必须占用定时器1作为时钟源。定时器1每溢出1次,发送一个时钟信号。只要让它每秒钟溢出9600次即可。
串口通信需要占用定时器1,同时需要设置一些基本参数。
串口工作模式设置为1(8位UART,波特率可变)。
波特率要设置为9600。
1.1.2 串口具体设置
具体参数设置方式,需要配置串口通信,初始化流程如下:
1)SCON
SM0、SM1:本案例中采用 0、1工作方式。
SM2:在方式1时,如果SM2位为1,则只有在接收到有效的停止位时才置位中断请求标志位RI为1,如果SM2为0,则无论是否接收到有效的停止位都可以置位RI。官方推荐模式1,SM2应设置为0。
REN:允许/禁止串行接收控制位。由软件置位REN,即REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息。软件复位REN,即REN=0,则禁止接收。
TI:发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后必须用软件复位,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,必须用软件复位。
RI:接收中断请求标志位。在方式0,当串行接收到第8位结束时,由内部硬件自动置位RI=1,向主机请求中断,响应中断后必须用软件复位,即RI=0。在其他方式中串行接收到停止位的中间时刻由内部硬件置位,即RI=1,必须由软件复位即RI=0。
从以上内容中可以看出,我们应该进行如下设置:
SM0 | SM1 | SM2 | REN | TB8 | B8 | TI | RI |
---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
2)PCON
SMOD:波特率选择位。当用软件置位SMOD,即SMOD=1,则使串行通信方式1、2、3的波特率加倍;SMOD=0,则各工作方式的波特率加倍。复位时SMOD=0。
PCON的主要作用是波特率选择。
#define FOSC 11059200 // 晶振频率
#define NT 12 // 单片机的工作周期为12T
#define T2TEMP 256 - (FOSC / NT / 32 / BAUD_RATE)
3)SBUF
SBUF是串行口缓冲寄存器,地址为99H,实际上是2个缓冲器,发送SBUF和接收SBUF。写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。STC89C5xRC.H中已有如下声明。
sfr SBUF = 0x99;
对该变量赋值即可写入发送SBUF寄存器,读取该变量即可读取接收SBUF寄存器。
4)定时器1相关变量
目前为止我们已经可以通过设置TH1的值来设置串口波特率。TH1这个变量属于定时器1,也就是说当串口工作时,定时器1要被占用。关于定时器1的寄存器如下:
TL1/TH1:定时器相关变量:
其中关于定时器0的相关变量解释:
变量 | 作用 |
---|---|
TF1 | 定时器T1溢出标志。T1被允许计数以后,从初值开始加1技术。当最高位产生溢出时由硬件置“1”TF1,向CPU请求中断,一直保持到CPU响应中断时,才由硬件清“0”TF1。这一位的置位和清零都可以由硬件控制,不需要软件控制。 |
TR1 | 定时器1运行开关,置1开启定时器0,置0关闭定时器0 |
GATE | 计数器模式外部输入控制(定时器模式必须置为0) |
C/T(——) | 置0表示定时器模式,1表示计数器模式 |
M1、M0(低4bit) | M1=1,M0=0表示8位自动重载定时器,当溢出时将TL1存放的值自动重装入TH1. |
TL1 | 定时器1低8位寄存器 |
TH1 | 定时器1高8位寄存器 |
综上所述,最终串口的初始化代码如下:
//波特率
#define BAUD_RATE 9600
//定时器初始值
#define T2TEMP 256 - (FOSC / NT / 32 / BAUD_RATE)
void Dri_UART_Init()
{
// 设置串口工作模式
SM0 = 0;
SM1 = 1;
SM2 = 0;
REN = 1;
//接受和发送完成标识
//TI 1 :已经有数据
//TI 0 :无数据数据
//RI 1 :数据正在接收
//RI 0 :无数据在接收
TI = 1;
RI