前言本文记录下笔者学习STM32CubeMX时的流程方便以后回忆同时也适合刚接触该软件的初学者。本章记录串口通信希望能对大家有帮助。文章只针对对应的具体功能讲述诸如创建项目时通常配置DEBUG项为Serial Wire而不是默认的No Debug避免第二次烧录程序时无法使用调试器进行等基础问题串口通信中的传输模式可分为阻塞模式与非阻塞模式后者的典型实现为中断模式和DMA模式阻塞模式下如HAL_UART_Transmit等传输函数会一直等待操作完成或超时退出期间占用CPU而非阻塞模式下包括中断和DMA方式执行函数立即返回数据在后台完成传输无超时等待阻塞模式在STM32CubeMX的串口配置按照下图配置串口为异步模式并且使能中断以及检查串口波特率等参数是否符合在 Keil5 中打开生成的工程文件编写发送函数并进行测试。其中huart1这个参数名称来源于串口初始化函数中定义的句柄结构体也就是配置好的。STM32CubeMX会生成配置好的串口句柄// 定义测试文本 uint8_t send_str1[] hello world\r\n; // 阻塞模式: 通过串口1发送指定长度的文本超时时间为1000ms HAL_UART_Transmit(huart1, send_str1, sizeof(send_str1), 1000);在stm32f1xx_hal_uart.h文件中串口操作相关函数声明在725行位置处。阻塞模式传输函数将会阻塞一直等待缓冲区可用时再传输数据如果超过了超时时间缓冲区在一定时间内无法发送数据时传输函数将会超时退出。非阻塞模式则与上述相反没有超时时间的概念有数据就收发不存在数据传输等待。// 阻塞模式发送 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); // 阻塞模式接收 HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); // 非阻塞模式发送 HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); // 非阻塞模式接收 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);接收回环测试将接收到的数据通过串口原样发回给调试助手阻塞模式通常用于定长数据接收在获取不到设定的长度时会一直阻塞程序// 判断是否是空闲中断if(__HAL_UART_GET_FLAG(huart1,UART_FLAG_IDLE)SET){HAL_UART_Receive(huart1,rece_str1,1,2000);HAL_UART_Transmit(huart1,rece_str1,1,2000);HAL_UART_Transmit(huart1,\r\n,2,2000);// 清空缓冲区memset(rece_str1,0,16);// 清除空闲中断标志否则会一直不断进入中断__HAL_UART_CLEAR_IDLEFLAG(huart1);}中断模式中断模式调用HAL_UART_Receive_IT(huart1, RxBuffer, 1)后每收到1字节便会触发回调函数。因此需要在初始化时调用一次启动接收并在回调中再次调用HAL_UART_Receive_IT以持续接收数据// 创建接收缓冲区uint8_tRxBuffer[3];// 重写中断接收回调voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart){if(huart-InstanceUSART1){SerialPort_RingQueue_PutChar(SerialPort1,RxBuffer[0]);// 如果希望继续接收数据可以再次调用HAL_UART_Receive_IT()HAL_UART_Receive_IT(huart1,RxBuffer,1);}}// 先在主函数中调用一次接收HAL_UART_Receive_IT(huart1,RxBuffer,1);DMA串口空闲中断模式STM32CubeMX配置串口全局中断开启DMA循环模式开启STM32CubeMX只能开启总的中断开关空闲中断要代码手动开启main.h#defineRX_BUFFER_SIZE128externuint8_trx_buffer[];externuint8_trx_data[];externuint16_trx_len;voidUART1_DMA_Processing(uint8_t*data,uint16_tlen);main.cuint8_trx_buffer[RX_BUFFER_SIZE];// DMA循环接收缓冲区uint8_trx_data[RX_BUFFER_SIZE];// 二次缓存用于处理数据避免DMA覆盖uint16_trx_len0;// 接收到的数据长度// 使能空闲中断 (IDLE Interrupt)__HAL_UART_ENABLE_IT(huart1,UART_IT_IDLE);// 启动DMA循环接收让DMA在后台持续运行HAL_UART_Receive_DMA(huart1,rx_buffer,RX_BUFFER_SIZE);stm32xx_it.c芯片下对应的中断文件// 只有在STM32CubeMX勾选了对应的全局中断才会生成该函数voidUSART1_IRQHandler(void){// 判断是否为空闲中断if(__HAL_UART_GET_FLAG(huart1,UART_FLAG_IDLE)){// 必须先清除标志位__HAL_UART_CLEAR_IDLEFLAG(huart1);// 计算接收数据长度HAL_UART_DMAStop(huart1);rx_lenRX_BUFFER_SIZE-__HAL_DMA_GET_COUNTER(hdma_usart1_rx);// 数据处理memcpy(rx_data,rx_buffer,rx_len);// 重启DMA接收HAL_UART_Receive_DMA(huart1,rx_buffer,RX_BUFFER_SIZE);// 调用数据处理函数DMA_Processing(rx_data,rx_len);}HAL_UART_IRQHandler(huart1);}扩展在发送数据前通常可以使用格式化函数将各种数据转换为字符形式后再发送。在C语言中可以使用sprintf函数实现例如sprintf(数组,Data1:%d\r\n,整型数据);