U(S)ART 串口应用

文章目录

单片机的U(S)ART

  • 以stm32u575为例

逻辑框图

不同UART接口的类型

不同U(S)ART接口类型的主要属性

U(S)ART的使用

  • 以stm32u575为例

发送数据

寄存器配置过程

  • 在USART_CR1寄存器中编程M位以定义字长,字长默认是8bit,但可以选 7, 8, 9bit
  • 使用USART_BRR寄存器选择所需的波特率,常见的有 9600,19200,38400,57600,115200,230400
  • 在USART_CR2寄存器中编程停止位的数量,停止位,默认是1bit,但可以选 1.5bit, 2 bit
  • 通过将USART_CR1寄存器中的UE位写1来使能USART
  • 如果需要进行多缓冲通信,则在USART_CR3寄存器中选择DMA使能(DMAT)。并按照"使用USART和DMA的连续通信"中的说明配置DMA寄存器

DMA,即 Direct Memory Access,可以在无需处理器干涉的情况下,直接完成数据在存储器和外设之间的传递,例如发送数据,可以直接从内存写入串口的发送数据寄存器,直到需要发送的数据都通过该寄存器发送完成,才触发中断

发送数据过程

  • 设置USART_CR1中的TE位以发送空闲帧作为首次传输(可选步骤)

此处,"帧"的概念为从起始位到停止位的一串数据流

  • 将要发送的数据写入USART_TDR寄存器。如果是单缓冲模式,则对每个待发送数据重复此操作
    • 当FIFO模式禁用时,向USART_TDR写入数据会清除TXE标志。
    • 当FIFO模式启用时,向USART_TDR写入数据会将一个数据添加到TXFIFO中。写入USART_TDR的操作需在TXFNF标志置位时进行,该标志会保持置位直到TXFIFO满。
  • 当最后一个数据写入USART_TDR寄存器后,等待TC=1
    • 当FIFO模式禁用时,表示最后一帧传输完成
    • 当FIFO模式启用时,表示TXFIFO和移位寄存器均为空
    • 此检查是为了避免在USART禁用或进入停机模式时损坏最后一次传输

发送相关中断

中断事件 中断标志 中断使能位 中断清除方法
TDR 空 TXE TXEIE 写 TDR
TXFIFO 不满 TXFNF TXFNFIE 写满 TXFIFO
TXFIFO 空 TXFE TXFEIE 写 TDR 或向 TXFRQ 位写 1
达到 TXFIFO 阈值 TXFT TXFTIE 写 TDR

发送两种模式

阻塞(轮询模式)
  • 阻塞:指处理器一直等待该过程处理完成才转入下一个流程,如字符串 "Hello World" 的发送
c 复制代码
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t
                                    *pData, uint16_t Size, uint32_t Timeout)
非阻塞(中断模式)
  • 中断是处理器非阻塞模式之一(另一种是DMA+中断方式),指处理器启动过程后,不必一直等待该过程处理完毕,而是可以通过完成的中断来获取完成的消息。启动处理过程后,可以转向处理其他的流程
c 复制代码
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t
                                        *pData, uint16_t Size);

//回调函数
//所有数据发送完成
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
//发送缓冲区空(TXFE引发)
void HAL_UARTEx_TxFifoEmptyCallback(UART_HandleTypeDef *huart);

HAL_UART_Transmit_IT() 调用一次后,发送完成,即取消发送中断状态!需要手动再次调用HAL_UART_Transmit_IT()

FIFO的使用

  • FIFO是部分单片机每个串口硬件特有的缓冲区

接收数据

起始位和数据位的检测

起始位
数据位

寄存器配置过程

  • 配置USART_CR1寄存器的M位以定义字长(数据位长度)。
  • 通过波特率寄存器USART_BRR设置所需的通信波特率。
  • 在USART_CR2寄存器中编程设定停止位的数量。
  • 将USART_CR1寄存器的UE位置1以启用USART模块。
  • 若需多缓冲区通信,则需在USART_CR3寄存器中使能DMA(设置DMAR位),并按照"使用USART和DMA实现连续通信"的内容说明配置DMA寄存器。
  • 将USART_CR1寄存器的RE位置1,使能接收器开始搜索起始位

接收数据过程

  • FIFO模式禁用时:RXNE位会被置1,表示移位寄存器的内容已传输至RDR(接收数据寄存器),即数据已接收完成并可读取(同时包含相关错误标志)。
  • FIFO模式启用时:RXFNE位会被置1,表示接收FIFO非空。读取USART_RDR将返回FIFO中最先存入的数据。接收的数据会与对应的错误位一同存入RXFIFO。
  • 若RXNEIE位(FIFO模式启用时为RXFNEIE位)被置1,则会产生中断。
  • 若检测到帧错误、噪声、奇偶校验错误或接收溢出错误,则会置位相应的错误标志位。四个错误检测标志:
    • 溢出错误:之前的数据未处理,新收到了数据
    • 帧错误:未在约定的时间范围内检测到结束位
    • 奇偶校验错误:校验位不符合约定的奇偶校验规则
    • 噪声检测:过采样过程,中心点采样,3次采样,结果不一致

