STM32蓝牙APP控制继电器:物联网入门实战教程
2026/9/1 4:16:06 网站建设 项目流程

这次我们来看一个非常实用的物联网控制项目:STM32单片机通过蓝牙APP控制2路继电器。这个项目不是停留在概念,而是能让你快速搭建一套可用的远程开关控制系统。核心就是利用一块常见的STM32开发板,搭配一个蓝牙模块(如HC-05/06),再编写一个简单的手机APP,实现对两个继电器(可以控制灯、风扇、电机等设备)的无线控制。

对于嵌入式开发者、电子爱好者或物联网初学者来说,这个项目的价值在于门槛低、成本可控、功能完整。你不需要复杂的网络协议栈,也不需要云服务器,就能实现一个典型的“手机控制硬件”场景。本文将带你从零开始,理清硬件选型、电路连接、STM32程序编写、蓝牙通信协议设计以及手机APP开发(提供简易方案)的全过程。读完本文,你将能够独立完成一套可工作的蓝牙继电器控制系统,并理解其扩展为更多路数或集成到更复杂项目中的方法。

1. 核心能力速览

在深入细节之前,我们先通过一个表格快速了解这个项目的关键信息,帮助你判断是否适合自己。

能力项说明
核心功能通过手机蓝牙APP,无线控制STM32连接的2路继电器开关状态。
主控芯片STM32系列单片机(如STM32F103C8T6,即常见的“蓝/黑”板)。
蓝牙模块经典蓝牙串口模块(如HC-05,HC-06),成本低廉,连接简单。
继电器模块2路继电器模块,通常支持5V或3.3V驱动,可控制220V/10A以内的交流负载。
开发环境Keil MDK-ARM / STM32CubeIDE, 配合STM32标准库或HAL库。
APP开发可使用Android Studio(Java/Kotlin)或更简单的MIT App Inventor等图形化工具。
通信协议自定义简单的串口字符指令,例如A开继电器1,a关继电器1。
供电要求5V USB供电或7-12V直流电源输入即可,整体功耗低。
适合场景智能家居原型(灯、窗帘)、实验室设备远程控制、物联网教学演示、小型自动化项目。
扩展潜力可轻松增加继电器路数、添加传感器反馈、改为Wi-Fi或4G控制。

2. 适用场景与使用边界

这个项目虽然简单,但能解决不少实际问题。它最适合那些需要低成本、快速实现、无线控制开关量设备的场景。

典型适用场景包括:

  1. 智能家居原型验证:控制房间的灯光、插座、小功率电器,验证想法可行性。
  2. 教学与实验:作为单片机、嵌入式系统、物联网通信课程的绝佳实践案例,涵盖GPIO控制、串口通信、外设驱动等多个知识点。
  3. 小型自动化控制:控制实验室的加热装置、搅拌器、通风设备,或者模型沙盘中的灯光、水泵。
  4. 设备状态远程指示:虽然本项目主要控制,但稍加修改(如读取继电器状态或接入传感器),也能实现状态上报。

使用边界与安全警告:

  1. 电气安全第一:继电器模块用于控制强电(220V交流)时,必须确保接线规范、绝缘良好,操作时断电进行。非专业人士请勿直接操作强电,建议先使用低压直流负载(如LED、小电机)进行测试。
  2. 控制功率限制:注意继电器模块的触点容量(如10A 250VAC),严禁超负荷使用,以免引发火灾。
  3. 通信距离限制:经典蓝牙(如HC-05)的有效通信距离通常在10米以内(无遮挡),不适合远距离控制。
  4. 非商业级产品:本项目作为学习和原型开发,在稳定性、安全性、抗干扰能力上无法与成熟商业产品相比,请勿直接用于对可靠性要求极高的生产环境或人身安全相关的控制。
  5. 隐私与授权:自制的蓝牙APP仅用于控制自有设备。任何涉及控制他人设备或公共设备的行为,必须获得明确授权,遵守相关法律法规。

3. 环境准备与前置条件

动手之前,请确保你已准备好以下软硬件环境。清单中的大部分物品都能在电商平台轻松购得。

