STM32F4 UART基础(HAL库)

2023-05-16

文章目录

  • 概述
  • `UART`初始化
    • `UART`参数初始化
      • `UART`句柄
      • `UART`初始化结构体
      • `UART`参数初始化函数
    • `UART`时钟初始化
    • `UART_GPIO`初始化
    • `UART`中断配置
    • `Msp`初始化函数
  • `UART`无中断收发
    • `UART`发送数据
      • `UART`发送数据`API`
      • `UART`无中断发送示例
    • `UART`接收数据
      • `UART`接收数据`API`
      • `UART`无中断接收数据示例
  • `UART`中断收发
    • `UART`发送中断
      • `UART`发送中断使能
      • `UART`发送完成中断回调
      • `UART`发送中断示例
      • 注意:
    • `UART`接收中断
      • `UART`接收中断使能
      • `UART`接收完成中断回调
      • `UART`接收中断示例
      • 注意:

概述

 本篇将以STM32F407VET6芯片的USART1为例,总结STM32CubeIDE平台关于UART通信的**主动收发(无中断收发)被动收发(中断收发)**流程。应当注意,对于USART的常规应用,应当使用HAL库中的UART API.

UART初始化

UART的完整初始化流程为:

1.UART参数初始化
    (1).UART句柄配置
    (2).UART初始化结构体配置
    (3).UART使能
2.UART时钟初始化(置于UART_Msp初始化函数)
3.UART_GPIO初始化(置于UART_Msp初始化函数)
    (1).GPIO时钟初始化
    (2).GPIO参数初始化
4.UART中断配置(置于UART_Msp初始化函数)
    (1).NVIC总中断优先级配置
    (2).NVIC使能总中断
    (3).UART开启分中断(发送中断/接收中断)

UART参数初始化

UART句柄

UART句柄是UART初始化和具体操作中最重要的参数,应当声明为工程级别的全局变量。HAL库中采用 发送缓冲区接收缓冲区 一次发送/接受 一个或多个字节 的方式提高数据吞吐效率。

typedef struct __UART_HandleTypeDef {
    
    /* UART实例,取值有 USART1,USART2,USART3,UART4,UART5... */
    USART_TypeDef *Instance;
    
    /* UART初始化结构体 */
    UART_InitTypeDef Init;
    
    /* UART 本次 发送缓冲区指针 */
    uint8_t *pTxBuffPtr;
    
    /* UART 本次 发送缓冲区字节数 */
    uint16_t TxXferSize;
    
    /* UART 本次 已发送字节数,用于查询发送进度 */
    __IO uint16_t TxXferCount;
    
    /* UART 本次 接收缓冲区指针 */
    uint8_t *pRxBuffPtr;
    
    /* UART 本次 接收缓冲区字节数 */
    uint16_t RxXferSize;
    
    /* UART 本次 已接收字节数,用于查询接收进度 */
    __IO uint16_t RxXferCount;
    
    /* DMA发送缓冲区指针 */
    DMA_HandleTypeDef *hdmatx;
    
    /* DMA接收缓冲区指针 */
    DMA_HandleTypeDef *hdmarx;
    
    /* UART同步锁状态,取值有 HAL_UNLOCKED / HAL_LOCKED */
    HAL_LockTypeDef Lock;
    
    /* UART发送状态 */
    __IO HAL_UART_StateTypeDef gState;
    /* UART接收状态 */
    __IO HAL_UART_StateTypeDef RxState;
    /* UART错误码 */
    __IO uint32_t ErrorCode;

} UART_HandleTypeDef;

UART初始化结构体

typedef struct {
    
    /* 波特率 */
    uint32_t BaudRate;
    
    /* 帧字长,一般取 UART_WORDLENGTH_8B */
    uint32_t WordLength;
    
    /* 停止位,一般取 UART_STOPBITS_1 */
    uint32_t StopBits;
    
    /* 奇偶校验位,一般取 UART_PARITY_NONE */
    uint32_t Parity;
    
    /* UART收发模式,取值有
       UART_MODE_RX - 发送模式
       UART_MODE_TX - 接收模式
       UART_MODE_TX_RX - 发送_接收全双工模式 */
    uint32_t Mode;
    
    /* 硬件流控制,一般取 UART_HWCONTROL_NONE */
    uint32_t HwFlowCtl;
    
    /* 过采样倍率,一般取 UART_OVERSAMPLING_16 */
    uint32_t OverSampling;
} UART_InitTypeDef;

