发布时间:2026/7/15 20:32:40
STM32F103通过USART串口指令实现多LED状态控制 1. 项目背景与硬件准备最近在做一个智能家居控制项目需要STM32通过串口接收指令控制多个LED灯的状态。手头正好有块正点原子的精英版STM32F103ZET6开发板板载4个LED和CH340G串口芯片特别适合做这个实验。先说说硬件连接开发板USART1的PA9(TX)和PA10(RX)已通过CH340G与电脑连接LED1~LED4分别连接在PB5、PB0、PB1、PC13引脚使用USB转串口模块时记得把开发板的BOOT0跳线帽接到1下载模式实测中发现个坑如果直接用杜邦线连接USB转TTL模块必须共地GND接GND否则会出现乱码。有次调试两小时才发现是地线没接气得我差点把开发板扔出窗外。2. USART串口初始化配置先上干货初始化代码要配置三个部分// 1. GPIO初始化 void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 开启GPIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE); // 配置USART1的TX(PA9)为复用推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // 配置USART1的RX(PA10)为浮空输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); // 配置LED引脚(PB5,PB0,PB1,PC13)为推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_5 | GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_Init(GPIOB, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_13; GPIO_Init(GPIOC, GPIO_InitStructure); } // 2. USART初始化 void USART1_Config(void) { USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); USART_InitStructure.USART_BaudRate 115200; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_Init(USART1, USART_InitStructure); USART_Cmd(USART1, ENABLE); }波特率计算有个小技巧当系统时钟72MHz时115200波特率对应的USARTDIV39.0625。配置时直接填整数部分39小数部分0.0625×161所以BRR寄存器应设置为0x271。3. 指令集设计与状态控制3.1 指令格式定义为了控制多个LED我设计了这样的指令格式单灯控制LEDx_ON / LEDx_OFF x1~4群组控制ALL_ON / ALL_OFF特殊效果ALL_BLINK闪烁3次查询状态STATUS?例如发送LED1_ON点亮PB5的LED发送ALL_BLINK让所有LED闪烁发送STATUS?返回当前LED状态3.2 状态机实现用状态机处理指令更可靠下面是核心逻辑typedef enum { CMD_LED1_ON, CMD_LED1_OFF, CMD_LED2_ON, // ...其他指令枚举 CMD_UNKNOWN } CommandType; CommandType parse_command(char* cmd) { if(strstr(cmd, LED1_ON)) return CMD_LED1_ON; if(strstr(cmd, LED1_OFF)) return CMD_LED1_OFF; // ...其他条件判断 return CMD_UNKNOWN; } void execute_command(CommandType cmd) { switch(cmd) { case CMD_LED1_ON: GPIO_ResetBits(GPIOB, GPIO_Pin_5); USART_SendString(USART1, LED1 is ON\r\n); break; case CMD_LED1_OFF: GPIO_SetBits(GPIOB, GPIO_Pin_5); USART_SendString(USART1, LED1 is OFF\r\n); break; // ...其他case } }4. 字符串解析与中断处理4.1 接收缓冲区管理#define MAX_CMD_LEN 32 char rx_buffer[MAX_CMD_LEN]; uint8_t rx_index 0; void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { char ch USART_ReceiveData(USART1); if(ch \n || rx_index MAX_CMD_LEN-1) { rx_buffer[rx_index] \0; process_command(rx_buffer); rx_index 0; } else { rx_buffer[rx_index] ch; } } }4.2 实用字符串处理技巧在嵌入式环境处理字符串要特别注意效率我总结了几个技巧用strncmp代替strstr做前缀匹配更高效环形缓冲区比线性缓冲区更适合高频数据使用查表法解析指令比if-else更快const CmdEntry cmd_table[] { {LED1_ON, CMD_LED1_ON}, {LED1_OFF, CMD_LED1_OFF}, // ...其他指令 }; CommandType fast_parse(char* cmd) { for(int i0; isizeof(cmd_table)/sizeof(CmdEntry); i) { if(strncmp(cmd, cmd_table[i].name, strlen(cmd_table[i].name)) 0) return cmd_table[i].cmd; } return CMD_UNKNOWN; }5. 系统整合与调试5.1 主程序逻辑int main(void) { SystemInit(); GPIO_Config(); USART1_Config(); // 使能接收中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART1_IRQn); // 发送欢迎信息 USART_SendString(USART1, LED Control System Ready\r\n); while(1) { // 主循环可以添加其他任务 __WFI(); // 进入低功耗模式 } }5.2 调试经验分享调试时踩过几个坑波特率不匹配电脑端和STM32的波特率必须完全一致中断优先级如果系统有其他中断要合理设置USART中断优先级缓冲区溢出一定要做长度检查我有次就因为没检查导致系统崩溃电气干扰长距离传输时建议加120Ω终端电阻推荐使用SecureCRT或Putty作为串口调试工具比普通的串口助手更稳定。调试时可以添加这样的调试信息#define DEBUG(fmt, ...) \ do { \ char dbg_buf[64]; \ sprintf(dbg_buf, [DEBUG] fmt \r\n, ##__VA_ARGS__); \ USART_SendString(USART1, dbg_buf); \ } while(0)6. 功能扩展与优化6.1 增加指令校验为防止误操作可以增加简单的校验机制指令格式#CMD?问号是校验和校验和计算所有字符异或bool verify_command(char* cmd) { if(cmd[0] ! # || strlen(cmd) 3) return false; char checksum 0; for(int i1; istrlen(cmd)-1; i) { checksum ^ cmd[i]; } return (checksum cmd[strlen(cmd)-1]); }6.2 使用DMA提高效率当需要控制大量LED或高频通信时可以用DMAvoid DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel4); DMA_InitStructure.DMA_PeripheralBaseAddr (uint32_t)USART1-DR; DMA_InitStructure.DMA_MemoryBaseAddr (uint32_t)tx_buffer; DMA_InitStructure.DMA_DIR DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize 0; DMA_InitStructure.DMA_PeripheralInc DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode DMA_Mode_Normal; DMA_InitStructure.DMA_Priority DMA_Priority_High; DMA_InitStructure.DMA_M2M DMA_M2M_Disable; DMA_Init(DMA1_Channel4, DMA_InitStructure); USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); }7. 最终效果演示烧录程序后打开串口助手测试发送LED1_ON→ PB5 LED点亮发送ALL_BLINK→ 所有LED闪烁三次发送STATUS?→ 返回LED1:ON,LED2:OFF,...为了更直观可以用Python写个测试脚本import serial import time ser serial.Serial(COM3, 115200, timeout1) def send_cmd(cmd): ser.write((cmd \n).encode()) print(ser.readline().decode().strip()) send_cmd(LED1_ON) time.sleep(1) send_cmd(ALL_BLINK) time.sleep(2) send_cmd(STATUS?)这个项目最让我自豪的是指令系统的可扩展性——新增LED或功能只需修改指令表和状态机核心逻辑不用动。后来客户要求增加PWM调光功能我只用了半小时就实现了。

