【STM32 + HAL + Cubemx】【TTL USART 串口三种模式控制LED亮灭】

发布时间:2026/7/28 10:17:01

【STM32 + HAL + Cubemx】【TTL USART 串口三种模式控制LED亮灭】 一、串口概述串口是STM常见的通信方式之一其是是用于异步串行通信的外设可实现设备间的数据传输如与传感器、上位机通信。在STM32中串口有很多种包括USB串口RJ-45串口TTL串口等我们今天学习的是比较常用的TTL串口而TTL串口有两种USART和UARTUSART 支持同步和异步模式UART 仅支持异步。他们均通过 TX发送和 RX接收引脚传输数据。串口通信需约定波特率、数据位、停止位和校验位等参数。关于串口的通信原理本文不作详细解释大家如有兴趣可以看这个视频【keysking的STM32教程】 第8集 STM32的串口通信_哔哩哔哩_bilibili。串口的常见用法有普通轮询模式、中断模式、DMA模式等能高效处理数据接下来将分别介绍这三种串口的用法。二、串口的普通轮询模式用法轮询按照字面意思就是“轮番询问”的意思即STM32不断“询问”串口是否空闲一旦空闲就执行发送或接收数据。我们就用串口的轮询模式实现向STM32发送数据来控制LED灯的亮灭。1.建立工程配置好STM32Cubemx标准工程的基本步骤见前面的文章然后在Connectivity一栏中找到USART1选其他串口也是可以的但是一定要注意要找STM32单片机和电脑连接的串口模式选择Asynchronous异步。在下面的设置栏中Baud Rate波特率保持默认115200 Bit/s即可。Word Length字长保持默认8Bits即可。Parity校验位保持默认“无”即可。Stop Bits停止位保持默认1位即可。综上所有设置保持默认以后遇到特殊需求再修改即可。为了点亮LED我们还需要按照之前文章提到的方法配置好对应的GPIO。给工程命名配置好项目地址后生成工程即可。2.代码编写实现发送打开生成的Keil工程在main.c中编写代码。发送串口数据的函数为HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);其中huart是UART句柄指向一个有效的UART_HandleTypeDef结构体实例pData指向要发送的数据的指针。Size表示要发送的数据长度。Timeout表示超时时间单位为毫秒。如果在该时间内未发送完所有数据函数就会返回错误。我们首先定义一个发送数据的数组类型为uint8_t。uint8_t datas[10] Hello!;然后调用串口发送函数huart1就是我们选用的串口句柄datas对应我们自定义的数据数组数据长度用sizeof函数即可等待时长可填HAL库的最大等待时间HAL_MAX_DELAY也可填100等具体的数值。HAL_UART_Transmit(huart1,datas,sizeof(datas),HAL_MAX_DELAY);运行代码连接好电脑和STM32的串口接口打开串口调试助手我这里用的是正点原子的串口调试助手大家也可以到网上搜索其他串口调试助手软件。需要将波特率数据长度停止位校验位调整为我们之前在Cubemx中的配置一样此时按下单片机的RESET键可以看到STM32不断向电脑发送我们设定的“hello!”字样。3.代码编写接收并控制LED接下来编写STM32接收电脑发送的数据并根据数据开关LED的代码。接收串口数据的函数为HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);其中的参数与之前发送函数类似。我们就用之前定义的datas数组作为接收数据的容器。HAL_UART_Receive(huart1,datas,sizeof(datas),HAL_MAX_DELAY);现在就可以实现向STM32发送数据控制LED亮灭了。我们可以规定当给STM32发送K时需要让其执行开灯这一指令当给STM32发送G时需要让其执行关灯这一指令。我们已经规定了接收数组为datas那么我们只需判断datas[0]是“K”还是“G”然后就可以按照不同情况来控制小灯的亮灭了。我们可以在while循环中写下以下功能代码HAL_UART_Receive(huart1,datas,sizeof(datas),HAL_MAX_DELAY); if(datas[0] K){ HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); } if(datas[0] G){ HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); } memset(datas,sizeof(datas),0); //清空避免干扰编译无问题后下载到单片机打开串口工具输入‘K’或‘G’就可以控制LED亮灭了。注由于这是轮询模式有时候会不灵可以多按几次发送就可以了三、串口的中断模式用法经过实践可以发现轮询模式总会有时候不那么“灵”,这时候就可以用中断模式让单片机从主程序中跳出到串口中断处理函数。1.建立工程中断模式和普通模式的区别是用到了专门的中断函数在配置Cubemx时打开相关功能即可。按照上图配置好后重新生成工程。2.代码编写中断收发中断发送函数为HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)。可以看到与普通模式相比中断接收函数少了等待时长这个参数这是因为中断模式下一旦接收完成就会触发接收完成回调函数不需要等待就少这个参数。中断接收函数为HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)。与发送函数类似少了等待时长这个参数。3.代码编写中断接收并控制LED类比上一章节用到的GPIO外部中断串口的中断模式也有相应的中断处理函数/** * brief Rx Transfer completed callbacks. * param huart Pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * retval None */ __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Prevent unused argument(s) compilation warning */ UNUSED(huart); /* NOTE: This function should not be modified, when the callback is needed, the HAL_UART_RxCpltCallback could be implemented in the user file */ }同样与GPIO的中断函数类似将此函数复制到main.c某处begin-end注释对中然后编写自己需要的函数。uint8_t datas[10] ; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(datas[0] K){ HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); } if(datas[0] G){ HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); } memset(datas,sizeof(datas),0); //清空避免干扰 HAL_UART_Receive_IT(huart1,datas,1); }可以看到整体代码与之前普通模式的代码类似最后一行之所以要再加一个接收函数是因为每次处理完当前串口数据后还要接收下次的数据所以还得再加一个。在主函数while循环前某处加上HAL_UART_Receive_IT(huart1,datas,1);开启串口接收中断就完整实现功能了。编译、下载验证功能可以发现与普通模式相比中断模式可以很快响应并处理我们发送的串口数据。但是有一个问题当串口数据发送过于频繁时主函数频频被中断函数打断一方面浪费CPU资源另一方面这种模式接收数据速度不够快这就可以用到DMA模式了。四、串口的DMA模式用法1.DMA配置在配置Cubemx时先取消掉之前的中断配置然后按照以下配置添加DMA按照上图分别添加USART_RX和USART_TX可以看到下方对DMA的配置界面功能已标在途中在当前应用场景保持默认即可。2.DMA模式收发函数DMA接收函数HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)DMA发送函数HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)比较方便的是DMA模式处理数据的回调函数与中断模式使用的是一样的因此只需要在Cubemx更改完配置后将原来的HAL_UART_Receive_IT(huart1,datas,1);改为HAL_UART_Receive_DMA(huart1,datas,1);即可。编译下载验证代码发现功能与中断模式实现的功能一样当然DMA的妙处在需要高速传数据时才能体现本例程这两种模式的区别并不明显。【拓展】如果想要实现接收不定长的数据可以用HAL_UARTEx_ReceiveToIdle_DMA(huart1,re,sizeof(re));这个函数要注意的是为了保证不会触发接收过半中断可以用HAL_DMA_DISABLE_IT(hdma_usart1_rx,DMA_IT_HT);把这个中断关掉。另外还要加一个extern DMA_HandleTypeDef hdma_usart1_rx;

相关新闻