UART参数初始化函数

/* UART参数初始化 
   参数:huart - UART句柄指针 
   返回:
   HAL_ERROR - huart = NULL 时,将返回 HAL_ERROR 
   HAL_OK - UART初始化成功 */
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);

UART参数初始化实例:

void MX_USART1_UART_Init(void) {
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    // 使用 UART API 而不是 USART API
    if (HAL_UART_Init(&huart1) != HAL_OK) {
        Error_Handler();
    }
}

UART时钟初始化

/* UART时钟使能应置于 Msp初始化函数 中 */

/* 宏函数,USART时钟使能 */
__HAL_RCC_USART1_CLK_ENABLE();
/* 宏函数,USART时钟失能 */
__HAL_RCC_USART1_CLK_DISABLE();

/* 宏函数,UART时钟使能 */
__HAL_RCC_UART4_CLK_ENABLE();
/* 宏函数,UART时钟失能 */
__HAL_RCC_UART4_CLK_DISABLE();

UART_GPIO初始化

/* UART_GPIO初始化应当置于 Msp初始化函数 中 */

GPIO_InitTypeDef GPIO_InitStruct = {0};

/* GPIO时钟初始化 */
__HAL_RCC_GPIOA_CLK_ENABLE();

GPIO_InitStruct.Pin = USART1_TX_Pin|USART1_RX_Pin;
/* 复用推挽输出模式 */
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
/* 上拉电阻 */
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
/* 复用映射 */
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

UART中断配置

/* UART中断配置应置于 Msp初始化函数 中 */

/* UART总中断优先级配置 */
HAL_NVIC_SetPriority(USART1_IRQn,0,0);

/* UART总中断使能 */
HAL_NVIC_EnableIRQ(USART1_IRQn);

Msp初始化函数

UART参数初始化函数HAL_UART_Init()中调用了Msp初始化函数实现用户自定义初始化配置。UART的时钟使能、GPIO初始化、中断配置 都应当在Msp初始化函数中实现。

/* 使用 UART API 而并非 USART API */
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) {
    
    // 时钟使能
    // GPIO初始化
    // 中断配置
    
}

UART无中断收发

UART发送数据

UART发送数据API

/* UART无中断发送数据
   参数:
   huart - UART句柄指针
   pData - UART本次发送缓冲区指针 
   Size - UART本次发送缓冲区字节数 
   Timeout - UART发送超时时限 
   
   返回:
   HAL_OK - UART成功发送指定字节数(Size)
   HAL_ERROR - pData = NULL 或 Size = 0 将返回 HAL_ERROR 
   HAL_TIMEOUT - UART发送超时 
   HAL_BUSY - UART发送繁忙 */
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, 
                                    uint8_t *pData, 
                                    uint16_t Size, 
                                    uint32_t Timeout);

UART无中断发送示例

uint8_t *TxBufferPtr = (uint8_t*)"Successful!\n\r";
#ifndef TIMEOUT
#define TIMEOUT 1000
#endif
while(HAL_UART_Transmit(&huart1,TxBufferPtr,13,TIMEOUT) != HAL_OK);

UART接收数据

UART接收数据API

/* UART无中断接收数据
   参数:
   huart - UART句柄指针
   pData - UART本次接收缓冲区指针 
   Size - UART本次接收缓冲区字节数 
   Timeout - UART接收超时时限 
   
   返回:
   HAL_OK - UART成功接收指定字节数(Size)
   HAL_ERROR - pData = NULL 或 Size = 0 将返回 HAL_ERROR 
   HAL_TIMEOUT - UART接收超时 
   HAL_BUSY - UART接收繁忙 */
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, 
                                    uint8_t *pData, 
                                    uint16_t Size, 
                                    uint32_t Timeout);