相关新闻

2026/7/15 20:32:39

08-LCD1602驱动实战:从时序解析到自定义字符显示

1. LCD1602基础认知与硬件解析第一次接触LCD1602时,我盯着这个巴掌大的屏幕想了半天——这玩意儿怎么就能显示两行字符呢?后来拆开看才发现,它内部藏着个精密的点阵世界。LCD1602本质上是个16列2行的字符型液晶显示器,每个字符位置…

2026/7/15 20:32:39

从赛题到实战:剖析三端口DC-DC变换器的双模式能量管理策略

1. 三端口DC-DC变换器的设计挑战与工程价值在新能源和智能硬件快速发展的今天,高效能量管理成为技术突破的关键。2021年全国大学生电子设计竞赛的C题——三端口DC-DC变换器,正是对这一技术痛点的精准捕捉。这个看似专业的赛题,实际上解决的是…

2026/7/15 20:32:39

QQ截图独立版:5个隐藏功能让你的Windows截图效率提升300%

QQ截图独立版:5个隐藏功能让你的Windows截图效率提升300% 【免费下载链接】QQScreenShot 电脑QQ截图工具提取版,支持文字提取、图片识别、截长图、qq录屏。默认截图文件名为ScreenShot日期 项目地址: https://gitcode.com/gh_mirrors/qq/QQScreenShot 还在为…