硬件清单:

  1. STM32最小系统板:推荐使用STM32F103C8T6核心板(约10-20元),它资源丰富,社区支持好。
  2. 蓝牙串口模块:HC-05(主从一体)或HC-06(从机模式)。HC-05更常用,建议购买已焊好插针的模块。
  3. 2路继电器模块:选择支持低电平触发的5V继电器模块,通常带有光耦隔离和指示灯。
  4. USB转TTL串口模块:用于STM32程序下载和调试,如CH340、CP2102模块。
  5. 杜邦线:若干(公对公、公对母),用于连接。
  6. 负载:用于测试,如LED灯和220Ω电阻(低压测试),或一个小台灯(强电测试,务必谨慎!)。
  7. 电源:5V/2A的USB电源或手机充电器,用于给整个系统供电。

软件清单:

  1. 开发IDE
    • Keil MDK-ARM:传统且强大,需安装STM32器件支持包。
    • STM32CubeIDE:ST官方免费IDE,集成CubeMX图形化配置,对新手友好。本文示例将侧重HAL库,可在CubeIDE中完成。
  2. STM32CubeMX:如果使用Keil,也需要用它来生成初始化代码。它是ST的图形化配置工具。
  3. 串口调试助手:如SSCOM、XCOM、Putty等,用于测试蓝牙模块和STM32的串口通信。
  4. 手机APP开发工具(二选一):
    • MIT App Inventor:在线图形化编程,无需代码基础,快速生成安卓APP。最适合初学者快速验证
    • Android Studio:开发功能更完善、界面更专业的原生APP。

4. 硬件连接与电路设计

正确的硬件连接是成功的第一步。下图展示了系统的核心连接关系:

[手机蓝牙APP] <--(蓝牙无线)--> [HC-05蓝牙模块] <--(串口TX/RX)--> [STM32单片机] <--(GPIO)--> [继电器模块] <--(强电端)--> [用电设备]

具体接线步骤(以STM32F103C8T6和HC-05为例):

  1. 供电统一:将STM32核心板、继电器模块、HC-05模块的VCC(5V)和GND分别连接到一起,确保共地。可以使用面包板或焊接。
  2. STM32与HC-05连接
    • HC-05的TXD接 STM32的PA3(USART2_RX)。
    • HC-05的RXD接 STM32的PA2(USART2_TX)。
    • 注意:蓝牙模块的TXD要接MCU的RXD,反之亦然。
  3. STM32与继电器模块连接
    • 继电器模块的IN1接 STM32的PB0(用于控制继电器1)。
    • 继电器模块的IN2接 STM32的PB1(用于控制继电器2)。
    • 继电器模块的VCC5VGNDGND
    • 注意:大多数继电器模块低电平触发,即STM32引脚输出低电平时继电器吸合,高电平时断开。程序需对应。
  4. 继电器负载端连接(低压测试示例)
    • 将继电器的COM(公共端)接电源正极(如5V)。
    • 将继电器的NO(常开端)接一个LED的正极。
    • LED的负极接一个220Ω限流电阻后,连接到电源负极(GND)。
    • 当继电器吸合时,COMNO接通,电路闭合,LED点亮。

关键点说明:

  • 电平匹配:HC-05模块是3.3V TTL电平,但通常兼容5V供电和通信。STM32F103的IO口也是3.3V,两者直接连接无问题。
  • 启动模式:STM32需要设置BOOT0和BOOT1引脚为正常启动模式(通常BOOT0=0,BOOT1=x),才能运行用户程序。
  • 下载接口:使用USB转TTL模块下载程序时,连接STM32的PA9(TX)和PA10(RX),注意交叉连接,并确保在下载时正确操作复位和BOOT0引脚。

5. STM32程序设计详解

我们将使用STM32CubeMX生成基础工程,然后在STM32CubeIDE中编写业务逻辑。程序的核心是:初始化串口和GPIO,在串口中断中接收APP发来的指令,并控制对应的GPIO输出高低电平。

