串口通信
1、串口通信通俗理解
通过波形测试发现微控制器发送的波形是这样的,这是一帧完整的串行数据,一共有 10 位,且从左往右依次把数据给发送出去。
第 1 位是起始位,永远都是低电平;第 10 位是停止位,永远都是高电平。中间的是 8 个二进制数据。因为是二进制,所以第 1 位代表1,第 2 位代表2,第 3 位代表 4 ,以此类推,第 8 位代表 128 。
按照这个规律,我们把收到的这个 A 的波形的每一位相加 (1+64) ,最后的结果就是 65, 65 和 A 之间有什么关系呢?由 ASCII 码对照表中可以看出 65 正好对应的 A 。
需要注意的是在发送的时候必须要有时间间隔,时间间隔与通讯的波特率有关,例如波特率 9600 是 1 秒之内发送 9600 位这样的数据,也就是每一位数据之间的间隔为 100 us (\frac{1s}{9600} = 100us),按照这个规律,每隔 100 us 给电脑发送一次高低电平,电脑就能收到。
如果想要发送更快,可以选择更高的波特率,如果选择 115200 的波特率,则它在 1s 之内可以发送 115200 个数据,比刚才快了 10 多倍,则它发送的时间间隔应调整为 8.7 (\frac{1s}{115200} = 8.7us)。
2、串口通信基础知识
2.1 基础概念
通讯协议:分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输(通俗一点就是硬件部分)。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准(软件)。
串行通信接口:指按位发送和接收的接口。如 RS-232(标准串口) / RS-485 等
RS-232 接口(DB9): 传统接口为 DB25 ,目前基本被淘汰
-
数据(异步):
-
TXD : 串口数据输出
-
RXD:串口数据输入
-
-
握手(同步):
-
RTS :请求发送
-
CTS :清除发送
-
DSR : 数据发送就绪
-
DCD : 数据载波检测
-
DTR : 数据终端就绪
-
-
地线(同步异步):
-
GND
-
-
其他(同步):
-
RI :振铃指示
-
DB9 串行线:
串行通信一般是以帧格式传输数据,即是一帧一帧的传输,每帧包含有起始信号、数据信息、校验信息(由我们自己设置)、停止信号
物理层:
电平标准:数据 0 和数据 1 的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有三种。
-
TTL 电平:+3.3V 或 +5V 表示 1 ,0V 表示 0
-
RS-232 电平:-3 ~ -15V 表示 1 ,+3 ~ +15V 表示 0
-
RS-232 电平一般在大型的机器上使用。由于环境可能比较恶劣,静电干扰比较大,所以电平电压都比较大,而且允许波动的范围也很大
-
-
RS-485 电平:两线压差 +2 ~ +6V 表示 1 ,-2 ~ -6V 表示 0 (差分信号)
-
抗干扰能力强
-
电平转换:
RS-232 <---> TTL :
TTL 与 RS-232 标准逻辑相反,而且电平也大不相同,若单片机与单片机或其他 TLL 设备通信采用 RS-232 通信,肯定先要进行电平的转化 ( TTL -> RS-232 RS-232 -> TTL )。
两个通讯设备的 DB9 接口 之间通过串口信号线建立起连接,串口信号线中使用 RS-232 标准 传输数据信号。由于 RS-232 电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个电平转换芯片转换成控制器能识别的 TTL 标准 的电平信号,才能实现通讯。
电平转换芯片一般有 MAX3232 、SP3232 。
USB转串口:
主要用于设备(如STM32)与电脑通信。电平转换芯片一般有 CH340 、PL2303 、CP2102 、FT232 ,使用的时候电脑要按照电平转换芯片的驱动(虚拟出一个串口)
注:以下内容是基于 TTL 电平
串行通信 and 并行通信:
特点 | 传输速度 | 抗干扰能力 | 通讯距离 | IO资源占用 | 成本 |
---|---|---|---|---|---|
串行通信 | 较低 | 较强 | 较长 | 较少 | 较低 |
并行通信 | 较高 | 较弱 | 较短 | 较多 | 较高 |
按照数据传输方向,分为:
-
单工:数据传输只支持数据在一个方向上传输。
-
半双工:允许数据在两个方向上传输,但是在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信。
-
全双工:允许数据同时在两个方向上传输,因此全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
按照数据同步方式,分为:
-
同步通信:共用同一时钟信号
-
异步通信:没有时钟信号,通过在数据信号中加入起始位和停止位等一些同步信号
如何区分同步通信和异步通信:判断是否有时钟信号
比特率和波特率:
-
比特率:每秒传送的比特数,单位 bit/s
-
波特率:每秒传送的码元数,单位Baud
-
比特率 = 波特率 * log2 M,M表示每个码元承载的信息量
-
二进制系统中,波特率数值上等于比特率
2.2 常见的串行通信接口
2.3 协议层
串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致(一样的起始位 数据 校验位 停止位)才能正常收发数据。
-
启动位:必须占一个位长,保持逻辑 0 电平
-
有效数据位:可选 5、6、7、8、9 个位长, LSB 在前, MSB 在后
-
校验位:可选占1个位长,也可以没有该位
-
停止位:必须有,可选占 0.5、1、1.5、2 个位长,保持逻辑 1 电平
2.4 USART 功能框图(M4)
2.4.1 功能引脚
2.4.2 读写单元
注意:
灰色框里的寄存器 用户是无法访问的,它是芯片内部工作自行处理的,用户能看见的、能操作的寄存器是(数据寄存器)DR。
所以要让串口发送数据,就要往 USART_DR 寄存器里写入操作。操作写完之后 DR 寄存器的值会自动的传到 TDR 寄存器,之后 TDR 寄存器会等到我们这个发送移位寄存器空里没有数据时,自动地传入进来。
流程如下:
STM32F1/F4/F7/H7 的 USART 框图简化版如下:
2.4.3 控制单元
接收器控制还会受到这个唤醒单元的唤醒作用,而发送控制是没有受到唤醒单元的一个唤醒的。因为发送数据是 CPU 主动发送,本来就是醒的,不用唤醒。如果是接收的话,比如 STM32 进入睡眠时,如果接收到数据,那么就由唤醒单元把它唤醒。
3、 USART 相关固件库函数
3.1 USART 初始化结构体
typedef struct { uint32_t USART_BaudRate; // 波特率 uint16_t USART_WordLength; // 字长 uint16_t USART_StopBits; // 停止位 uint16_t USART_Parity; // 校验位 uint16_t USART_Mode; // USART 模式 uint16_t USART_HardwareFlowControl; // 硬件流控制 } USART_InitTypeDef;
-
USART_BaudRate:波特率设置。一般设置为 2400、9600、19200、115200。标准库函数会自己计算计算得到 USARTDIV 值,从而写入USART_BRR 寄存器。
-
USART_WordLength:数据帧字长,可选 8 位或 9 位。它设置了USART_CR1 寄存器的 M 位的值。如果没有使能奇偶校验位,一般使用 8 数据位;如果使能了奇偶校验则一般设置为 9 数据位,最后一位是奇偶校验位。
-
USART_StopBits:停止位设置,可选 0.5 个、1 个、1.5 个和 2 个停止位,它设定USART_CR2 STOP位,一般我们选择 1 个停止位。
-
USART_Parity : 奇 偶 校 验 控 制 选 择 ,USART_CR1 寄存器的 PCE 位和 PS 位的值。
-
USART_Mode:USART 模式选择,有 USART_Mode_Rx 和 USART_Mode_Tx,允许使用逻辑或运算选择两个,USART_CR1 寄存器的 RE 位和 TE 位。
-
USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,可选有⑴使能 RTS、⑵使能 CTS 、⑶同时使能 RTS 和 CTS、⑷不使能硬件流。
3.2
(1)串口时钟和 GPIO 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1 时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能 GPIOA 时钟
(2) 设置引脚复用器映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //PA9 复用为 USART1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//PA10 复用为 USART1
(3)GPIO 端口模式设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9 与 GPIOA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度 50MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA9,PA10
(4)串口参数初始化:设置波特率,字长,奇偶校验等参数
USART_InitStructure.USART_BaudRate = bound; //一般设置为 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为 8 位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位 USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口
(5)使能串口
USART_Cmd(USART1, ENABLE); //使能串口
(6)