USART_STM32

本文详细介绍了STM32中的USART串口通信原理,包括通信协议、硬件电路、电平标准、时序参数、USART外设功能、配置流程以及数据包处理。还提供了如何使用printf函数移植和数据包编码实例。
摘要由CSDN通过智能技术生成

一、串口通信

1.1 通信协议简介

  • 通信的目的:将一个设备的数据传输到另一个设备,扩展硬件系统
  • 通信协议:制定通信的规则,通信双方按照协议规则进行数据收发
  • 常用通信协议:
    在这里插入图片描述
  • 异步通信和同步通信的区别在于是否有时钟线连接两端

1.2 串口通信协议简介

串口是一种应用广泛的通讯接口,可实现两个设备的互相通信,包括单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信。

1.2.1 硬件电路

在这里插入图片描述

  • 简单双向串口通信有两根通信线(发送端TX和接收端RX)
  • 通信线TX、RX需要交叉连接
  • 设备均有独立供电时,VCC可不接
  • 当电平标准不一致时,需要加电平转换芯片

1.2.2 电平标准

  • 电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系。(即多少电压判定为1,多少判定为0
  • 串口常用的电平标准:
    • TTL电平:+3.3V或+5V表示1,0V表示0
    • RS232电平:-3至-15V表示1,+3至+15V表示0;一般用于大型设备
    • RS485电平:两线压差+2至+6V表示1,-2至-6V表示0(差分信号);抗干扰能力强,一般用于远距离通信

1.2.3 串口参数及时序

  • 串口通信可以选择在8位数据位的最后是否加一个校验位
  • 波特率:因为串口通信是异步通信,所以需要规定串口通讯的速率
    • tips:波特率为每秒传输码元速率,比特率才是每秒传输比特速率,但在二进制中两者数值相等。
  • 起始位:标志一个数据帧的开始,固定为低电平。(因为串口通信的空闲状态固定为高电平)
  • 数据位:数据帧的有效载荷,存储8位数据,1高0低,低位先行(即从数据的低位开始倒着发)
  • 校验位:用于数据验证,判断是否发送错误,根据数据位计算得来。
    • 无校验、奇校验(保证9位数据位中共有奇数个1)、偶校验(…共有偶数个1)、CRC校验(循环冗余校验)
  • 停止位:用于数据帧间隔,固定为高电平。

在这里插入图片描述


二、USART外设

2.1 USART简介

  • USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器
    • USART主要使用异步模式。此处的“S”同步收发,只有时钟输入没有时钟输出,一般用于特殊用途。
  • USART是STM32内部集成的硬件外设,其功能作用是:可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里。(即外设自动完成串口收发的相关流程操作,用户只需要读写数据寄存器即可
  • USART外设自带波特率发生器,最高达4.5Mbits/s
  • USART外设可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)、可选校验位(无/奇/偶校验)
  • 还支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN
    • 硬件流控制:数据接收端会给发送端反馈接收完成信号,防止接收混乱数据丢失。
  • STM32F103C8T6 USART资源: USART1、 USART2、 USART3

2.2 USART基本结构

在这里插入图片描述

  • 写操作时:程序将数据写入发送数据寄存器TDR,USART自动将数据转入发送移位寄存器并一位一位转换为电平信号发送。
    • 关键标志位,TXE空,表示发送数据寄存器空,可以写入下一个数据。
  • 读操作时:RX引脚接收到电平信号,接受移位寄存器一位一位的接收信号转换为二进制数据,一个字节完成接收后,USART自动将数据转入接收数据寄存器RDR。
    • 关键标志位:RXNE非空,表示接收寄存器非空,可以读取当前数据。
  • 波特率发生器本质上为分频器,用于对时钟分频,得到收发波特率。
  • 发送/接收控制器用于控制收发功能的使能/失能。
  • 硬件流控制:用于避免丢弃/覆盖数据的现象,具体略。
  • 配置流程:开启USART和GPIO的RCC时钟 → 配置GPIO → 配置USART → (如果需要接收的功能)配置USART中断和NVIC → 开关控制

2.3 起始位侦测与数据采样

  • 为了每次采样都能够采样到每一帧数据电平的正中间,采样时钟以16倍的波特率对电平采样,即一帧数据采样16次。
  • 起始位侦测:在采样出现0后,判断接下来16次的采样结果,每3次采样中至少有2次为0,则该帧为起始位,否则判定为噪声。
  • 数据采样:每帧16次的采样时钟,选择位于中间的“8,9,10”次采样的结果作为该帧数据的值,存在噪声时,少数服从多数,并置噪声标志位为1。

三、配置USART

'1. 开启USART/GPIO的RCC时钟'
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
'2. 配置GPIO'
// 需要配置TX引脚为复用推挽输出模式,RX引脚为输入模式(浮空/上拉)
// GPIO功能表中,GPIOA的PA9口为USART1_TX脚,PA10为USAR1T_RX脚
'3. 配置USART'
// 一般使用“8位数据位长度,无校验”或“9位数据位长度,奇/偶校验”的组合
USART_InitTypeDef* USART_InitStructure;				// 定义结构体变量
USART_InitStructure.USART_BaudRate = 9600;			// 配置波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx;		// 串口模式,如果Tx/Rx都需要使用,则写入USART_Mode_Tx | USART_Mode_Rx
USART_InitStructure.USART_Parity = USART_Parity_No;	// 校验位选择,选择无/奇/偶校验
USART_InitStructure.USART_StopBits = USART_StopBits_1;		// 停止位长度选择,可选0.5/1/1.5/2位的停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;	// 数据位长度,可选8/9位
USART_Init(USART1, &USART_InitStructure);
'4. (如果需要Rx接收的功能)配置USART中断和NVIC'
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);		// 开启RXNE标志位中断控制 
// NVIC配置略,见EXTI
'5. 开关控制'
USART_Cmd(USART1, ENABLE);
'补充1:典型发送数据函数编写'
void SendByte(uint8_t Byte)
{
	USART_SendByte(USART1, Byte);		
			// 写入数据寄存器以发送数据
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
			// 等待TXE发送数据寄存器空标志位置1,表示数据发送完成,该标志位会自动清零
}
'补充2:典型接收数据函数编写'
// 接收数据有两种方法:查询和中断
// 查询即一直判断RXNE标志位是否置1,置1后读取DR寄存器。
// 但一直判断标志位的过程程序无法进行其他工作,因此不常用,一般使用中断方法。
// 中断方法:配置好中断和NVIC后,在编写中断函数读取数据寄存器即可
uint8_t RxData;
void USART1_IRQHandler(viod)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)	// 判断中断标志位是否置1
	{
		RxData = USART_ReceiveData(USART1);
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);		
			// 清除中断标志位,此处其实读取DR后会自动清除,但手动再清一下也没事 
	}
}