5.1 使用STM32CubeMX配置工程

  1. 新建项目:打开CubeMX,选择MCU型号STM32F103C8Tx
  2. 配置时钟:在RCC中,将HSE设置为Crystal/Ceramic Resonator
  3. 配置SYS:将Debug设为Serial Wire(方便ST-Link调试)。
  4. 配置USART2
    • 模式选择Asynchronous(异步)。
    • 参数默认(波特率9600, 8位数据,无校验,1停止位)。可与蓝牙模块匹配,后期可改为115200等更高波特率。
    • 开启中断:在NVIC Settings中勾选USART2 global interrupt
  5. 配置GPIO
    • PB0PB1设置为GPIO_Output,初始输出电平设为高电平(因为继电器模块低电平触发,初始状态应为断开)。
    • 可以重命名为RELAY1_CTRLRELAY2_CTRL以便识别。
  6. 配置时钟树:在Clock Configuration标签页,将系统时钟(HCLK)设置为最高72MHz。
  7. 生成代码:在Project Manager中设置项目名称、路径、选择IDE为STM32CubeIDE,然后点击GENERATE CODE

5.2 编写核心控制代码

在生成的工程中,我们主要修改main.cstm32f1xx_it.c(中断服务函数)。

main.c/* USER CODE BEGIN PV */区域定义变量:

/* Private variables ---------------------------------------------------------*/ uint8_t uart_rx_buffer = 0; // 用于存储接收到的单个字节 uint8_t relay1_state = 0; // 继电器1状态,0=关,1=开 uint8_t relay2_state = 0; // 继电器2状态

main.c/* USER CODE BEGIN 2 */区域,启动串口接收中断:

/* USER CODE BEGIN 2 */ // 启动串口2接收中断(以字节为单位) HAL_UART_Receive_IT(&huart2, &uart_rx_buffer, 1); /* USER CODE END 2 */

stm32f1xx_it.c文件中,找到串口2中断服务函数USART2_IRQHandler,并在其中调用HAL库的中断处理函数。我们主要修改其回调函数。

main.c文件末尾的/* USER CODE BEGIN 4 */区域,重写串口接收完成回调函数HAL_UART_RxCpltCallback

/* USER CODE BEGIN 4 */ // 串口接收中断回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) // 判断是串口2 { // 根据接收到的字符执行相应动作 switch(uart_rx_buffer) { case 'A': // 打开继电器1 HAL_GPIO_WritePin(RELAY1_CTRL_GPIO_Port, RELAY1_CTRL_Pin, GPIO_PIN_RESET); // 输出低电平 relay1_state = 1; break; case 'a': // 关闭继电器1 HAL_GPIO_WritePin(RELAY1_CTRL_GPIO_Port, RELAY1_CTRL_Pin, GPIO_PIN_SET); // 输出高电平 relay1_state = 0; break; case 'B': // 打开继电器2 HAL_GPIO_WritePin(RELAY2_CTRL_GPIO_Port, RELAY2_CTRL_Pin, GPIO_PIN_RESET); relay2_state = 1; break; case 'b': // 关闭继电器2 HAL_GPIO_WritePin(RELAY2_CTRL_GPIO_Port, RELAY2_CTRL_Pin, GPIO_PIN_SET); relay2_state = 0; break; case 'S': // 查询状态 { char status_msg[32]; sprintf(status_msg, "R1:%d,R2:%d\n", relay1_state, relay2_state); HAL_UART_Transmit(&huart2, (uint8_t*)status_msg, strlen(status_msg), 100); } break; default: // 收到未知指令,可忽略或返回错误 break; } // 重新开启接收中断,等待下一个字节 HAL_UART_Receive_IT(&huart2, &uart_rx_buffer, 1); } } /* USER CODE END 4 */

代码逻辑解析:

  1. HAL_UART_Receive_IT启动了一次性接收1字节的中断。
  2. 当蓝牙模块通过串口发送一个字符到STM32时,触发中断,进入回调函数。
  3. 在回调函数中,根据收到的字符(uart_rx_buffer)执行对应的开关动作。
  4. 控制继电器实质是控制GPIO引脚输出高低电平。GPIO_PIN_RESET为低电平(继电器吸合),GPIO_PIN_SET为高电平(继电器断开)。
  5. 指令S用于查询状态,STM32会将两个继电器的当前状态格式化成字符串(如R1:1,R2:0\n)发回给手机APP,实现简单的状态反馈。
  6. 每次处理完指令后,必须再次调用HAL_UART_Receive_IT重新使能接收中断,否则只会接收一次。

