STM32 HAL UART 框架初体验

本文详细介绍了如何使用STM32CubeMX工具配置STM32L010K8的UART2接口,包括环境配置、参数设置及中断处理。通过HAL库简化硬件寄存器操作,提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

STM32开发平台,时至今日发展的已经相当成熟了,尤其对于外围硬件接口的抽象封装库,即HAL。好多基于STM32开发的工程师,习惯于直接操作外围接口相关的寄存器来完成所谓的驱动开发,其实,ST公司早就为大家准备好了对于这些外围接口的驱动框架,我们只需要直接拿来就可以使用。

可是以前,基于STM32平台开发时,存在一个问题就是,变换MCU型号时,需要在新老MCU之间移植驱动程序,移植过程中可能出现很多莫名其妙的问题,导致浪费了很多宝贵的开发时间,如何避免这种问题呢?其实,ST早就为大家考虑到了这一点,其开发了STM32CubeMX工具,基于该工具,我们可以轻松的完成各种外围接口的配置工作,而且最为神奇的就是,配置完成之后,该工具会自动生成工程代码,我们基于此,就可以直接进行开发了,免去了很多不必要的硬件寄存器配置工作。当然,对于特殊需求,我们还是需要去手动配置一些硬件寄存器,但是,这项工作大部分时间是不需要的。

既然,ST公司为我们提供了这么好用的工具,我们为什么不用起来呢?下面就基于UART的配置过程,来逐步的讲解一下,如何基于STM32CubeMX、Kiel和STM32 HAL来配置生成一个可用的开发环境。

开发步骤

配置环境

工欲善其事,必先利其器。首先第一步就是安装STM32CubeMX环境,关于STM32CubeMX环境的安装,网上有好多写的特别棒的文中,这里引用一篇
ybhuangfugui的博客,在此感谢ybhuangfugui的无私贡献。大家可以阅读该文章完成STM32CubeMX环境的安装。

在这里说一句,STM32CubeMX提供所有STM32家族的MCU芯片的初始配置抽象,并提供了HAL,封装、抽象了关于底层硬件的配置、使用过程,这是一把双刃剑,有利有弊:利是它增强了STM32不同MCU之间的兼容性,大大加快了初始开发进度,其提供的HAL为开发者提供了统一的开发接口,这样节省了宝贵开发时间。同时,基于其提供的配套的中间件(RTOS、TCP/IP、FS等),开发者可以快速的完成更高级需求的环境定制,这对于开发者来说是不小的福音;弊是,STM32 MCU毕竟是比较低级的硬件开发平台,其开发过程中涉及到大量的底层硬件操作,如果我们想彻底理解这些基础的硬件操作原理的话,可能还是需要从最为原始的硬件寄存器配置开始。

不过,个人感觉STM32CubeMX利大于弊,就像通用操作系统,其屏蔽了所有的硬件相关的操作,为开发者抽象出了进程、内存管理、文件系统、网络等等,易于开发、理解的开发接口,也是正是操作系统的逐步成熟,才最终促使了后来的计算机一次又一次的革命。我想,对于MCU来说,其过程是类似的。如今,已经进入了物联网时代,各种各样的的硬件开发平台层出不穷,各种层次的开发者都涌入到了这一开发领域。试想对于一个原来从事于Web开发的人员来说,其不可能从头去理解底层的硬件知识,其需要的就是一个快速、高效的配置工具,完成原始开发环境的搭建。这时,STM32CubeMX就可以提供很大的帮助。

相信,STM32CubeMX未来肯定会发展的更为智能,任何一个有志于基于该平台开发的开发者,都会被其强度的功能所折服的,零基础的开发人员也能够快速上手该平台。我想,这可能也是STM32CubeMX未来的目标吧。

最后说明一下,本文所使用的STM32CubeMX的版本是:5.5.0。温馨提示,不同版本的操作步骤也能不太一样,所以建议使用相同的版本进行配置。

开始配置

首先,我们需要确定我们所使用的STM32的MCU具体型号,然后,打开STM32CubeMX,创建一个新的工程。

我们选择第一个“ACCESSTO MCU SELECTOR”,开始创建一个工程。我们选择的MCU是STM32L010K8,安装如下图的步骤创建工程。

  1. 选择MCU型号
  2. 查看MCU型号信息
  3. 创建项目

然后,选择Project Manager项目,配置本项目的一些信息。

接下来,我们进行Pinout & Configuration配置,这里面会涉及到MCU提供的所有外围硬件的相关配置。本文主要关注的是UART的配置过程,STM32L010K8提供一个UART2和LPUART,我们选择的配置项为UART2。

UART2的基本配置步骤如下,

  1. 选择UART2配置项。

  2. 选择UART2的工作模式,这里选择的是Asynchronous。

  3. 配置UART2的参数,参数分为Basic Parameters、Advanced Paramters、Advanced Features几类。

    • 基本参数配置就是波特率、字长、校验方式、停止位;
    • 高级参数配置就是数据传输方向、采集相关的配置;
    • 高级特性配置:就是UART2提供的一些比较高级的功能,比如,自适应波特率、Overrun等。

