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;
}
相关推荐
女神下凡15 小时前
芯参谋(38):NAND_MCP_电路设计指南
arm开发·单片机·嵌入式硬件·设计规范
嵌入式学习菌16 小时前
FreeRTOS 中断管理实战:BASEPRI 寄存器实验
单片机·嵌入式硬件
HRTOS17 小时前
HRTOS:一个名字背后的目标——不断逼近硬实时
经验分享·单片机·系统架构·51单片机
UrSpecial19 小时前
GPIO 是什么?
单片机·嵌入式硬件
修船大队长21 小时前
配置接受报文每个报文对应一个mailbox配置流程记录
网络·单片机·mcu
搁浅小泽1 天前
二极管选型技术规范
单片机·嵌入式硬件·汽车
搁浅小泽1 天前
电感选型技术规范
单片机·嵌入式硬件·汽车
..Dauntless..1 天前
【stm32】串口——在MCU内部的工作过程
stm32·单片机·嵌入式硬件
lzqrzpt1 天前
临沂LED驱动电源工程选型标准与工艺对比解析
python·单片机·嵌入式硬件·物联网
小黄蚁1 天前
使用LVGL模拟示波器创建正弦函数波形
单片机·学习