四、USART常用库函数

void USART_DeInit(USART_TypeDef* USARTx);
		// 复位函数
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
		// USART初始化函数
void USART_StructInit(USART_InitTypeDef* USART_InitStruct);
		// 结构体初始化函数
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
		// 开关控制函数
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
		// 中断控制函数
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
		// 写入数据寄存器
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
		// 读取数据寄存器
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
		// 获取标志位
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
		// 清除标志位
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
		// 获取中断标志位
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
		// 清除中断标志位
'其他函数都用于USART的其他各种功能模式,用的不多'
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);
		// 以上两个函数用于配置同步模式时的时钟
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);
		// 用于开启USART到DMA的通道
'略'

五、数据包

  • 在传输多字节数据时,将数据分组,并以规定一定的格式“打包”,以“数据包”为单位进行收发数据可以防止出现数据错位现象。
  • 通常,可以设置固定的数据作为“包头”/“包尾”,可以设置每个数据包的长度为固定/不固定。不同形式排列组合使用有不同效果。
  • 发送数据:把数据按照规定的格式“打包”成数组/结构体,指针依次指向每个成员发送即可。
  • 接收数据:接收到数据后需要根据不同的状态判断该数据为“包头”/“包尾”/“内容”
    • 状态机:在不同状态执行不同的操作,并且能够进行状态的转移。
      在这里插入图片描述

六、补充

printf函数的移植方法

  • MDK5中,魔术棒→Target→勾选Use MicroLIB
  • 重定向,因为printf默认是输出至屏幕,需要改为输出至串口
    • 头文件加上#include <stdio.h>
    • 编写函数:
      int fputc(int ch, FILE *f)
      {
      	SendByte(ch);
      	return ch;
      } 
      
  • 此时直接使用printf打印,就会输出至串口

也可以使用sprintf函数打印

  • sprintf函数可以指定打印位置,将数据打印至一个字符串中,然后通过编写的串口发送函数发送该字符串即可。
  • 封装sprintf,略(sprintf为可变参数函数)

Reference
STM32入门教程-2023版(江科大)

数据包代码实例:视频[9-5]
FlyMcu使用介绍:视频[9-6]

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
USART (Universal Synchronous/Asynchronous Receiver/Transmitter) 是一种用于串行通信的通信协议,它允许数据在串行线上进行双向传输。OpenMV 是基于Python的机器视觉平台,它可以与STM32F407微控制器一起使用。 在使用USART进行双向通信之前,我们需要先为STM32F407配置USART的参数。具体步骤如下: 1. 首先,我们需要在STM32F407上启用USART模块。可以通过STM32CubeMX工具进行配置。选择USART4或其他可用USART,设置其工作模式为全双工,并根据需要进行其他设置,例如波特率。 2. 然后,我们需要在OpenMV上实现对应的代码。首先,我们需要初始化OpenMV的串口对象,指定波特率等参数: ```python import serial # Initialize the serial port serial_port = serial.Serial("/dev/ttyUSB0", baudrate=115200, timeout=1) ``` 在上述代码中,我们使用PySerial库初始化串口对象,指定串口设备路径、波特率和超时时间。 3. 接下来,我们可以使用OpenMV的串口对象进行数据传输。例如,我们可以通过串口发送数据: ```python # Send data through the serial port serial_port.write(b'Some data') ``` 在上述代码中,我们调用串口对象的write()方法发送数据。在这里,我们发送了一个字符串`"Some data"`。 4. 同样地,我们可以使用串口对象接收从STM32F407发送过来的数据: ```python # Receive data through the serial port received_data = serial_port.read(10) ``` 在上述代码中,我们调用串口对象的read()方法接收长度为10的数据。将接收到的数据存储在`received_data`变量中。 通过上述步骤,我们可以实现OpenMV与STM32F407之间的双向通信。我们可以使用STM32F407发送数据到OpenMV,然后从OpenMV接收数据,并且反之亦然。注意,我们需要确保STM32F407和OpenMV之间的串口参数是匹配的,例如波特率和数据位数。 总而言之,使用USART进行双向通信需要在STM32F407和OpenMV上分别进行配置和代码编写。这样,我们可以实现两者之间可靠的数据传输。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值