1. 项目概述与硬件选型智能家居设备正逐渐走进我们的生活而蓝牙控制是最常见的无线控制方式之一。这次我们要用STM32F103C8T6最小系统板和JDY-23蓝牙模块打造一个可以通过手机APP控制的智能灯系统。这个项目非常适合嵌入式开发初学者不仅能学习到硬件连接、串口通信等基础知识还能掌握实际项目开发的全流程。STM32F103C8T6是一款性价比极高的ARM Cortex-M3内核微控制器72MHz主频、64KB Flash、20KB RAM完全能满足我们的需求。我实测过这款芯片的性能运行简单的控制程序绰绰有余。JDY-23蓝牙模块则是基于蓝牙5.0的透传模块最大传输距离60米支持AT指令配置使用起来非常方便。这两个硬件搭配起来既经济实惠又功能强大。除了主控和蓝牙模块我们还需要准备以下元件LED灯建议使用高亮LED效果更明显220Ω限流电阻OLED显示屏用于显示状态信息杜邦线若干USB转TTL模块用于调试2. 硬件连接详解硬件连接是整个项目的基础正确的接线能避免很多后续问题。我刚开始做这个项目时就因为接线问题折腾了好久后来总结出了一些经验。首先来看STM32与JDY-23的连接蓝牙模块的VCC接3.3V注意不要接5V可能会损坏模块GND接GNDTXD接STM32的PA10USART1_RXRXD接STM32的PA9USART1_TX这里有个小技巧蓝牙模块的TX要接MCU的RXRX接MCU的TX这个交叉连接新手很容易搞错。我第一次接线时就弄反了导致数据无法传输排查了半天才发现问题。LED的连接相对简单LED正极通过220Ω电阻接PA1LED负极接GNDOLED显示屏的连接SCL接PB8SDA接PB9VCC接3.3VGND接GND实际接线时建议先用万用表测试线路是否导通。我就遇到过杜邦线内部断线的情况表面看起来接好了实际信号根本过不去。3. 蓝牙模块配置与测试JDY-23蓝牙模块出厂时已经配置好了基本参数但我们最好还是了解下AT指令的使用方法方便后续调试。要进入AT模式需要满足两个条件模块未连接任何设备发送AT指令时要带换行符在串口助手中勾选发送新行常用的AT指令包括ATNAME查看/设置设备名称ATBAUD查看/设置波特率ATVERSION查看固件版本测试时可以先用USB转TTL模块连接电脑通过串口助手发送指令。这里有个坑要注意有些串口助手默认不发送换行符导致AT指令无效。我推荐使用XCOM或者SSCOM这类功能完善的串口工具。蓝牙模块与手机连接也很简单手机打开蓝牙设置搜索名为JDY-23的设备默认名称点击连接无需配对密码连接成功后模块上的指示灯会从快闪变为慢闪。如果遇到连接问题可以尝试重启模块或者检查天线是否完好。4. 通信协议设计为了让手机APP和STM32能够正确通信我们需要设计一个简单的协议格式。经过多次测试我采用了指令*#的格式这种设计有以下优点起始符和结束符#可以明确标识一帧数据的开始和结束中间的*作为指令和参数的分隔符格式简单容易解析具体指令定义如下LED_ON*#开灯指令LED_OFF*#关灯指令STATUS?#查询状态指令在STM32端我们需要编写串口中断服务程序来解析这个协议。核心思路是使用状态机初始状态等待字符收到后进入指令接收状态遇到*进入参数接收状态收到#表示一帧接收完成这种设计可以有效避免数据错位和粘包问题。我在实际项目中测试过即使在有干扰的环境下也能稳定工作。5. STM32程序设计STM32的程序开发我们使用Keil MDK环境代码主要分为以下几个部分首先是串口初始化配置USART1工作在9600波特率void Serial_Init(void) { // 启用USART1和GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置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); // 配置RX(PA10)为上拉输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; GPIO_Init(GPIOA, GPIO_InitStructure); // USART参数配置 USART_InitStructure.USART_BaudRate 9600; 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_Tx | USART_Mode_Rx; USART_Init(USART1, USART_InitStructure); // 使能USART和接收中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE); // 配置NVIC NVIC_InitStructure.NVIC_IRQChannel USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); }接下来是核心的中断服务程序负责协议解析void USART1_IRQHandler(void) { static uint8_t state 0; static uint8_t index 0; if(USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { uint8_t data USART_ReceiveData(USART1); switch(state) { case 0: // 等待起始符 if(data !rxFlag) { state 1; index 0; } break; case 1: // 接收指令 if(data *) { state 2; } else { rxBuffer[index] data; } break; case 2: // 等待结束符 if(data #) { rxBuffer[index] \0; rxFlag 1; state 0; } break; } USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }主程序逻辑负责处理解析完成的指令while(1) { if(Serial_RxFlag) { OLED_ClearLine(2); OLED_ShowString(2, 1, Serial_RxPacket); if(strcmp(Serial_RxPacket, LED_ON) 0) { LED_ON(); Serial_SendString(LED_ON_OK\r\n); OLED_ShowString(4, 1, Light ON); } else if(strcmp(Serial_RxPacket, LED_OFF) 0) { LED_OFF(); Serial_SendString(LED_OFF_OK\r\n); OLED_ShowString(4, 1, Light OFF); } else { Serial_SendString(ERROR_CMD\r\n); OLED_ShowString(4, 1, Error CMD); } Serial_RxFlag 0; } }6. 手机APP使用与调试手机端我们可以使用现成的蓝牙调试APP比如蓝牙串口助手或者Serial Bluetooth Terminal。这些APP在应用商店都能免费下载。使用步骤打开APP搜索蓝牙设备选择JDY-23进行连接连接成功后在发送框输入指令观察STM32的响应和LED状态调试过程中常见的问题指令发送后无响应检查蓝牙连接状态确认指令格式正确包括和#用逻辑分析仪抓取串口信号LED状态与指令不符检查LED接线是否正确测量PA1引脚电平变化查看OLED显示的命令内容通信不稳定检查电源是否稳定尝试降低波特率缩短通信距离我在调试时遇到过最棘手的问题是蓝牙模块偶尔会死机后来发现是电源质量问题换了个质量好的LDO稳压器就解决了。这也提醒我们硬件设计时电源部分千万不能将就。7. 功能扩展与优化基础功能实现后我们可以考虑做一些扩展让项目更加实用增加PWM调光功能修改指令格式为LED_PWM*50#50表示亮度百分比STM32端使用定时器输出PWM波需要修改LED驱动电路增加MOS管添加多设备控制为每个LED分配独立ID指令格式变为DEV1_LED_ON*#STM32维护设备状态表实现场景模式预设几种灯光场景通过单一指令切换可以结合光敏电阻实现自动调节增加状态反馈STM32定时上报设备状态手机APP显示实时状态异常情况主动报警OTA升级功能通过蓝牙传输固件STM32实现bootloader安全校验升级包这些扩展功能可以根据实际需求选择性实现。我在自己的项目中实现了PWM调光和场景模式效果很不错。特别是PWM调光能让LED实现柔和的明暗变化比简单的开关高级多了。8. 常见问题解决方案在实际开发中我遇到过不少问题这里总结几个典型的蓝牙模块无法连接检查模块供电是否正常3.3V确认天线完好无损尝试恢复出厂设置ATRESTORE串口通信乱码确认双方波特率一致检查时钟配置是否正确测量晶振是否起振程序跑飞或死机检查堆栈大小是否足够添加看门狗定时器关键操作加入异常处理OLED显示异常确认I2C地址正确检查上拉电阻降低I2C时钟频率功耗过高不使用的外设及时关闭合理使用低功耗模式优化程序运行流程遇到问题时建议按照以下步骤排查确认最小系统正常工作跑个LED闪烁测试分模块测试单独测试蓝牙、单独测试OLED使用逻辑分析仪抓取信号简化程序逐步添加功能我刚开始做蓝牙项目时最常犯的错误就是急于实现全部功能结果出了问题无从下手。后来学会了模块化开发和测试效率提高了很多。