UART无中断接收数据示例

uint8_t RxBufferPtr[10] = {0};
#ifndef TIMEOUT
#define TIMEOUT 1000
#endif
/* 接收完成指定字节数之前,main()将一直阻塞 */
while(HAL_UART_Receive(&huart1,RxBufferPtr,10,TIMEOUT) != HAL_OK);
// 接收回显
while(HAL_UART_Transmit(&huart1,RxBufferPtr,10,TIMEOUT) != HAL_OK);

UART中断收发

HAL库中将UART中断深度封装,仅提供中断回调函数进行用户中断处理逻辑的实现。中断回调函数均有弱定义(__weak)声明,用户可在任意源文件(.c)中重新强定义(无__weak声明)中断回调函数实现自定义中断处理逻辑。
UART中断回调流程:

1.中断发生
2.进入中断服务函数 UARTx_IRQHandler()
3.中断服务函数调用 通用入口函数 HAL_UART_IRQHandler(),
  通用入口函数中进行中断源的判断、中断标志的清除等操作
4.通用入口函数依据事件判断调用 中断回调函数 HAL_UART_XxxCallback()    

UART发送中断

UART发送中断使能

/* 使能发送中断并配置本次发送中断缓冲区 
   参数:
   huart - UART句柄指针
   pData - UART本次发送缓冲区指针 
   Size - UART本次发送缓冲区字节数 
   
   返回:
   HAL_OK - 配置成功且UART发送中断准备就绪
   HAL_ERROR - pData = NULL 或 Size = 0 将返回 HAL_ERROR
   HAL_BUSY - UART发送中断未准备就绪 */
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart,
                                       uint8_t *pData,
                                       uint16_t Size);

UART发送完成中断回调

/* UART成功发送指定字节数(Size)将执行此中断回调 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    // 用户中断处理逻辑
}

UART发送中断示例

uint8_t *TxBufferPtr = (uint8_t*)"Successful!\n\r";
int main(void) {
    /*****省略代码*****/
    while(HAL_UART_Transmit_IT(&huart1,TxBufferPtr,13) != HAL_OK);
    /*****省略代码*****/
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    if(huart->Instance == USART1) {
        // 发送完成之后打开LED
        LED_ON();
    } 
}

注意:

UART发送中断回调的机制是:每发送一个字节之后均会进入中断服务函数,通过UART句柄中的TxXferCount判断UART发送数据的进度,如果发送达到指定字节数(Size),则调用HAL_UART_TxCpltCallback().

HAL_UART_Transmit_IT()只能开启1次发送中断,调用发送中断回调函数之后便 失能 发送中断。在合适的时机再次调用HAL_UART_Transmit_IT()可以再次开启发送中断。

HAL_UART_Transmit_IT()不可在UARTMsp初始化函数中调用。Msp初始化函数并非在UART参数初始化函数HAL_UART_Init()的末尾调用,在Msp初始化函数调用之后还会进行UART状态的初始化操作。如果在Msp初始化函数中调用HAL_UART_Transmit_IT()将导致错误判断UART发送状态,HAL_UART_Transmit_IT()将错误返回HAL_BUSY.
 正确的做法是:在UART参数初始化函数HAL_UART_Init()调用后调用HAL_UART_Transmit_IT().

UART接收中断

UART接收中断使能

/* 使能接收中断并配置本次接收中断缓冲区 
   参数:
   huart - UART句柄指针
   pData - UART本次接收缓冲区指针 
   Size - UART本次接收缓冲区字节数 
   
   返回:
   HAL_OK - 配置成功且UART接收中断准备就绪
   HAL_ERROR - pData = NULL 或 Size = 0 将返回 HAL_ERROR
   HAL_BUSY - UART接收中断未准备就绪 */
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
                                       uint8_t *pData,
                                       uint16_t Size);

UART接收完成中断回调