我们选择UART2的中断方式处理数据的传输模式,所以,需要进一步配置NVIC。配置步骤如下:

  1. 点击System Core中的NVIC配置。
  2. 使能USART2中断,并配置中断抢占优先级为0。

还有就是需要确定UART2使用GPIO引脚,配置方式如下:

这里使用的是PA2和PA3。

最后,配置SysClock,我们最终选择的系统主时钟频率为16MHz。

完成上述配置之后,点击GENERATE CODE完成项目代码的生成。

HAL

项目代码生成之后,我们使用Kiel打开,如下图:

下面是main中的芯片初始化代码:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */
 
 

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

我们看到,STM32CubeMX自动生成了关于HAL、系统时钟、UART2的初始化代码。下面看一下UART2的初始化代码:

static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */
}

stm32l0xx_it.c中定义了UART2的中断处理函数,代码如下:

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

该中断处理函数用来处理所有与UART2相关的中断事件。那如何才能开启UART2的数据发送和接收呢?这就需要HAL中关于UART2数据发送接收的接口函数:

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

当我们需要已中断的方式接收数据时,就调用HAL_UART_Receive_IT函数,其中第一个参数是UART的描述符,pData保存数据的缓存区,Size是缓存区的大小。注意,调用完该接口之后,UART2开始已中断的方式接收数据,数据的大小为Size,当接收了Size个字节的数据之后,UART2就不会再接收数据。若想再次接收数据,需要再一次调用HAL_UART_Receive_IT函数。一个比较好的实现就是,在重新覆盖实现下面的函数,

`__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)`

该函数会在数据接收完之后被调用,然后我们在函数中,可以将数据拷贝走,然后再次调用HAL_UART_Receive_IT。

对于数据的发送,处理过程与接收类似,所不同的就是发送的接口函数为:HAL_UART_Transmit_IT,该发送完成之后的回调函数是:

__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)

好了,至此我们基本完成了基于STM32CubeMX的UART的配置过程,可以看到基于此种方式,我们基本上不会触碰到硬件寄存器的配置过程,所要做的就是基于HAL框架提供的接口完成APP的开发。这也许就是STM32CubeMX的魅力所在吧,简单,高效,可移植性强。
UART_TxCpltCallback(UART_HandleTypeDef *huart)

好了,至此我们基本完成了基于STM32CubeMX的UART的配置过程,可以看到基于此种方式,我们基本上不会触碰到硬件寄存器的配置过程,所要做的就是基于HAL框架提供的接口完成APP的开发。这也许就是STM32CubeMX的魅力所在吧,简单,高效,可移植性强。

### 使用 STM32 HAL 库通过 UART 进行程序烧录 为了实现通过 UARTSTM32 设备进行程序烧录,通常会涉及到使用串口调试工具以及特定的固件更新协议。下面详细介绍如何设置和操作。 #### 配置 CubeMX 和项目初始化 在开始之前,确保已经安装并配置好 STMCubeMX 工具来生成初始代码框架[^1]。利用该软件可以方便地设定系统时钟、启用必要的外设(如 USART),并且自动生成初始化代码片段。对于基于 HAL 的应用程序来说,这是非常重要的一步。 #### 设置 UART 接收模式 当准备进入编程模式时,设备应当处于监听状态等待来自 PC 或其他主机下发的新固件镜像。此时可以通过如下方式调整 UART 收发行为: - **移除原有中断处理逻辑**:如果先前存在用于常规通信的接收中断,则应将其删除以免干扰后续流程。 - **激活空闲线检测机制**:向 `main()` 函数中添加语句以允许 UART 模块识别到输入流结束信号——即所谓的“空闲”事件。此功能有助于界定每一段待写入闪存的数据包边界。 ```c __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); ``` - **启动 DMA 控制下的批量读取过程**:紧接着上面的操作之后立即调用 API 来触发直接存储器访问控制器执行连续抓取动作直至缓冲区满载为止。 ```c HAL_UART_Receive_DMA(&huart1, (uint8_t *)Uart1_RxBuff, UART_RX1_BUFFSIZE); ``` 上述措施共同作用使得目标板能够高效稳定地获取外部传来的二进制指令序列[^3]。 #### 实现固件升级算法 考虑到安全性与可靠性,在实际编写负责解析并加载新版本的应用层代码前还需考虑几个方面的问题: - 数据校验方法的选择; - 如何妥善保存临时文件而不破坏现有运行环境; - 完成刷机后重启装置使之生效的具体手段等。 这些细节取决于具体应用场景和个人偏好,不过一般推荐采用 CRC 循环冗余检验技术验证接收到的内容无误后再继续下一步骤;同时建议开辟独立分区专门用来暂存即将替换进去的新映像副本以防万一发生错误还能迅速回滚至旧版保持业务连续性。 最后值得注意的是整个过程中可能还需要额外配合一些辅助性的命令集比如进入引导装载程序(Bootloader)的方式等等,这部分依赖于所选用芯片型号及其配套资源文档中的说明指引来进行相应适配开发。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值