STM32利用HAL库中断方式进行串口通信

✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进

❤欢迎关注我的知乎:对error视而不见

代码获取、问题探讨及文章转载可私信。

☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。

🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇

点击领取更多详细资料

一、引言

在嵌入式系统开发中,串口通信是一种常见且重要的通信方式,它可以实现微控制器与外部设备(如计算机、传感器等)之间的数据传输。STM32系列微控制器以其高性能、低功耗等特点被广泛应用,而HAL(Hardware Abstraction Layer)库则为开发者提供了一种简单、高效的方式来操作STM32的硬件资源。本文将详细介绍如何使用STM32的HAL库以中断方式实现串口通信。

二、串口通信原理

串口通信是一种按位顺序传输数据的通信方式,分为同步和异步两种类型。在异步串口通信中,数据的发送和接收双方不需要使用共同的时钟信号,而是通过起始位、数据位、校验位和停止位来实现数据的同步。

2.1 数据帧格式

  • 起始位:标志着一帧数据的开始,通常为低电平。
  • 数据位:要传输的数据,常见的有 5、6、7、8 位。
  • 校验位:用于检测数据传输过程中是否发生错误,有奇校验、偶校验和无校验等方式。
  • 停止位:标志着一帧数据的结束,通常为高电平,有 1 位、1.5 位或 2 位。

2.2 通信速率

串口通信的速率用波特率来表示,即每秒传输的比特数。常见的波特率有 9600、115200 等。

三、硬件连接

以 STM32F103C8T6 为例,使用 USART1 进行串口通信。硬件连接如下:

  • TX(发送端):连接到外部设备的 RX(接收端)。
  • RX(接收端):连接到外部设备的 TX(发送端)。
  • GND(接地):与外部设备的 GND 相连,确保共地。

四、HAL 库配置

4.1 时钟配置

首先,需要配置系统时钟和串口时钟。在 CubeMX 中,选择合适的外部晶振,配置系统时钟为 72MHz,并使能 USART1 的时钟。

4.2 串口配置

在 CubeMX 的“Pinout & Configuration”选项卡中,选择 USART1,将其模式设置为“Asynchronous”(异步模式),并配置波特率、数据位、校验位和停止位等参数。例如,波特率设置为 115200,数据位为 8 位,无校验位,停止位为 1 位。

4.3 中断配置

在 CubeMX 中,使能 USART1 的接收中断。在“NVIC Settings”选项卡中,勾选“USART1 global interrupt”,并设置中断优先级。

五、代码实现

5.1 生成代码

完成 CubeMX 的配置后,生成代码并导入到 Keil 或其他开发环境中。

5.2 主函数代码

#include "main.h"
#include "usart.h"
#include "gpio.h"

#define BUFFER_SIZE 256
uint8_t rx_buffer[BUFFER_SIZE];
uint8_t rx_index = 0;

void SystemClock_Config(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  // 开启串口接收中断
  HAL_UART_Receive_IT(&huart1, &rx_buffer[rx_index], 1);

  while (1)
  {
    // 主循环可以处理其他任务
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

5.3 中断处理函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART1)
  {
    // 处理接收到的数据
    if (rx_index < BUFFER_SIZE - 1)
    {
      rx_index++;
      // 继续开启下一次接收中断
      HAL_UART_Receive_IT(&huart1, &rx_buffer[rx_index], 1);
    }
    else
    {
      // 缓冲区已满,可进行相应处理
      rx_index = 0;
      HAL_UART_Receive_IT(&huart1, &rx_buffer[rx_index], 1);
    }
  }
}

5.4 发送数据函数

void send_data(const char *data)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)data, strlen(data), HAL_MAX_DELAY);
}

六、代码解释

6.1 主函数

在主函数中,首先进行系统初始化,包括 HAL 库初始化、系统时钟配置、GPIO 初始化和串口初始化。然后调用 HAL_UART_Receive_IT 函数开启串口接收中断,使能串口接收一个字节的数据,并在接收到数据后触发中断。

6.2 中断处理函数

HAL_UART_RxCpltCallback 是 HAL 库提供的串口接收完成回调函数。当接收到一个字节的数据后,会自动调用该函数。在函数中,首先判断是否是 USART1 产生的中断,然后将接收到的数据存储到缓冲区中,并更新缓冲区索引。如果缓冲区未满,则继续开启下一次接收中断;如果缓冲区已满,则清空缓冲区并重新开始接收。

6.3 发送数据函数

send_data 函数用于向串口发送数据。通过调用 HAL_UART_Transmit 函数,将指定的数据发送出去。