2026/7/15 21:27:45

参赛实测|以企业项目落地为例!聊聊AI赋能Java开发的真实体验

做技术博主、深耕后端开发这么多年,我一直有个很直观的感受:企业级Java项目开发,难的从来不是写代码,而是整体架构规范、业务闭环落地、工程标准化。很多新手甚至初级工程师,能写CRUD,但很难独立搭建一套合…

2026/7/15 21:27:45

MFC框架下SIP语音通话客户端开发:从PJSIP集成到音频处理实战

1. 项目概述:在MFC框架下构建一个SIP语音通话客户端 如果你是一个长期在Windows桌面端摸爬滚打的C开发者,尤其是对MFC(Microsoft Foundation Classes)又爱又恨的那批人,那么“在MFC里搞一个SIP客户端实现语音通话”这个…

2026/7/15 21:27:45

HFSS实战指南:基于参数化方程构建Vivaldi天线渐变槽线

1. Vivaldi天线与HFSS建模基础Vivaldi天线作为一种超宽带天线,因其优异的阻抗匹配特性和方向性,在雷达、通信系统中广泛应用。它的核心结构是那个像喇叭一样逐渐张开的槽线——我们称之为指数渐变槽线。这个渐变曲线的形状直接决定了天线的性能表现。我第…

2026/7/15 21:27:45

深入解析TDA2P-ABZ时钟系统:从DPLL原理到硬件设计实战

1. 时钟系统整体设计与思路拆解时钟系统之于一颗复杂的SoC,就如同心脏和神经系统之于人体。它不仅仅是提供“滴答”声的节拍器,更是协调内部数以亿计晶体管协同工作的指挥家。在TDA2P-ABZ这类面向高级驾驶辅助系统(ADAS)、车载信息…

2026/7/15 21:27:45

C++高并发编程:线程安全、竞态条件与同步原语实战解析

1. 项目概述:为什么线程安全是C高并发编程的命门?如果你写过C多线程程序,大概率遇到过那种“幽灵”般的Bug:程序运行十次,有八次结果正确,剩下两次莫名其妙地崩溃或者数据错乱。你反复检查逻辑,…

2026/7/15 17:04:06

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾在网易云音乐下载了心爱的歌曲&#…

2026/7/14 19:23:19

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境随着新能源汽车行业的快速发展,充电通信协议的标准化和测试验证变得尤为重要。GB/T 27930-2023作为中国智能充电协议的最新版本,对充电机与电动汽车之间的通信提出了更严格…

2026/7/14 18:30:06

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡 【免费下载链接】rtl8852be Realtek Linux WLAN Driver for RTL8852BE 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8852be 还在为Linux系统无法识别RTL8852BE Wi-Fi 6网卡而烦恼吗?&#x1f…

2026/7/15 0:08:29

【LINUX】驱动

【LINUX驱动】【字符设备】【中断】【Platform】【网课 设备树】【GPIO】【PINCTRL】【INPUT】【IIC】【SPI】【网络驱动】【屏幕驱动】【一 设备树】【二 内核模块编译】【三 基本驱动框架】【四 Platform总线设备驱动框架】【五 驱动子系统】【六 综合】

2026/7/15 0:08:29

【1982-2026】全国高精度建筑轮廓|村级精度|SHP矢量

🔍 数据简介 本次分享1982-2026年全国村级精度建筑轮廓矢量数据,覆盖全国各省市区县,到村级别精细,为2026年最新实时采集成果,非网传仅60/77个城市的老旧数据。 数据含带高度/不带高度双版本,单体建筑边界精…

2026/7/15 0:08:29

【1975-2026】全国水系水路数据|河流/水库/运河|SHP矢量

🔍 数据简介 本次分享1975-2026年全国高精度水系水路矢量数据,覆盖全国全域,包含河流、水系、水库、运河、湿地、冰川、沟渠等全类别水文要素。 数据集包含双层矢量图层,字段分类清晰、要素齐全,支持2013-2026逐年完整…

2026/7/15 13:36:32

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…