5.3 编译与下载

  1. 在STM32CubeIDE中,点击锤子图标编译项目,确保0错误,0警告。
  2. 将USB转TTL模块的TXRXGND分别连接到STM32的PA10(RX)、PA9(TX)、GND
  3. 设置STM32为下载模式(BOOT0=1, BOOT1=0),上电复位。
  4. 在IDE中选择正确的下载器配置(如ST-Link或串口),点击下载按钮。
  5. 下载完成后,将STM32设置为运行模式(BOOT0=0),复位重启。

6. 蓝牙模块配置与测试

新的HC-05模块通常需要配置其角色和波特率。我们可以先用USB转TTL模块连接电脑进行配置。

配置步骤:

  1. 连接:将HC-05的VCC(5V)、GNDTXDRXD分别接USB转TTL模块的5VGNDRXDTXD注意交叉
  2. 进入AT模式:按住HC-05模块上的小按钮(或使KEY/EN引脚接高电平),再给模块上电。此时模块指示灯慢闪(约2秒一次),表示进入AT命令模式。
  3. 串口助手设置:打开串口调试助手,选择正确的COM口,波特率设置为38400(HC-05 AT模式默认波特率),数据位8,停止位1,无校验。
  4. 发送AT指令
    • 发送AT,应返回OK
    • 发送AT+NAME=MyRelay,设置蓝牙名称为MyRelay
    • 发送AT+PSWD=1234,设置配对密码为1234
    • 发送AT+UART=9600,0,0,设置通信波特率为9600(与STM32程序匹配)。
    • 发送AT+ROLE=0,设置模块为从机模式(HC-06可跳过,它只能是从机)。
  5. 退出AT模式:断开电源,重新上电(不按按钮),指示灯快闪,进入可配对状态。

与STM32联调测试:

  1. 将配置好的HC-05按第4章方式连接到STM32。
  2. 给整个系统供电。
  3. 打开手机蓝牙设置,搜索并配对名为MyRelay的设备,密码1234
  4. 在手机上安装一个通用的“蓝牙串口”APP(如Serial Bluetooth Terminal)。
  5. 在APP中连接MyRelay
  6. 在APP的发送框中输入指令AaBb,分别观察两个继电器是否相应吸合/断开,同时观察LED的亮灭。输入S,查看是否返回状态信息。

至此,硬件和STM32底层驱动部分已全部完成。如果测试成功,说明你的蓝牙通信链路和继电器控制基础功能已经正常。

7. 手机APP开发方案(MIT App Inventor)

对于大多数只想快速实现功能的开发者,MIT App Inventor是最佳选择。它是一个图形化编程的在线平台,无需编写复杂代码。

核心组件与逻辑:

  1. 界面设计:添加两个按钮用于开关继电器1,两个按钮用于开关继电器2,一个按钮用于查询状态,一个标签(Label)用于显示状态,一个列表选择框(ListPicker)用于选择蓝牙设备,以及必要的蓝牙客户端(BluetoothClient)组件。
  2. 逻辑设计
    • 点击“连接设备”按钮,调用ListPicker显示已配对的蓝牙设备列表,选择后通过BluetoothClient连接。
    • 连接成功后,点击“开继电器1”按钮,通过BluetoothClient发送字符A
    • 点击“关继电器1”按钮,发送字符a。继电器2同理。
    • 点击“查询状态”按钮,发送字符S
    • 配置BluetoothClient当收到数据时事件,将接收到的字节解码为字符串,并更新到显示状态的标签中。

关键积木块示例(文字描述):

  • 连接设备:当ListPicker选择后 -> 调用BluetoothClient.Connect连接选中的地址。
  • 发送指令:当按钮被点击 -> 调用BluetoothClient.SendText发送对应的单字符(如A)。
  • 接收数据:当BluetoothClient收到数据 -> 用BluetoothClient.ReceiveText获取文本 -> 设置标签的显示文本为接收到的内容。

导出与安装:在App Inventor中完成设计后,可以打包生成APK文件,通过二维码下载安装到安卓手机。这样,一个专属的控制APP就诞生了。

8. 功能测试与效果验证流程

完成所有部分后,需要进行系统化测试,确保功能稳定可靠。