接收相关中断

中断事件 中断标志 中断使能位 中断清除方法
RDR 不为空 RXNE RXNEIE 读 RDR 或向 RXFRQ 写入 1
RXFIFO 不为空 RXFNE RXFNEIE 读 RDR 直到 RXFIFO 空或向 RXFRQ 写入 1
RXFIFO 满 RXFF RXFFIE 读 RDR
达到 RXFIFO 阈值 RXFT RXFTIE 读 RDR
溢出错误 ORE RXNEIE/RXFNEIE 向 ORECF 写 1
检测到数据线空闲 IDLE IDLEIE 向 IDLECF 写 1
奇偶校验错误 PE PEIE 向 PECF 写 1

接收两种模式

阻塞(轮询)模式
c 复制代码
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData,
                                    uint16_t Size, uint32_t Timeout);
非阻塞(中断)模式
c 复制代码
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData,
                                        uint16_t Size);
//回调函数
//接收数据长度达到预设值引起的
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
//RXFF引起
void HAL_UARTEx_RxFifoFullCallback(UART_HandleTypeDef *huart);

注意: HAL_UART_Receive_IT() 每调用一次,接收到要求长度的数据后,即取消接收中断状态,不再接收新的数据!需要重新手动开启接收中断

接收不定长数据

  • 接收过程配合使用空闲(IDLE)中断
c 复制代码
HAL_StatusTypeDef HAL_UARTEx_ReceiveTodle_IT(UART_HandleTypeDef *huart, uint8_t
                                                *pData, uint16_t Size);
//回调函数
//IDLE引起
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);

注意: HAL_UARTEx_ReceiveToIdle_IT() 每调用一次,接收时检测到空闲中断或者接收到要求长度的 数据后,即取消接收所有中断状态,不再接收新的数据!

print函数发送实现原理

  • printf()函数是通过调用库中的字符输出函数(不同的编译器,使用的库函数略有差异)实现数据的输出,字符输出函数默认是把字符输出到调试器控制窗口,要把数据通过USART输出到串口,需对字符输出函数重定向到USART端口上去

方式一:使用MicroLib库

  • 在Keil MDK的STM32工程中,点击魔术棒,打开工程配置界面

MicroLib是一个专为深度嵌入式系统设计的C库,优化了代码和数据内存使用,适合在没有操作系统的环境中运行。 相较于标准C库,MicroLib不包含文件I/O和宽字符支持,且某些函数执行速度可能较慢

  • fputc() 函数重定向
c 复制代码
#include <stdio.h>
int fputc(int ch, FILE *f)
{
    //向调试串口发送1字节数据
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
    return ch;
}

方式二:取消半主机模式

  • 半主机模式是嵌入式开发中一种特殊的调试机制,允许运行在目标设备上的代码使用主机(通常是开发计算机)的资源进行输入/输出操作。具体来说半主机模式通过以下方式工作:
    • 嵌入式代码执行特定的指令序列(通常是断点指令或软中断)
    • 调试器捕获这些指令并解释为服务请求
    • 主机提供请求的服务(如文件I/O、控制台输出等)
    • 结果通过调试接口返回给目标设备
c 复制代码
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
// ARM Compiler 6 (MDK V6)
// 禁用半主机模式
__asm(".global __use_no_semihosting\n");
//标准库需要的支持函数
struct FILE
{
    int handle;
};
FILE __stdout;
void _ttywrch(int ch)
{
    ch = ch;
}
#else
// ARM Compiler 5 (MDK V5)
// 禁用半主机模式
#pragma import(__use_no_semihosting)
struct __FILE {
    int handle; // 占位符,无实际用途(可简化)
};
FILE __stdout, __stdin; // 标准输入/输出流
#endif
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
    x = x;
}
// 重定向 fputc 函数
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);
    return ch;
}
相关推荐
’长谷深风‘11 小时前
51单片机入门(4温度采集:DS18B20)
单片机·嵌入式硬件·51单片机·ds18b20·温度采集
Hello World . .11 小时前
51单片机——DS18B20 温度传感器
单片机·嵌入式硬件·51单片机
yugi98783812 小时前
51单片机控制8×8点阵显示汉字(上下左右滚动)
单片机·嵌入式硬件·51单片机
LCG元15 小时前
STM32项目开发:基于CAN总线的多节点通信与数据采集系统
stm32·单片机·嵌入式硬件
12.=0.16 小时前
【stm32_2.1】【快速入门】自举模式、Flash闪存、LED点灯——对二极管PN结解析
stm32·单片机·嵌入式硬件
辰哥单片机设计16 小时前
STM32智能风扇(机智云)
stm32·单片机·嵌入式硬件
【 STM32开发 】16 小时前
【STM32 + CubeMX】低功耗 -- SLEEP 睡眠模式
stm32·单片机·低功耗·sleep·睡眠模式
芯芯点灯17 小时前
LIS2DW12驱动,功耗,数据可视化
驱动开发·单片机
Nice__J17 小时前
Mcu架构以及原理——2.Cortex-M流水线与指令集
单片机·嵌入式硬件·架构