/* UART成功接收指定字节数(Size)将执行此中断回调 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    // 用户中断处理逻辑
}

UART接收中断示例

uint8_t RxBufferPtr[10] = {0};
int main(void) {
    /*****省略代码*****/
    while(HAL_UART_Receive_IT(&huart1,RxBufferPtr,10) != HAL_OK);
    /*****省略代码*****/
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if(huart->Instance == USART1) {
        #ifndef TIMEOUT
        #define TIMEOUT 1000
        #endif
        // 接收回显
        while(HAL_UART_Transmit(&huart1,RxBufferPtr,10,TIMEOUT) != HAL_OK);
        // 换行
        while(HAL_UART_Transmit(&huart1,(uint8_t*)"\r\n",2,TIMEOUT) != HAL_OK);
        // 使能中断
        while(HAL_UART_Receive_IT(&huart1,RxBufferPtr,10) != HAL_OK);
    } 
}

注意:

UART接收中断回调的机制是:每接收一个字节之后均会进入中断服务函数,通过UART句柄中的RxXferCount判断UART接收数据的进度,如果接收达到指定字节数(Size),则调用HAL_UART_RxCpltCallback().

HAL_UART_Receive_IT()只能开启1次接收中断,调用接收中断回调函数之后便 失能 接收中断。在合适的时机再次调用HAL_UART_Receive_IT()可以再次开启接收中断。

