从零构建:基于JDY-18蓝牙与STM32的智能灯光APP控制系统
1. 项目背景与硬件准备
智能家居正在改变我们的生活方式,而灯光控制是最基础也最实用的应用场景之一。最近我在工作室搭建了一个基于JDY-18蓝牙模块和STM32的智能灯光控制系统,整个过程从硬件连接到APP开发都亲自动手实现。这个方案特别适合刚接触嵌入式开发的朋友,因为用到的都是性价比极高的常见硬件:一块STM32F103C8T6最小系统板(十几块钱就能买到)、JDY-18蓝牙模块(比HC-05更便宜)、几个LED灯珠,再加上手机就能玩转智能照明。
先说说为什么选择JDY-18蓝牙模块。相比常见的HC-05,它有几个明显优势:首先是价格便宜近一半;其次功耗更低,待机电流只有8μA;最重要的是支持蓝牙4.2标准,传输距离最远可达30米。我在实测中发现,隔着两堵墙都能稳定控制灯光,这对于家庭使用完全足够了。硬件清单具体需要准备:
- STM32F103C8T6最小系统板(蓝色小板)
- JDY-18蓝牙模块(注意要买带底板的版本)
- LED灯珠(建议RGB三色各一个)
- 杜邦线若干
- USB转TTL模块(用于初始配置)
- 安卓手机(用于安装控制APP)
2. JDY-18蓝牙模块配置
拿到蓝牙模块后第一步是进行基础配置。这里有个小坑要注意:新买的JDY-18默认波特率是115200,但为了兼容性建议改为9600。我用的是PL2303 USB转TTL模块,连接时特别注意TX-RX要交叉连接,即模块的TX接JDY-18的RX,模块的RX接JDY-18的TX,GND和VCC直接相连。
打开串口调试工具(推荐使用XCOM V2.2),发送AT指令时要记得勾选"发送新行"。基础配置只需要三条指令:
AT+BAUD4(设置波特率为9600)AT+NAMEJDY-LIGHT(设置设备名称)AT+ROLE0(设置为从机模式)
配置完成后记得断电重启模块。这时候用手机蓝牙搜索,应该能看到名为"JDY-LIGHT"的设备。我刚开始调试时遇到模块无响应的情况,后来发现是USB转TTL模块供电不足,换成外部5V供电就正常了。建议大家在调试时先用外部电源给蓝牙模块供电,避免这类问题。
3. STM32硬件连接与开发环境搭建
硬件连接其实非常简单,核心就是串口通信和PWM输出。具体接线如下:
- JDY-18的TX接STM32的PB11(USART3_RX)
- JDY-18的RX接STM32的PB10(USART3_TX)
- LED正极通过220Ω电阻接PA6(TIM3_CH1 PWM输出)
- 共地连接必不可少
开发环境我推荐使用Keil MDK,社区版就够用。新建工程时要注意:
- 选择正确的芯片型号STM32F103C8
- 添加标准外设库(StdPeriph_Lib)
- 在Options for Target中勾选"Use MicroLIB"(否则printf无法使用)
有个实用技巧:在工程里添加串口重定向代码,这样就能用printf调试了。具体是在usart.c中添加如下代码:
#include <stdio.h> int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); return ch; }4. STM32程序设计详解
整个程序可以分为三个关键部分:串口通信、PWM输出和主控制逻辑。先来看串口初始化,这是蓝牙通信的基础。在usart3.c中,我们需要配置USART3为异步模式,波特率9600,启用接收中断:
void usart3_init(u32 bound) { // 时钟使能省略... GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // PB10复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; // PB11浮空输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStructure); USART_InitStruct.USART_BaudRate = bound; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART3, &USART_InitStruct); USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); USART_Cmd(USART3, ENABLE); }PWM输出部分使用TIM3的通道1,关键是要正确设置自动重装载值(ARR)和预分频值(PSC)。我设置的PWM频率为1kHz,适合大多数LED调光应用:
void TIM3_PWM_Init(u16 arr, u16 psc) { TIM_TimeBaseStructure.TIM_Period = arr; // 自动重装载值 TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_Cmd(TIM3, ENABLE); }主程序中通过解析蓝牙指令来控制灯光。我设计了一个简单的协议:字符'0'关灯,'1'-'3'设置不同亮度,'4'-'6'控制RGB三色LED:
while(1) { if(USART3_RX_STA & 0x8000) { // 收到完整数据 switch(USART3_RX_BUF[0]) { case '0': TIM_SetCompare1(TIM3, 0); break; // 关闭PWM case '1': TIM_SetCompare1(TIM3, 50); break; // 20%亮度 case '2': TIM_SetCompare1(TIM3, 150); break; // 60%亮度 case '3': TIM_SetCompare1(TIM3, 350); break; // 100%亮度 // RGB控制省略... } USART3_RX_STA = 0; // 清除接收标志 } }5. 手机APP开发实战
考虑到大多数开发者没有安卓开发经验,我选择了App Inventor2这个图形化工具。它完全在线开发,无需安装IDE,拖拽组件就能完成APP设计。首先在浏览器打开App Inventor官网,新建项目后按以下步骤操作:
界面设计:
- 添加1个ListPicker(选择蓝牙设备)
- 添加4个Button(连接、断开、亮度+、亮度-)
- 添加1个Slider(亮度精细调节)
逻辑设计: 关键是要使用BluetoothLE组件,设置服务UUID为0xFFE0,特征UUID为0xFFE1(这是JDY-18的默认配置)。具体代码块包括:
- 扫描蓝牙设备
- 连接/断开处理
- 发送控制指令
我分享一个实用技巧:在发送数据时,最好添加简单的校验机制。比如发送亮度值时,我采用"L=xxx\n"的格式,STM32端解析时先检查首字母,这样能避免误操作。完整的APP源码可以导出为aia文件,我已经上传到GitHub,文末会给出链接。
6. 系统调试与优化建议
实际调试中可能会遇到几个典型问题。首先是蓝牙连接不稳定,这通常是因为天线摆放不当。JDY-18的PCB天线要避免被金属物体遮挡,我建议将模块直立放置。其次是PWM调光时有闪烁,这个问题困扰了我很久,最后发现是电源问题——当使用USB供电时电流不足,改用5V/2A的电源适配器后问题解决。
对于想进一步优化的朋友,我有几个建议:
- 增加状态反馈:让STM32定时向APP发送当前亮度值
- 添加场景模式:比如"阅读模式"、"影院模式"等预设亮度
- 实现定时功能:通过APP设置定时开关
- 加入OTA升级:通过蓝牙更新STM32固件
电源管理方面,如果要做成产品,可以考虑加入锂电池充放电管理电路,配合JDY-18的低功耗特性,可以实现数月待机。我在面包板上测试的完整系统,在5V供电下,驱动3个LED总电流约60mA,完全可以用移动电源供电。
