1、串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大的扩展了单片机的应用范围,增强了单片机系统的硬件实力。51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机的串口通信。
2、串口的硬件电路:
(1)简单双向串口通信有两根通信线(发送端TXD和接收端RXD)。
(2)TXD与RXD要交叉连接。
(3)当只需单向的数据传输时,可以直接一根通信线。
(4)当电平标准不一致时,需要加电平转换芯片。
(附)电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
①TTL电平:+5V表示1,0V表示0
②RS232电平:-3~-15V表示1,+3~+15V表示0
③RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)
3、常见的通讯接口比较:
名称 | 引脚定义 | 通信方式 | 特点 |
UART | TXD、RXD | 全双工、异步 | 点对点通信 |
I2C | SCL、SDA | 半双工、同步 | 可挂载多个设备 |
SPI | SCLK、MOSI、MISO、CS | 全双工、同步 | 可挂载多个设备 |
1-Wire | DQ | 半双工、异步 | 可挂载多个设备 |
此外还有:CAN、USB等。
4、相关术语:
(1)全双工:通信双方可以在同一时刻互相传输数据。
半双工:通信双方可以互相传输数据,但必须分时复用一根数据线。
单工:通信只能有一方发送到另一方,不能反向传输。
(2)异步:通信双方各自约定通信速率。
同步:通信双方靠一根时钟线来约定通信速率。
(3)总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)。
5、STC89C52有1个UART,STC89C52的UART有四种工作模式:
模式0:同步移位寄存器
模式1:8位UART,波特率可变(常用)
模式2:9位UART,波特率固定
模式3:9位UART,波特率可变
6、串口参数及时序图:
(1)波特率:串口通信的速率(发送和接收各数据位的间隔时间)。
(2)检验位:用于数据验证。
(3)停止位:用于数据帧间隔。
7、串口模式图:
(1)SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器;读操作时,读出的是接收寄存器。
(2)TH1、TL1一部分与波特率有关(这也是为什么初始化串口的时候需要配置定时器1,不过定时器1的中断和串口的中断是有区别的,定时器1只是负责控制波特率,并不需要处理中断,串口的中断与TI和RI有关)。
(3)数据是一帧一帧进行传输的,当发送完一帧数据时,内部硬件自动置为TI,即TI=1,这时就会请求中断处理;当接收完一帧数据时,内部硬件自动置为RI,即RI=1,这时也会请求中断处理。(TI和RI被置为1后要在中断函数内将其置为0,否则中断不会停止)
8、串口和中断系统:
9、串口相关寄存器:
10、数据显示模式:
(1)HEX模式/十六进制模式/二进制模式:以原始数据的形式显示。
(2)文本模式/字符模式:以原始数据编码后的形式显示。
11、串口向电脑发送数据:
(1)借助STC-ISP的波特率计算器快速获取配置Uart的子函数:
注:AUXR开头的两行去掉。
(2)项目包含的文件:其中需要重写的都会在下面给出,未给出的沿用旧例出现过的即可。
(3)补充代码,然后进行编译。
①UART.h文件:
#ifndef __UART_H__
#define __UART_H__
void UART_Init(void);
void UART_SendByte(unsigned char Byte);
#endif
②UART.c文件:
#include <REGX52.H>
/**
* @brief 串口初始化,4800bps@11.0592MHz
* @param 无
* @retval 无
*/
void UART_Init(void)
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x40;
//SM0、SM1分别配置为0和1,使串口工作在模式1
//REN置为0,单片机在该例中不需要接收数据(置为1也无妨)
//初始化不需要请求中断,TI和RI置为0
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xF4; //设定定时初值
TH1 = 0xF4; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
/**
* @brief 串口发送一个字节数据
* @param Byte:要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF = Byte; //将数据写入SBUF中
while(TI == 0); //TI为0,说明数据还没全部传进SBUF
TI = 0; //数据传送完成,TI置为1,产生中断,SBUF将数据传到电脑,中断处理完成后TI置为0
}
③main.c文件:
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
unsigned char sec = 0;
void main()
{
UART_Init();
UART_SendByte(0x56); //在进入死循环前就往电脑发送数据
//由于单片机的速度很快,串口没来得及打开数据就传送完成,然后进入死循环
//要想在串口助手观察0x56的输出,就要在打开串口后按下复位键,强制将程序回滚到main函数的第一句
while(1)
{
UART_SendByte(sec); //一直往串口发送逐秒递增的数字
sec++;
Delay(1000); //时间间隔为1秒
}
}
(4)将生成的.hex文件下载到开发板中,马上打开串口助手,可以看到电脑每隔一秒就会接收到一个递增的数字(十六进制),按下复位按键后电脑会马上接收到56,紧接着开始接收从0开始每秒递增1的数字。
12、电脑通过串口控制LED:
(1)往项目中添加如下代码文件,然后进行编译:
①UART.h文件:
#ifndef __UART_H__
#define __UART_H__
void UART_Init(void);
void UART_SendByte(unsigned char Byte);
#endif
②UART.c文件:
#include <REGX52.H>
/**
* @brief 串口初始化,4800bps@11.0592MHz
* @param 无
* @retval 无
*/
void UART_Init(void)
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50;
//SM0、SM1分别配置为0和1,使串口工作在模式1
//REN置为1,单片机在该例中需要接收数据
//初始化不需要请求中断,TI和RI置为0
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xF4; //设定定时初值
TH1 = 0xF4; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA = 1; //启动串口中断
ES = 1; //启动串口中断
}
/**
* @brief 串口发送一个字节数据
* @param Byte:要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF = Byte; //将数据写入SBUF中
while(TI == 0); //TI为0,说明数据还没全部传进SBUF
TI = 0; //数据传送完成,TI置为1,产生中断,SBUF将数据传走,中断处理完成后TI置为0
}
/*串口中断函数模板
void UART_Routine() interrupt 4 //串口中断的中断号是4
{
if(RI == 1) //发送和接收都会产生串口中断,如果是接收中断,执行下面代码段
{
RI = 0; //将RI置为0,准备下次接收中断的到来
}
}
*/
③main.c文件:
#include <REGX52.H>
#include "UART.h"
unsigned char sec = 0;
void main()
{
UART_Init();
P2 = 0xFF; //初始化LED灯全灭
while(1)
{
}
}
void UART_Routine() interrupt 4 //串口中断的中断号是4
{
if(RI == 1) //发送和接收都会产生串口中断,如果是接收中断,执行下面代码段
{
P2 = ~SBUF; //读取SBUF的内容,取反赋给P2寄存器
UART_SendByte(SBUF); //将发送给单片机的数据通过串口再传回电脑
RI = 0; //将RI置为0,准备下次接收中断的到来
}
}
(2)将生成的.hex文件下载到开发板中,然后打开串口助手,发送“00”LED灯全灭,发送“FF”LED灯全亮。