HAL_UART_Receive_IT()不可在UARTMsp初始化函数中调用。Msp初始化函数并非在UART参数初始化函数HAL_UART_Init()的末尾调用,在Msp初始化函数调用之后还会进行UART状态的初始化操作。如果在Msp初始化函数中调用HAL_UART_Receive_IT()将导致错误判断UART接收状态,HAL_UART_Receive_IT()将错误返回HAL_BUSY.
 正确的做法是:在UART参数初始化函数HAL_UART_Init()调用后调用HAL_UART_Receive_IT().

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32F4 UART基础(HAL库) 的相关文章

  • UART(通用异步收发传输器)

    1 UART其在数据发送时将并行数据转换成串行数据来传输 xff0c 在数据接收时将接收到的 串行数据转换成并行数据 是异步串行通信的总称 2 而 RS232 RS449 RS423 RS422 和 RS485 等是对应各种异步串行通信口的
  • UART串口通信协议概述

    1 UART协议介绍 UART是一种通用串行数据总线 xff0c 用于异步通信 UART能实现双向通信 xff0c 在嵌入式设计中 xff0c 常用于主机与辅助设备通信 UART包括RS232 RS449 RS423等接口标准规范和总线标准
  • 4.RTT-UART-中断接收及轮询发送

    本期博客开始分享RTT的UART xff0c 利用战舰V3的uart2来输入输出一些字符串 UART xff08 Universal Asynchronous Receiver Transmitter xff09 通用异步收发传输器 xff
  • 心跳跟随的心形灯(STM32(HAL)+WS2812+MAX30102)

    文章目录 前言 介绍 系统框架 原项目地址 本项目开发开源地址 硬件PCB 软件功能 详细内容 硬件外壳制作 WS2812级联及控制 MAX30102血氧传感器 0 96OLED FreeRTOS 效果视频 总结 前言 在好几年前 我好像就
  • stm32f407zgt6的pdr_on引脚怎么接

    原文链接 https www amobbs com thread 5495105 1 1 html dsign c6460fe9 407的100脚封装没有这个PDR ON 就是VSS 在引脚分布图中为pdr on 但实际量pdr on对VS
  • mega328p-ADC,PWM,UART驱动

    ADC驱动 函 数 名 Ai Init 函数功能 Ai端口初始化 输入参数 void 输出参数 void 返 回 值 void 参考文档 void 创 件 人 程强刚 创建日期 2016 02 09 修改历史 void Ai Init vo
  • ESP32-C3入门教程 基础篇(三、UART模块 — 与Enocean无线模块串口通信)

    测试第三课 ESP32 C3的串口通信测试 老样子 使用Enocean无线模块和ESP32 C3进行串口通信 目录 前言 1 UART示例测试 1 1 UART 基础测试 1 2 与Enocean无线模块串口通信测试 2 ESP32 C3
  • 使用HAL库开发STM32:UART基础使用

    文章目录 目的 基础说明与初始化 基础说明 初始化 数据接收和发送 轮询方式 中断方式 DMA方式 其它说明 总结 目的 UART 异步串口 是单片机非常常用的一个功能 一般用作设备或模块间通讯的一种方式 通常所说的232或是485通讯从写
  • 使用HAL库开发STM32:GPIO口基础使用与外部中断

    文章目录 目的 GPIO口基础使用 基础说明 初始化设置 输出与控制 读取端口值 GPIO口与外部中断 总结 目的 对于MCU来说GPIO口的使用是最基础的内容 仅使用GPIO口和延时等 就可以完成很多功能了 GPIO口基础使用 基础说明
  • STM32 HAL库更改中断向量表的偏移地址

    以STM32F767为例 打开system stm32f7xx c文件 定位VECT TAB OFFSET 更改此宏定义的值 即可更改偏移量
  • CUBEMX+HAL库实现STM32串口(不定长度)收发

    CUBEMX HAL库实现STM32串口接收 不定长度 并发送 首先新建一个CUBEMX工程 选择你自己开发板的芯片型号 设置时钟和串口 设置时钟为72MHZ 设置串口中断 点击小齿轮生成KEIL5的工程 设置工程名称及存放位置 点击Ope
  • IOError:[Errno 2]没有这样的文件或目录(当它确实存在时)Python [重复]

    这个问题在这里已经有答案了 我正在通过 python 中的 uart 传输文件文件夹 下面您可以看到简单的功能 但有一个问题 因为我收到如标题所示的错误 IOError Errno 2 No such file or directory 1
  • C、硬件抽象层中“extern”类型的变量

    我正在研究硬件抽象层 该 HAL 的目的是在 Linux 驱动程序和 MCU 驱动程序之间轻松切换 我正在研究SPI接口 下面是 打开 SPI接口的HAL函数的签名 哈尔 spi h spi handle t spi open spi po
  • 启用 DMA 的 UART Tx 模式

    我已经为 UART 在传输模式下编写了一个简单的设备驱动程序 并启用了 DMA 和中断 我使用的硬件是 omap 4460 pandaboard 其中加载了 Linux 3 4 下面我分享一下相关部分的代码 在开放阶段 dma map io
  • 英特尔伽利略裸机 UART

    我想编写一些 hello world 程序裸机申请于英特尔伽利略木板 当然 使用 UEFI 打印文本 到 UART 1 效果很好 但我想 手动 访问 UART 而不需要 UEFI 的任何帮助 在 QEMU 中我的代码运行良好 h file
  • 通过 USB 模拟 UART

    有谁知道是否可以通过 USB 模拟 UART 简单串行发送和接收 这将如何实现 我在 Microchip 网站上找到了这个链接 但不是很容易找到 http www microchip com forums m522571 print asp
  • 跨线程操作无效:从创建它的线程以外的线程访问控制“textBox1”[重复]

    这个问题在这里已经有答案了 我想使用 UART 将温度值从微控制器发送到 C 接口并显示温度Label Content 这是我的微控制器代码 while 1 key scan get value of temp if Usart Data
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 使用 /dev/tty* 进行 9 位 uart 仿真

    我有一个不常见的协议 它需要 9600 波特率 9 位和 1 个停止位 我找不到任何可以实现此发送 接收的驱动程序 我可以寄东西到 dev tty 用于模拟这些查询 我应该发送什么 如何模拟 9600 波特率 您可以使用粘性奇偶校验 也称为
  • 如何检测来自 QNX 中 ncurses 的屏幕调整大小事件?

    我无法配置为接收有关使用 ncurses QNX Momentics 更改终端大小的事件 我使用Putyy作为终端 通过COM端口传输数据 我的问题是如何实现使用远程终端时接收屏幕变化事件 FILE fcons fopen dev ser1

随机推荐