测试1:基础指令控制测试

  • 操作:手机APP依次发送A,a,B,b
  • 预期:继电器1吸合->断开,继电器2吸合->断开。可听到清晰的“咔哒”声,指示灯状态变化,负载(LED)同步亮灭。
  • 失败排查
    • 继电器无反应:检查STM32 GPIO引脚输出电平(用万用表测量),检查继电器模块供电和输入信号线连接。
    • 手机APP显示发送成功但无效果:用串口调试助手监听STM32与HC-05之间的TX/RX线,看指令是否被正确传输。检查STM32程序中的指令字符判断逻辑。

测试2:状态查询与反馈测试

  • 操作:手动改变继电器状态(或通过指令),然后发送S
  • 预期:手机APP收到格式为R1:1,R2:0的字符串,并正确显示。
  • 失败排查
    • 无返回数据:检查STM32的串口发送代码,确认HAL_UART_Transmit函数被调用且参数正确。
    • 返回乱码:检查手机APP和STM32的串口波特率、数据格式是否一致。

测试3:连续操作与稳定性测试

  • 操作:快速、随机地点击APP上的各个开关按钮,持续1-2分钟。
  • 预期:每次操作都有正确响应,无继电器误动作、程序死机或蓝牙断开连接。
  • 失败排查
    • 蓝牙断开:检查供电是否稳定,距离是否过远或有严重遮挡。
    • 程序死机:检查STM32的中断处理函数是否过于冗长或存在逻辑错误,导致无法及时响应新指令。

测试4:负载带载能力测试(务必注意安全!)

  • 操作:在继电器输出端接入额定范围内的实际负载(如小功率台灯)。
  • 预期:能正常控制负载的通断,继电器触点无打火、过热现象。
  • 失败排查:如控制大功率负载失败,检查电源容量是否足够,继电器规格是否匹配,强电接线是否牢固。

9. 资源占用与性能观察

对于STM32F103C8T6这款芯片,本项目的资源占用极低,留有大量空间用于功能扩展。

  • Flash占用:上述核心程序(包含HAL库、串口中断、GPIO控制)编译后通常不超过20KB,远小于芯片64KB的Flash容量。
  • RAM占用:全局变量很少,主要消耗在栈和中断,通常不超过2-3KB,远小于20KB的RAM。
  • CPU负载:系统绝大部分时间处于空闲或低功耗状态,仅在收到蓝牙指令时触发短暂的中断处理,CPU负载可忽略不计。
  • 功耗:核心板、蓝牙模块、继电器模块(线圈未吸合时)的静态总电流约50-100mA。继电器吸合时,线圈电流会增加(约70mA/路)。整体可由USB口或5V/1A适配器轻松驱动。

性能优化方向:

  1. 提高波特率:将串口波特率从9600提升到115200或更高,可以加快指令传输速度,减少延迟感。
  2. 指令协议优化:当前单字符指令简单,但易误操作。可改为带校验的帧结构,如[帧头][指令码][数据][校验和][帧尾],提高可靠性。
  3. 增加看门狗:在main函数的循环中喂狗,防止程序跑飞导致设备失控。
  4. 低功耗模式:如果由电池供电,可以在无操作时让STM32进入睡眠模式,蓝牙模块唤醒后再激活MCU。

10. 常见问题与排查方法

在开发过程中,你可能会遇到以下问题。下表提供了系统的排查思路。