七、注意事项

  • 缓冲区溢出:在使用中断方式接收数据时,要注意缓冲区的大小,避免缓冲区溢出。可以根据实际需求调整缓冲区的大小。
  • 中断优先级:合理设置中断优先级,避免高优先级中断长时间占用 CPU,导致低优先级中断无法及时处理。
  • 数据处理:在中断处理函数中,尽量避免进行复杂的操作,以免影响中断响应时间。可以将数据处理任务放到主循环中进行。

八、总结

通过使用 STM32 的 HAL 库以中断方式实现串口通信,可以提高系统的实时性和效率。在实际应用中,可以根据需求扩展功能,如添加数据解析、错误处理等。同时,要注意代码的优化和调试,确保系统的稳定性和可靠性。

<think>嗯,用户想要找关于STM32 HAL实现串口中断的示例代码和教程。我需要先回顾一下自己掌握的知识,然后结合提供的引用内容来组织回答。 首先,用户提到的三个引用中,引用[1]和[2]都提到了HAL中断方式串口通信,特别是空闲中断和DMA的应用。引用[3]则有一段时钟配置的代码,可能涉及到初始化设置。我需要确保回答中包含具体的步骤和代码示例,同时引用相关的内容。 接下来,我应该分步骤来讲解如何配置串口中断。通常,使用HAL的步骤包括初始化串口、配置中断、编写中断回调函数,以及启用中断。需要提到CubeMX的配置,因为这是HAL常用的配置工具。然后给出代码示例,比如初始化函数、中断处理函数,以及回调函数的实现。 用户可能需要知道如何启用接收中断,可能涉及HAL_UART_Receive_IT函数,以及如何处理接收完成的中断,比如使用HAL_UART_RxCpltCallback。此外,引用[1]提到的空闲中断和DMA结合使用,可能也是用户感兴趣的部分,特别是处理不定长数据。这部分可以作为优化或进阶内容提及,并引用相关链接。 需要注意代码的正确性,比如检查HAL函数的使用是否正确,例如在HAL_UART_MspInit中启用中断和配置NVIC。还要提醒用户不要忘记启动中断,并处理错误情况,比如Error_Handler。 然后,生成相关问题的时候,应该围绕用户可能进一步想知道的内容,比如如何结合DMA,如何实现不定长接收,以及常见的错误处理。这些问题需要基于引用内容,比如引用[1]中的空闲中断和DMA,引用[2]中的HAL优势,以及引用[3]中的时钟配置可能引发的问题。 最后,确保回答结构清晰,分步骤说明,代码用正确的格式,并正确添加引用标识。同时,检查是否有遗漏的部分,比如CubeMX配置的截图可能需要用户自行查看教程,但在这里用文字描述关键步骤即可。</think>### STM32 HAL实现串口中断的步骤与示例 #### 1. 环境配置(CubeMX) 在STM32CubeMX中完成以下配置: - **串口模式选择**:异步模式(Asynchronous)或中断模式(Interrupt)。 - **时钟配置**:确保系统时钟和串口外设时钟正确分配。例如,引用[3]中提到的时钟初始化代码需匹配实际硬件: ```c if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } ``` - **NVIC配置**:使能串口全局中断(USARTx_IRQn),并设置优先级。 #### 2. 关键代码实现 在生成的工程中,添加以下代码: ```c // 串口初始化函数(CubeMX自动生成) 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; HAL_UART_Init(&huart1); } // 中断服务函数(HAL自动调用) void USART1_IRQHandler(void) { HAL_UART_IRQHandler(&huart1); } // 接收完成回调函数(用户自定义) void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { // 处理接收到的数据(示例:回传数据) HAL_UART_Transmit_IT(&huart1, &rx_data, 1); // 重新启动接收中断 HAL_UART_Receive_IT(&huart1, &rx_data, 1); } } ``` #### 3. 启动接收中断 在`main()`函数中初始化后启动中断接收: ```c uint8_t rx_data; HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 启动单字节接收中断 ``` #### 4. 进阶优化(DMA+空闲中断) 若需实现不定长数据接收,可结合**DMA传输**和**空闲中断**(IDLE Interrupt),如引用[1]所述: ```c // 启用空闲中断 __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // 在空闲中断回调中处理数据 void HAL_UART_IdleCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { // 计算接收数据长度并处理 uint16_t len = huart1.RxXferSize - __HAL_DMA_GET_COUNTER(huart1.hdmarx); process_data(rx_buffer, len); // 重新启动DMA接收 HAL_UART_Receive_DMA(&huart1, rx_buffer, BUFFER_SIZE); } } ``` ### 注意事项 - **中断优先级**:避免与其他高优先级中断冲突。 - **错误处理**:添加`HAL_UART_ErrorCallback`处理通信错误。 - **内存管理**:DMA模式下需确保缓冲区大小足够。 ### 引用资料 - 串口DMA+空闲中断实现方法详见[^1]。 - HAL中断机制与开发流程可参考[^2]。 - 时钟配置对串口波特率的影响见[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值