ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

STM32 HAL库串口通信实战:从点灯到串口屏交互开发

STM32 HAL库串口通信实战:从点灯到串口屏交互开发 简介本资源是一套基于STM32G030C8T6与中显串口屏SDWn035T63T的嵌入式人机交互实战项目面向单片机初学者及HAL库进阶开发者解决串口屏通信、多传感器融合控制与LED动态调光等典型工程问题。压缩包共1048个文件涵盖567个C源码、243个头文件含硬件驱动与GUI逻辑、30余个编译中间文件.o/.d及26个图像资源.bmp/.img另有Keil工程配置.uvprojx/.ioc、固件镜像.bin/.hex和数学库支持文件.a/.lib整体大小26.85MB。已有1796人学习下载配套B站实操视频完整演示按键控制、呼吸灯、光敏调光、温光数据实时刷新等全部功能。读者可直接复现完整系统包含立创EDA设计的主控板与灯板原理图、DS18B20GY-30双传感器驱动、4路LED差异化控制策略及串口屏VGUS协议解析代码具备良好可扩展性与定制化基础。1. 项目概述从点灯到串口屏交互的跨越搞嵌入式开发的朋友对“点灯”这个操作肯定再熟悉不过了。它就像是程序员的“Hello World”是验证硬件、软件环境是否正常工作的第一步。但今天我们要聊的远不止是让一个LED闪烁那么简单。这个项目的核心是让STM32这颗“大脑”通过串口UART与一块“中显串口屏”进行对话并最终通过屏幕上的一个虚拟按钮来控制一个真实的LED灯。这看似简单的“点灯”背后实际上完成了一次从单片机到人机交互界面的完整通信链路搭建。为什么说这是一个有意义的跨越传统的点灯我们可能通过按键、定时器或者简单的串口命令来控制交互方式原始且信息有限。而引入串口屏后我们获得了一个图形化、可定制、信息丰富的交互前端。你可以设计漂亮的界面显示传感器数据设置复杂的参数并通过触摸屏进行控制。这对于智能家居控制面板、工业设备操作台、仪器仪表显示等场景来说是刚需。STM32 HAL库的引入则大大简化了我们对底层硬件的操作让我们能更专注于应用逻辑的开发而不是纠结于寄存器配置的细节。所以这个项目适合两类朋友一是已经熟悉STM32基本操作想进阶学习如何与外部智能模块通信的开发者二是正在寻找一种快速、低成本为嵌入式设备添加友好人机界面方案的工程师。通过这个项目你将掌握STM32 HAL库串口通信的核心配置、理解与串口屏的通信协议、并实现一个完整的“屏控硬件”的闭环。2. 核心思路与通信协议解析要实现STM32与串口屏的通信并控制LED我们需要先理清整个数据流的逻辑。这不是一个单向的“发指令-执行”过程而是一个包含触发、反馈的交互循环。2.1 系统工作流程拆解整个系统的运行可以分解为以下几个核心步骤初始化STM32上电后初始化系统时钟、GPIO用于控制LED、串口外设用于与屏幕通信。界面触发用户在串口屏上设计好的界面中点击一个“按钮”控件。指令下发串口屏检测到触摸事件后根据预先的设置通过串口TX线向STM32发送一条约定好的指令数据。指令接收与解析STM32的串口外设在中断或轮询模式下接收到这条指令并将其存入缓冲区。指令处理STM32的主程序解析缓冲区中的数据。例如判断指令是否是“开灯”命令如收到字节0x01或者“关灯”命令如收到字节0x00。执行控制根据解析结果STM32通过HAL库的GPIO写函数控制连接LED的引脚输出高电平点亮或低电平熄灭。状态反馈可选但推荐STM32在改变LED状态后可以通过串口再向屏幕发送一条状态更新指令让屏幕上的按钮图标或文字颜色随之改变例如灯亮时按钮显示为绿色灯灭时显示为灰色实现视觉反馈提升用户体验。这个流程的关键在于第3步和第5步通信协议。STM32和屏幕必须说同一种“语言”。2.2 串口屏通信协议浅析市面上主流的串口屏如大彩、迪文、淘晶驰等虽然各有自己的上位机配置软件和指令集但其底层通信本质都是基于串口的自定义协议。协议通常包含以下几个部分帧头用于标识一帧数据的开始常见的有0xAA、0x5A、0xA5等用于在数据流中进行帧同步。指令/地址码指明这条指令要做什么。比如0x01代表“写寄存器”0x03代表“读寄存器”。对于触摸事件屏幕通常会自动发送控件ID和事件类型。数据长度指示后面跟随的有效数据有多少个字节。数据域具体的控制参数或信息。例如要写入的寄存器地址、要显示的文本内容、或者是控件的状态值。校验和用于验证数据传输过程中是否出错常见的有和校验、异或校验、CRC校验等。接收方会重新计算校验和并与接收到的进行比对。对于本项目我们为了简化可以和屏幕约定一个极其简单的协议。例如我们在屏幕上做一个按钮设置其“按下发送数据”为0x01另一个按钮发送0x00。这样STM32只需要判断接收到的字节是0x01还是0x00即可。注意在实际复杂项目中必须严格按照屏幕厂商提供的协议手册来组包和解包数据。简单协议仅适用于学习和快速验证。2.3 为什么选择HAL库STM32的开发库主要有标准外设库Standard Peripheral Library和硬件抽象层库Hardware Abstraction Layer, HAL。HAL库是ST主推的新一代库优势明显跨系列兼容性HAL库的API在不同系列的STM32芯片上高度统一项目移植成本低。CubeMX集成通过STM32CubeMX图形化工具可以一键生成包含HAL库的初始化代码极大提升开发效率避免繁琐的底层配置。中间件支持HAL库是ST生态如FreeRTOS, USB, FATFS等中间件的基础。维护性ST持续维护和更新HAL库而标准库已停止更新。对于串口通信这种常用外设HAL库提供了HAL_UART_Transmit(),HAL_UART_Receive(),HAL_UART_Receive_IT()中断接收,HAL_UART_Receive_DMA()DMA接收等一系列函数封装完善使用起来比直接操作寄存器或标准库更直观、安全。3. 硬件连接与工程环境搭建在写代码之前正确的硬件连接和软件开发环境是成功的基石。3.1 硬件清单与接线你需要准备以下硬件STM32最小系统板如STM32F103C8T6即常见的“蓝色药丸”板。中显串口屏型号不限需支持UART通信如带TJC、DWIN、USART HMI等标识的屏幕。USB转TTL串口模块用于调试和可能给屏幕下载工程。LED灯和限流电阻通常开发板已自带用户LED如PC13。杜邦线若干。接线示意图关键部分串口屏的TX引脚 ---- STM32的串口RX引脚 (例如PA10, 如果使用USART1) 串口屏的RX引脚 ---- STM32的串口TX引脚 (例如PA9, 如果使用USART1) 串口屏的GND引脚 ---- STM32的GND引脚 串口屏的VCC引脚 ---- STM32的5V或3.3V引脚 (请严格参照屏幕规格书供电) STM32的LED控制引脚 (例如PC13) ---- LED阳极LED阴极接GND若使用板载LED则无需额外接线实操心得接线时务必先断电串口屏的供电电压一定要看清有的是5V有的是3.3V接错极易烧毁屏幕。TX/RX要交叉连接即屏的TX接MCU的RX。如果通信不正常首先用USB转TTL模块连接电脑用串口助手工具测试屏幕本身是否能正常发送数据这是最有效的排查方法。3.2 使用STM32CubeMX创建工程打开CubeMX选择MCU型号例如 STM32F103C8Tx。配置系统核心SYS在“SYS”选项卡中将“Debug”设置为“Serial Wire”如果要用ST-Link调试。配置时钟RCC在“RCC”选项卡中将高速外部时钟HSE选择为“Crystal/Ceramic Resonator”为系统提供准确时钟源。配置时钟树点击“Clock Configuration”标签通常对于F103可以直接输入72然后按回车软件会自动配置PLL将系统时钟HCLK设置为72MHz。这是F1系列的一个常见高性能配置。配置GPIO找到控制LED的引脚如PC13将其设置为“GPIO_Output”。模式为“Output Push Pull”上拉/下拉根据电路选择通常默认即可输出速度“Low”即可。配置串口以USART1为例在左侧引脚图中找到PA9和PA10将PA9设置为“USART1_TX”PA10设置为“USART1_RX”。在左侧“Connectivity”中找到USART1模式选择“Asynchronous”异步通信。配置参数波特率常用115200、字长8位、停止位1位、无奇偶校验、无硬件流控。这些参数必须与串口屏的设置完全一致。最关键的一步开启串口全局中断。在“NVIC Settings”选项卡中勾选“USART1 global interrupt”的使能复选框。这样我们才能使用中断方式接收数据不阻塞主程序。生成代码转到“Project Manager”选项卡设置项目名称、路径、IDE如MDK-ARM V5。在“Code Generator”中选择“Copy only necessary library files”以减小工程体积勾选“Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral”让代码更模块化。点击“GENERATE CODE”生成Keil工程。3.3 串口屏界面设计以简单按钮为例不同的串口屏使用不同的上位机软件如迪文的DGUS淘晶驰的USART HMI。但基本逻辑相通新建一个工程选择与你的屏幕型号匹配的分辨率。从控件工具箱中拖放一个“按钮”控件到画布上。双击按钮进入属性设置。你需要关注两个核心属性控件ID给这个按钮一个唯一的编号比如1。按下/弹起发送数据这是核心。设置当按钮被按下时通过串口发送什么数据。为了简单我们可以直接设置为“十六进制发送”数据为01 0A假设01是开灯指令0A是自定义的帧尾。或者更简单地只发送一个字节0x01。具体格式需参考屏幕的指令手册。同理再做一个“关灯”按钮设置发送数据为00 0A或0x00。设计完成后将工程编译并下载到串口屏中通常通过SD卡或USB口。4. 核心代码实现与解析打开CubeMX生成的Keil工程我们主要在main.c和stm32f1xx_it.c中断服务函数文件中添加业务逻辑。4.1 全局变量与宏定义在main.c的顶部用户代码区添加/* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart1; // CubeMX已声明 /* Private user code ---------------------------------------------------------*/ #define LED_PIN GPIO_PIN_13 #define LED_PORT GPIOC #define CMD_LED_ON 0x01 #define CMD_LED_OFF 0x00 uint8_t uart_rx_buffer[1]; // 用于中断接收的缓冲区 uint8_t received_cmd 0; // 存储接收到的命令这里我们定义了一个大小为1的接收缓冲区因为我们的简易协议每次只发送一个命令字节。received_cmd用于在主循环中判断执行什么操作。4.2 主函数初始化后开启串口接收中断在main()函数中系统初始化之后用户代码开始处/* USER CODE BEGIN 2 */和/* USER CODE END 2 */之间启动串口接收中断。/* USER CODE BEGIN 2 */ // 启动串口1以中断方式接收数据每次接收1个字节存入uart_rx_buffer if (HAL_UART_Receive_IT(huart1, uart_rx_buffer, 1) ! HAL_OK) { // 如果启动失败可以在这里处理错误比如让LED闪烁报警 Error_Handler(); } // 先关闭LED HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); // 假设LED是低电平点亮高电平熄灭 /* USER CODE END 2 */HAL_UART_Receive_IT函数会启动一次中断接收当收到1个字节后会触发串口接收完成中断执行回调函数然后需要再次调用此函数以准备接收下一个字节。4.3 编写串口接收完成回调函数HAL库采用回调机制。当串口接收完成一个字节或指定长度的数据后会自动调用HAL_UART_RxCpltCallback函数。我们需要重写这个函数。在main.c文件中/* USER CODE BEGIN 4 */和/* USER CODE END 4 */之间添加/* USER CODE BEGIN 4 */ /** * brief 串口接收完成中断回调函数 * param huart: 串口句柄 * retval None */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { // 判断是否是USART1触发的中断 if (huart-Instance USART1) { // 将接收到的字节赋值给命令变量 received_cmd uart_rx_buffer[0]; // 再次启动中断接收准备接收下一个字节循环 HAL_UART_Receive_IT(huart1, uart_rx_buffer, 1); } } /* USER CODE END 4 */这个函数是中断服务程序的一部分执行时间要尽可能短。我们只做最简单的数据搬运和重新使能接收中断的操作复杂的解析和处理放到主循环中。4.4 主循环中的命令解析与执行最后在main()函数的while (1)循环中我们不断检查received_cmd变量并执行相应的操作。/* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ // 解析并执行接收到的命令 switch(received_cmd) { case CMD_LED_ON: HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); // 点亮LED received_cmd 0; // 清除命令避免重复执行 // 可选发送状态反馈给屏幕 // uint8_t feedback[] {0xAA, 0x01, 0x01, 0xAC}; // 示例反馈帧 // HAL_UART_Transmit(huart1, feedback, sizeof(feedback), 100); break; case CMD_LED_OFF: HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); // 熄灭LED received_cmd 0; // 清除命令 // 可选发送状态反馈给屏幕 // uint8_t feedback[] {0xAA, 0x01, 0x00, 0xAB}; // HAL_UART_Transmit(huart1, feedback, sizeof(feedback), 100); break; default: // 接收到未知命令可以忽略或做错误处理 break; } // 这里可以添加其他任务如传感器读取等 HAL_Delay(10); // 短暂延时防止CPU占用率过高 } /* USER CODE END 3 */注意事项在主循环中处理命令而不是在中断回调函数中直接控制GPIO是一个好习惯。这符合“快进快出”的中断设计原则避免在中断服务程序中执行耗时操作影响系统对其他中断的响应。同时通过received_cmd这个“标志”进行通信也是裸机编程中常见的任务间通信方式。5. 调试技巧与常见问题排查即使代码和接线都看似正确第一次尝试也难免遇到问题。下面是一些实战中总结的排查思路。5.1 通信失败的“三板斧”排查法查硬件供电用万用表测量屏幕VCC引脚电压是否正确稳定。接线TX/RX是否交叉连接GND是否共地这是最常见的问题。引脚冲突检查STM32的串口引脚是否被其他功能如JTAG复用了。例如PA15、PB3、PB4默认是JTAG引脚如果要用作普通IO或串口需要在CubeMX的SYS里禁用JTAG选择SWD模式。查配置波特率STM32的串口波特率必须与屏幕设置的波特率精确一致。115200和9600差一点都会导致乱码。建议双方都设置为9600或115200这种常用值。数据格式数据位8位、停止位1位、校验位无必须完全匹配。中断优先级如果系统中有多个中断需合理配置NVIC优先级避免高优先级中断阻塞串口中断。查数据逻辑分析仪/示波器这是终极武器。直接抓取串口屏TX引脚发出的波形看其波特率、数据内容是否与预期一致。串口助手旁路测试将串口屏的TX线暂时接到USB转TTL模块上连接电脑用串口助手如XCOMSecureCRT接收数据。点击屏幕按钮看电脑是否能收到正确的指令数据。这能直接证明屏幕本身工作是否正常、指令设置是否正确。5.2 代码层面的常见坑点未重新使能中断接收在HAL_UART_RxCpltCallback回调函数中必须再次调用HAL_UART_Receive_IT否则串口只会接收一次数据。缓冲区溢出如果屏幕发送数据很快而主循环处理很慢可能导致uart_rx_buffer在被处理前就被新的数据覆盖。对于多字节协议需要使用环形缓冲区Ring Buffer来安全地存储数据。我们的单字节例子简单但扩展到复杂协议时必须考虑。HAL库延时问题避免在中断回调函数中使用HAL_Delay()这个函数依赖于系统滴答定时器SysTick在中断中使用可能导致系统卡死。变量共享冲突received_cmd在中断回调写和主循环读中被共同访问。虽然在这个简单例子中一个字节的读写是原子的不会出大问题。但在更复杂的系统中对于多字节变量或结构体需要考虑使用临界区保护或禁止中断来防止读写冲突。5.3 功能扩展与优化建议当基础功能实现后可以考虑以下优化让项目更健壮、更实用协议规范化实现一个完整的帧解析函数包含帧头判断、长度校验、和校验/CRC校验。这能极大提高通信的可靠性。超时与重发机制在发送指令给屏幕后启动一个定时器如果超时未收到应答则进行重发或错误处理。使用DMA接收对于数据量较大或频率较高的通信如实时刷新数据使用DMA代替中断接收可以大大减轻CPU负担。CubeMX可以方便地配置串口DMA。加入状态反馈如前所述在控制LED后主动发送其状态给屏幕更新界面显示实现真正的双向交互。整合简单调度器如果后续需要增加其他任务如读取传感器、扫描按键可以考虑引入一个像protothreads或简单的状态机让主循环结构更清晰。通过这个从“点灯”到“串口屏通信”的项目你不仅掌握了HAL库串口通信的基本操作更重要的是理解了嵌入式系统中“感知-决策-控制-反馈”的闭环思想。串口屏作为一个强大的交互终端其潜力远不止控制一个LED。你可以轻松地将其扩展为数据显示终端温湿度、电压电流、参数设置界面PID参数、阈值设置、甚至简单的游戏菜单。下次当你需要为你的STM32项目添加一个界面时不妨就从这块串口屏开始。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进