问题现象可能原因排查步骤解决方案
蓝牙APP搜不到设备1. 蓝牙模块未供电或损坏。
2. 模块未进入配对状态(指示灯非快闪)。
3. 手机蓝牙未打开或距离过远。
1. 检查模块VCC、GND是否接好,电压是否正常(5V)。
2. 观察模块指示灯状态。
3. 重启手机蓝牙,靠近模块。
1. 确保供电正确。
2. 重新上电,确认模块处于可配对模式。
3. 更换手机或蓝牙模块测试。
APP连接后立即断开1. 波特率不匹配。
2. 模块与STM32的TX/RX接反。
3. STM32串口未初始化或初始化错误。
1. 用串口助手分别测试模块和STM32的收发。
2. 检查接线。
3. 检查CubeMX串口配置和程序初始化代码。
1. 统一配置波特率(如9600)。
2. 交叉连接TX/RX。
3. 确保HAL_UART_Init成功,并启动了接收中断。
发送指令,继电器无反应1. 指令字符错误(大小写)。
2. STM32 GPIO引脚配置错误(非输出模式)。
3. 继电器模块触发方式不匹配(高/低电平)。
1. 用串口助手监听STM32的RX引脚,确认收到正确字符。
2. 用万用表测量控制引脚电压变化。
3. 查阅继电器模块手册。
1. 核对APP发送字符与程序判断字符。
2. 检查CubeMX中GPIO配置。
3. 修改程序中的输出电平逻辑(SET/RESET互换)。
继电器状态随机切换或抖动1. 电源干扰或功率不足。
2. GPIO引脚受干扰。
3. 蓝牙数据受到干扰,收到错误指令。
1. 测量电源电压在负载动作时是否跌落严重。
2. 在控制引脚加一个下拉电阻(如10kΩ到GND)。
3. 在串口中断回调中增加指令有效性校验。
1. 使用更稳定、功率更大的电源,并在电源入口加滤波电容。
2. 软件上可对指令进行连续多次判断再执行。
程序下载失败1. BOOT模式设置错误。
2. 下载器驱动或连线问题。
3. 芯片已写保护。
1. 确认BOOT0=1(下载),BOOT1=0。
2. 检查USB转TTL驱动,TX/RX是否交叉连接。
3. 使用STM32CubeProgrammer尝试解除保护。
1. 严格按照下载模式操作。
2. 更换下载线或接口。
3. 使用编程器解除读保护。

11. 项目扩展与进阶思路

这个双路继电器控制项目是一个完美的起点,你可以基于它进行多种扩展,打造更强大的控制系统。

  1. 增加控制路数:STM32F103C8T6有大量空闲GPIO,可以轻松控制8路、16路甚至更多的继电器。只需在程序中定义更多的控制引脚和状态变量,并扩展指令协议(如C/c控制第三路)。
  2. 加入传感器反馈:接入温湿度传感器(如DHT11)、光照传感器、人体红外传感器等。STM32读取传感器数据后,不仅可以通过蓝牙上报给APP,还可以实现本地自动控制逻辑(如温度过高自动打开风扇)。
  3. 改进通信协议:使用更严谨的帧协议,例如0xAA 0x01 0x01 0xAC表示打开第一路,其中包含帧头、地址、命令、校验和,大大提高抗干扰能力和可靠性。
  4. 更换通信方式
    • Wi-Fi:使用ESP8266/ESP32模块,通过MQTT协议接入家庭局域网或物联网平台(如阿里云、Home Assistant),实现远程控制。
    • 4G Cat.1:使用移远EC200S等模块,直接通过蜂窝网络控制,无距离限制。
  5. 设计专用PCB:将STM32最小系统、继电器驱动电路、电源电路、蓝牙模块接口集成到一块PCB上,使产品更紧凑、可靠。
  6. 开发更专业的APP:使用Android Studio或Flutter开发功能更全的APP,包括场景模式(一键全开/全关)、定时任务、状态历史记录、用户登录等。
  7. 接入语音控制:通过APP集成语音识别SDK,或使用独立的语音模块(如LD3320),实现“小爱同学,打开客厅灯”这样的语音控制。

12. 总结与下一步

这个“STM32单片机蓝牙APP控制2路继电器”项目,成功串联了嵌入式硬件、单片机编程、无线通信和移动应用开发几个关键环节。它的价值不在于复杂度,而在于完整的闭环实现极高的可扩展性

你应该最先验证的是蓝牙通信链路基本的GPIO控制,这是整个系统的基石。最容易踩的坑通常是电平匹配串口交叉接线电源干扰。按照本文的步骤,从硬件连接到CubeMX配置,再到指令逻辑编写和APP测试,一步步走下来,成功点亮LED的那一刻,你会对物联网控制有最直观的理解。

接下来,你可以尝试修改指令协议,增加一路继电器控制,或者尝试用手机APP做一个简单的界面来同时显示继电器状态和控制开关。当你熟悉了整个流程后,将其改造成Wi-Fi控制、加入温控逻辑,或是集成到你的毕业设计、创新项目中,就会变得水到渠成。建议将本文的代码和配置作为基础模板收藏,在未来的项目中随时复用和修改。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询