声明:本人跟随b站江科大学习,我的所有文章仅记录我的学习总结,以防我以后忘了,有地方回忆,况且江科大的资料都是开源的。我也希望大家多多去看江科大的视频,讲的是真的好,我的文章仅限看过视频学习过的,过段时间有些地方不清楚又懒得再看视频,可以快速查看知识点的。
一、串口的介绍
串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大的扩展了单片机的应用范围,增强了单片机系统的硬件实力。
51单片机内部自带UART (Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现 单片机的串口通信。
二、硬件电路
- 简单双向串口通信有两根通信线(发送端TXD和接收端RXD)
- TXD与RXD要交叉连接
- 当只需单向的数据传输时,可以直接一根通信线
- 当电平标准不一致时,需要加电平转换芯片
三、电平标准
电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
- TTL电平: +5V表示1,0V表示0
- RS232电平: -3~-15V表示1, +3~+15V表示0
- RS485电平:两线压差+2~+6V表示1, -2~-6V表示0 (差分信号)
- 注意:TTL电平和RS232电平最多传输10米的距离,再远就会出错,而RS485电平最多可传输一千米的距离
四、常见的通信接口比较
此外还有:CAN总线、USB等
- 全双工:通信双方可以在同一时刻互相传输数据
- 半双工:通信双方可以互相传输数据,但必须分时复用一根数据线
- 单工:通信只能有一方发送到另一方,不能反向传输
- 异步:通信双方各自约定通信速率
- 同步:通信双方靠一根时钟线来约定通信速率
- 总线:连接各个设备的数据传输线路(类似于一条马路,把路边各住户连接起来,使住户可以相互交流)
同步的一般都带有时钟线SCL/SCLK,异步的一般不带有时钟线 ;异步的一般都是双方预定好通信速率,设备发送10和1100,不同的通信速率,可能会导致接收的数据错误。比如设备A一秒发送一个数据,设备B却0.5秒进行一次采样,就会出现数据传输错误。
五、51单片机的UART
- STC89C52有1个UART
- STC89C52的UART有四种工作模式:
模式0:同步移位寄存器
模式1: 8位UART,波特率可变(常用)
模式2: 9位UART,波特率固定
模式3: 9位UART,波特率可变
六、串口参数及时序图
七、串口模式图
中间T1定时器模式为8位自动重装载(自动重装载时间更精确),靠定时器约定通信速率即波特率,设置波特率时SMOD为1是加倍。
波特率计算:
删除AUXR,波特率倍速一定要用
这里的F3十进制是243,算的是T1的溢出率,8位的计数器到256进行一次溢出,256-243=13,即
13us进行一次溢出,1/13us=0.07692MHz,0.07692MHz/16=0.00480769MHz=4807.69Hz,即波特率
八、串口和中断系统
当接收、发送完成产生中断进入中断系统
九、串口相关寄存器
十、代码
UART.c
#include <REGX52.H>
/**
* @brief 串口初始化
* @param 无
* @retval 无
*/
void UART_Init()//UART串口用的T1定时器,模式是8位自动重装载,//4800bps@12.000MHz
{
SCON=0x40;
PCON|= 0x80; //使能波特率倍速位SMOD
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式,当溢出时将TH1存放的值自动重装
//载入TL1
TL1 = 0xF3; //设定定时初值
TH1 = 0xF3; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
/**
* @brief 串口发送一个字节数据
* @param Byte 要发送的一个字节数据
* @retval 无
*/
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte;
while(TI==0);//这里是在等数据发送完,当数据发送完TI由硬件置1就会跳出循环
TI=0; //此时再由软件置0
}
main.c
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
unsigned char Sec;
void main()
{
UART_Init();
while(1)
{
UART_SendByte(Sec);
Sec++;
// Delay(1); //由于晶振的原因,波特率产生的误差,发的太快了就会出现错误,可以延时函数延时一下
Delay(1000);
}
}