直接说结论:这是入门蓝牙硬件控制性价比最高的一条路。HC05 加一块 UNO 板载 LED,整套下来不超过 30 块钱,却能完整跑通“手机发指令-蓝牙透传-单片机解析-外设动作”的全链路。这篇文章我会从选型思路、接线、AT 指令配置、代码烧录到手机端调试,一步步讲清楚,尤其会重点说说 HC05 连不上、乱码、主从模式这些坑。适合刚接触 Arduino、想玩蓝牙控制的同学,也适合想把手头 HC05 模块用起来的老手。
1. 项目整体设计与思路拆解
1.1 为什么选 HC05 而不是其他蓝牙方案
市面上常见的蓝牙模块有 HC05、HC06、JDY-31、HM-10 这些,但做手机控制外设,HC05 依然是最稳妥的选择。核心原因就一个:HC05 支持主从一体,既能当从机被手机连接,也能当主机去连接别的蓝牙设备。而 HC06 只能做从机,JDY-31 虽然便宜且支持 AT 指令,但兼容性和资料丰富度都不如 HC05。
从成本角度算一笔账:一块 HC05 模块大概 15 到 20 元,UNO 板如果是兼容版也就 20 元出头,板载 LED 是现成的,不需要额外买硬件。相比 ESP32 的蓝牙方案,HC05 的学习曲线更平缓——它不需要你理解复杂的协议栈,本质上就是一个“无线串口”,把 TX、RX 对接好就能用。
还有一点容易被忽略:HC05 的 AT 指令是标准化的。这意味着你配好一个模块,后面做双机通信、主从切换、改波特率、改名称密码,全都有固定套路,不会因为换了商家就出现玄学差异。对于系列教程来说,这种可复制性很重要。
1.2 用板载 LED 做实验的科学性在哪
很多同学第一次做蓝牙控制,第一反应是外接一个 LED 或者继电器,这其实没必要。UNO 板载的 L 口 LED 接了数字引脚 13,而且引脚 13 上有板载电阻,不需要额外串限流电阻,直接就能用。用它做实验的最大好处是:排查问题范围足够小。
想清楚这个逻辑:如果手机发了指令灯不亮,可能性只有三种——蓝牙链路没通、串口数据没到、代码逻辑出错。如果你外接了一堆传感器和继电器,问题就可能是供电不足、引脚冲突、电平不匹配。从板载 LED 起步,等于把变量控制在最小范围,这对新手排查问题非常友好。
还有一个实际考量:板载 LED 在 UNO 上电时就会有一个闪烁程序,如果烧录前能看见 LED 在闪,说明板子本身是好的。到烧录代码后,如果 LED 不再按默认节奏闪,而是被你的指令控制,那说明你的整套链路已经通了。这个从“默认态”到“受控态”的转变,本身就是一个天然的验证信号。
1.3 这个项目能延伸到哪些场景
别小看“控制一个 LED 亮灭”这件事,它背后是物联网控制的最简模型。把板载 LED 换成继电器,就是远程开关插座;换成水泵,就是远程浇花;换成舵机,就是远程开门。我在后面的系列文章里会逐步扩展,但第一步必须先把这套链路跑稳。
关于选型,我再多说一句:为什么不用蓝牙 4.0 的 HM-10?因为 HM-10 的 BLE 协议和 Android 手机的兼容性有坑,尤其是老版本 Android 手机和 iOS 设备,经常出现配对成功后秒断的情况。HC05 走的是经典蓝牙 2.0 协议,几乎所有手机都能稳定连接,传输距离还更远,实测在空旷环境下能到 10 米。做教学项目,稳定性远比先进性重要。
2. 硬件准备与接线实操要点
2.1 物料清单与购买注意事项
做这个项目你需要准备的物料非常简单,但有几个细节值得说道。UNO 板建议选带有 CH340 芯片的兼容版,便宜且驱动好装,原版是 16U2 芯片,虽然稳定性更好,但价格高出好几倍,对新手来说没必要。
HC05 模块要注意区分“带底板”和“裸板”。带底板的版本引出了排针,可以直接插面包板,上面通常还带一个稳压芯片,输入 5V 没问题。裸板则只有排针孔,而且不带稳压,供电必须是 3.6 到 6V,接 5V 勉强能用但有点悬。我建议多花几块钱买带底板的,省去很多麻烦。
还需要一根 USB 数据线,注意必须是带数据传输的线,不是只有充电功能的那种。判断方法很简单:插上电脑后设备管理器能识别到 COM 口,就是数据线。那种只能充电的线看起来一模一样,很多新手在这里卡了半天。
配套的还有杜邦线若干、一个智能手机。手机端需要装一款蓝牙串口 APP,我后面会专门说怎么选。
2.2 模块引脚对应关系详解
HC05 模块的引脚不多,但接线时非常容易出错。先看背面丝印,一般有六个引脚:EN(有的标 KEY)、VCC、GND、TXD、RXD、STATE。
关键点来了:HC05 的 TXD 要接 UNO 的 RX(引脚 0),RXD 要接 UNO 的 TX(引脚 1)。这就是最经典的交叉接线法——发送接接收,接收接发送。不理解这个的同学可以想成两个人对话:A 的嘴巴必须对着 B 的耳朵,如果嘴巴对嘴巴,那谁都听不见谁。
这里有一个新手最容易踩的坑:UNO 的引脚 0 和引脚 1 在插上 HC05 后,不能再用来做其他通信。因为这两个引脚是 USB 转串口芯片和主控芯片之间的通信通道,你外接蓝牙模块占用了它们,USB 串口就会“失效”。也就是说,如果你用 HC05 占用了引脚 0 和 1,烧录程序会失败,除非你先拔掉 HC05 或者把 UNO 的 RX、TX 接到其他软串口引脚上。
供电方面:VCC 接 5V,GND 接 GND。STATE 引脚是状态输出,未连接时低电平,连接后高电平,可以用来驱动一个 LED 指示蓝牙连接状态,这个引脚可以不接,不影响功能。
2.3 接线过程与检查方法
具体接线顺序建议这样做:
- 先把 UNO 断电,确保安全。
- 用杜邦线将 HC05 的 RXD 连接到 UNO 的引脚 1(TX)。
- 将 HC05 的 TXD 连接到 UNO 的引脚 0(RX)。
- VCC 接 5V,GND 接 GND。
- 连接好后仔细检查一遍,尤其确认有没有接反 TX 和 RX。
接好以后给 UNO 上电,观察 HC05 模块上的 LED 状态。HC05 的板载 LED 通常有两种闪烁模式:快闪(大约 2 秒闪一次)表示处于 AT 命令模式或者等待配对;慢闪(大约 1 秒闪一次)表示已经连接上设备。如果 LED 不亮,先查供电;如果 LED 常亮不动,也属于正常情况,说明模块可能在等待配置。
另一个检查方法:开机后手机搜索蓝牙设备,如果能搜到一个名为“HC-05”的设备,说明模块供电和基本功能都正常。这时候可以先用手机配对试试,密码默认是 1234 或 0000。如果手机能配对成功,说明模块工作正常,问题大概率在后期配置。
注意:给 HC05 接线的顺序很重要,我建议先接 GND,再接 VCC,最后接 TX 和 RX。因为模块在上电瞬间如果有 GPIO 口电平抖动,可能会导致误触发进入 AT 模式,先接好地线和电源线能减少这种问题。
3. 核心代码实现与参数配置详解
3.1 两种模式的区别与切换方法
HC05 有AT 命令模式和通信模式两种工作状态,这是整个项目的关键。AT 模式下模块接收 AT 指令来配置参数,通信模式下模块作为无线串口透传数据。区分的方法是看模块上的 LED 闪烁频率:AT 模式大约 2 秒快闪一次,通信模式大约 1 秒慢闪一次。
进入 AT 模式有两种方式,取决于你的模块是带底板还是裸板。带底板的模块上有一个按钮(有的叫 EN,有的叫 KEY),按住按钮然后给模块上电,模块就会进入 AT 模式。裸板则需要把 EN/KEY 引脚拉高到 VCC,同样是在上电前拉高。
如果要在不拆线的情况下进入 AT 模式,还有一个办法:先把蓝牙从手机上断开,再短按底板上的按钮,让模块进入 AT 模式。但这个方法不太稳定,我建议你还是按规范来:接好 EN 到 VCC 的跳线,再上电。
这里有个细节很多教程不会提:如果你已经通过 UNO 给 HC05 供电,那么进入 AT 模式需要在 UNO 上电前就把 EN 拉高。用 Arduino 代码里的delay(1000)加空闲引脚拉高也可以,但那是更进阶的方案。新手就用最笨但最可靠的方法——拔掉 HC05 供电,接上 EN 到 VCC 跳线,再重新上电。
3.2 AT 指令配置实操
进入 AT 模式后,你需要通过串口给 HC05 发送指令。这里的坑点在于:AT 模式要求波特率是 38400,而不是默认的 9600。很多新手在这里犯迷糊,配了半天没反应,其实只是波特率选错了。
我用的是 UNO 自带的 USB 转串口功能,通过 Arduino IDE 的串口监视器发送 AT 指令。具体操作如下:
- 打开 Arduino IDE,选择好正确的端口(在设备管理器里查看 COM 口编号)。
- 打开串口监视器,波特率选 38400。
- 在发送框中输入
AT,点击发送。如果返回OK,说明模块在 AT 模式且通讯正常。 - 输入
AT+NAME=MyBluetooth,设置模块名称(可选)。 - 输入
AT+PSWD=1234,设置配对密码(可选,不设置默认就是 1234 或 0000)。 - 输入
AT+UART=9600,0,0,将通信波特率设置为 9600(这里是为了和后面代码一致)。 - 输入
AT+ROLE=0,设置模块为从机模式(这是手机连接模块的模式)。 - 最后给模块重新上电,退出 AT 模式进入通信模式。
要注意一点:串口监视器如果勾选了“发送新行”(默认开启),会在指令末尾追加一个回车符,HC05 对 AT 指令是接受回车换行的。如果取消勾选“发送新行”,指令可能没反应。我试过好几次,有时候明明指令没错但没返回,就是因为发送框末尾没带换行。
3.3 Arduino 代码开发与逐行解读
模块配好后,剩下的就是写 Arduino 代码了。核心逻辑非常简单:初始化串口,读取蓝牙发来的数据,判断字符后控制板载 LED。
看一下完整的示例代码:
// 引脚定义 const int ledPin = 13; // UNO 板载 LED // 程序初始化 void setup() { // 初始化板载 LED 引脚为输出 pinMode(ledPin, OUTPUT); // 初始化串口通信,波特率必须与 HC05 通信模式一致 Serial.begin(9600); // 起始状态:LED 熄灭 digitalWrite(ledPin, LOW); } // 主循环 void loop() { // 检查串口是否有数据 if (Serial.available() > 0) { // 读取一个字节 char cmd = Serial.read(); // 字符 '1' 点亮 LED if (cmd == '1') { digitalWrite(ledPin, HIGH); Serial.println("LED ON"); } // 字符 '0' 熄灭 LED else if (cmd == '0') { digitalWrite(ledPin, LOW); Serial.println("LED OFF"); } } }这个代码里有个细节要注意:Serial.begin(9600)的波特率必须和 HC05 通信模式一致。我在前面 AT 配置里特意设置了AT+UART=9600,0,0,就是为了这一步能对得上。如果你的 HC05 模块之前被设置过其他波特率,这里就要改成相应值,否则收到的全是乱码。
代码里的Serial.println("LED ON")这句话不是必须的,但保留它对调试有帮助。它会把控制结果回传给手机,你在手机 APP 里能看到反馈信息,知道命令确实被执行了。
烧录这个代码有个小技巧:如果 HC05 已经接在了引脚 0 和 1 上,直接烧录大概率会失败,因为 HC05 会干扰 USB 串口通信。解决办法是先拔掉 HC05 的 TX 线(或直接把 HC05 断电),烧录成功后再接回去。
3.4 一个进阶小技巧:软串口实现同时调试
如果你想让 HC05 烧录时不拔线也能工作,可以用软串口方案,即用 UNO 的其他数字引脚模拟串口。这样的话,HC05 接在引脚 2 和 3 上,引脚 0 和 1 保留给 USB 调试用。典型代码如下:
#include <SoftwareSerial.h> SoftwareSerial BT(2, 3); // RX, TX void setup() { Serial.begin(9600); BT.begin(9600); } void loop() { if (BT.available()) { char cmd = BT.read(); Serial.print(cmd); if (cmd == '1') { digitalWrite(13, HIGH); } else if (cmd == '0') { digitalWrite(13, LOW); } } }软串口的缺点是最高波特率有限制,9600 没问题,28800 以上就可能丢数据。但用来做蓝牙控制足够用了。我建议新手做这个项目优先用软串口,因为烧录调试方便很多,不需要每次拔线。
4. 手机端操作与联调实录
4.1 蓝牙串口 APP 的选型问题
手机端的 APP 选择没有统一标准,但有几个硬性要求:能连接经典蓝牙(不是 BLE)、能发送自定义字符串、最好能显示十六进制数据。我用过几款,功能大同小异,关键是别选那些只支持 BLE 的 App。
建议先打开手机蓝牙,搜索并配对 HC05。配对成功后,再打开串口 APP,连接到 HC05。有几个 APP 在配对后还需要在 APP 内建立连接,这一步不能省。
这里有一个常见的错误理解:手机的系统蓝牙设置里显示“已配对”,不等于 APP 能通信。必须让 APP 主动建立串口连接,通信才会建立。如果在系统设置里配对成功但 APP 不发送数据,请回 APP 检查连接状态。
有些手机在连接 HC05 后会自动弹出“是否允许访问通讯录”之类的权限请求,可以直接拒绝,不影响蓝牙通信。如果手机提示“无法连接”,建议先在系统蓝牙设置中解除配对,然后在串口 APP 里重新搜索并配对连接,路径不同,成功率也不同。
4.2 联调过程的完整操作步骤
手机端配置好以后,真正联调时的操作方法如下:
- 打开手机系统蓝牙,搜索新设备。找到 HC05 后点击配对,输入密码 1234 或 0000。
- 配对成功后,打开蓝牙串口 APP,选择要连接的设备。
- APP 连接成功后,HC05 模块的 LED 会从快闪变为慢闪(有的模块是常亮),表示已经建立连接。
- UNO 板上电,代码开始运行,板载 LED 处于低电平熄灭状态。
- 在 APP 的发送框中输入
1,点击发送。如果一切正常,板载 LED 会点亮。 - 输入
0,LED 熄灭。
如果以上步骤都执行了但 LED 没反应,先别怀疑模块坏了,按下面顺序排查。
第一步:看 HC05 的 LED 是否处于慢闪或常亮状态。如果不是,说明蓝牙链路没通,回看配对步骤。
第二步:确认代码烧录成功。可以打开串口监视器(波特率 9600),在手机上发送1,如果串口监视器打印出了LED ON,说明代码和串口链路都没问题,问题出在手机 APP 或连接上。
第三步:确认手机 APP 发送的确实是字符1而不是别的。很多 APP 默认发送十六进制或带换行。如果发送的是0x31(即字符 '1' 的十六进制),那代码里的if (cmd == '1')判断也能匹配上,但如果发送的是文本01那就是两个字符,前面的 '0' 会被当成命令。这个需要仔细看 APP 的设置项。
4.3 实测过程中的现场记录
我自己测试的时候遇到过一个问题:手机发送1后 LED 亮了,但再发送0没反应。排查后发现,APP 里勾选了“发送新行”选项,导致每次发送的内容变成0\n,代码读取到字符0后本来应该执行熄灭,但紧接着读到的\n(ASCII 10)被代码忽略了,问题不在换行符本身,而在于我写代码时判断完0和1后没有把剩余缓冲区清空,导致下一次来的1被上一次的\n挤到了缓冲后面。
解决办法也很简单:在loop()末尾加while(Serial.available() > 0) { Serial.read(); },把缓冲区清空。这是很多新手写串口命令时容易忽略的细节。
4.4 扩展玩法:字符串指令解析
如果只控制一个 LED,用单字符1、0就够了。但如果后续要控制多个外设,比如控制三个 LED、一个蜂鸣器、一个电机,就需要自定义一套简单协议,下面这个格式很实用:
#LED1_ON #LED1_OFF #BUZZER_ON然后代码里可以用Serial.readStringUntil('\n')读取一整行,再做字符串匹配。这种方式更接近真实项目中的通讯协议设计,一句话解释就是:把手机当遥控器,把指令当消息,协议就是双方约定好的消息格式。
为什么推荐渐进式扩展?因为单字符指令实现简单,适合验证链路;字符串指令虽然稍微复杂,但为后续项目铺路是值得的,我自己的系列教程后面几篇就是基于这套字符串协议做继电器控制、温湿度上传、双机通信这些功能的。
5. 常见问题排查与调试实录
做蓝牙控制类的项目,最让新手头疼的就是各种“连接不上”“收不到数据”的问题。这一块我把踩过的坑和排查思路整理成一套速查表,按优先级排列。
出现问题的排查顺序是:先看模块供电和指示灯,再看手机配对状态,然后看 APP 连接状态,接着核对串口波特率,最后检查代码逻辑。顺序不能乱,否则低层问题没解决就排查上层,浪费时间还可能绕晕。
模块 LED 不闪烁:先量 VCC 和 GND 之间的电压,应为 5V 左右。如果用的是裸板,要注意供电不可超过 5V,否则可能损坏模块。如果电压正常但 LED 不亮,大概率模块本身坏了,换模块测试。
手机搜不到 HC05:检查模块是否处于 AT 模式。AT 模式下虽然也会广播蓝牙信号,但部分手机可能识别异常。另外确认模块有没有改过名字,如果之前设置过一个自定义名字,搜不到 HC-05 是正常的。用电脑的蓝牙再试一下,可以排除手机系统问题。
手机能配对但 APP 连不上:这种情况多半是 APP 不支持经典蓝牙 SPI RFCOMM。换个 APP 试试,或者检查 APP 权限设置,在 Android 上要确保授予位置权限和附近设备权限,否则系统会屏蔽蓝牙扫描和连接。还有,有些 APP 在系统设置配好设备后还要点一下 APP 界面的连接按钮。
发送指令没反应:先确认 HC05 的 LED 是慢闪还是常亮,如果是快闪说明模块不在通信模式。这个情况经常发生在刚配置完 AT 指令后,模块还在 AT 模式下,需要重新上电切换。其次确认 Arduino 串口波特率和 HC05 一致,最常见的就是 HC05 是 115200 而你代码里写 9600。
收到的数据是乱码:波特率不匹配。用串口监视器连接 Arduino,如果监视器输出乱码而手机发送的是英文,检查 Arduino 代码里的波特率和 HC05 通信模式波特率是否一致。另外还有一种情况是 HC05 被设置了奇偶校验位,AT+UART 指令里第二个 0 参数可以查一下当前配置。
代码烧录失败:在 HC05 占用了串口引脚的情况下,UNO 无法通过 USB 下载程序。拔掉 HC05 的 RX 线(注意是 HC05 接 UNO 引脚 0 的那根线),然后重新烧录。如果拔线不方便,用软串口方案彻底避免这个问题。
另外一个值得留意的小问题:HC05 模块的 STATE 引脚,我建议接一个 LED 做连接指示。原因很现实,项目做完后放一段时间,再回来玩可能忘了模块是否连上手机。用 STATE 引脚控制一个 LED,亮着就是连接成功,暗着就是断开,省去很多排查时间的浪费。
6. 基于 HC05 的下一步扩展思路
6.1 从单 LED 扩展到多路控制
当你掌握了 LED 控制,下一步自然就是扩展外设。我推荐先做隔离型继电器控制,因为继电器是电磁隔离的,可以控制高压设备,安全性和实用性都有了。四路继电器的接线思路和单 LED 完全一样,只是多了几个引脚和对应的数字引脚定义。
代码层面可以这样做:
char cmd; if (Serial.available()) { cmd = Serial.read(); switch(cmd) { case '1': digitalWrite(4, HIGH); break; case '2': digitalWrite(5, HIGH); break; case '3': digitalWrite(6, HIGH); break; case '4': digitalWrite(7, HIGH); break; case '5': digitalWrite(4, LOW); break; case '6': digitalWrite(5, LOW); break; case '7': digitalWrite(6, LOW); break; case '8': digitalWrite(7, LOW); break; } }这样手机端就可以用数字 + 一个开关动作来控制多路设备。但字符太多容易记混,更推荐用格式化的指令:R1ON、R2OFF这样的按字母加数字组合。解析时可以用strchr定位字母位置,也可以用sscanf提取数字,代码写起来更清晰也能少打字符。
6.2 状态反馈与上传
HC05 不只是单向接收指令,也可以把单片机采集到的数据发回手机。温度、湿度、传感器状态、开关状态,都能通过串口回传。这个功能在物联网场景里完全够用,做家用小设备不太需要完整的上云方案,手机直连反而更私密更可控。
回传数据的代码非常简单:
float temp = 26.5; BT.print("TEMP: "); BT.println(temp);手机上用能显示实时串口数据的 APP,就能以一定频率刷新看到传感器数据了。这一步实现了从“控制”到“数据交互”的跃迁,算是蓝牙项目的第二里程碑。
6.3 双机通信方案预告
HC05 支持主从模式,这意味着你可以用第二块 HC05 连接第一块 HC05,在串口层面打通两个单片机。这个功能可以做遥控小车——主控板接手机或主 HC05,从机板控制电机驱动。因为后续的系列文章(二)、(三)会专门展开讲双机通信,这里不展开,只提示几个关键点:
做主从配对时,两块 HC05 必须配对,即主模块的地址要指向从模块的地址。AT 指令里与地址相关的参数是绑定状态的。一旦配置错,两个模块会反复搜索却无法连接,常表现为 LED 一直快闪。
给个经验性的参数参考:主模块建议波特率 9600,从模块同样 9600,主模块 ROLE=1,从模块 ROLE=0。配对指令具体如下:
AT+ROLE=1 // 主模块 AT+CMODE=0 // 固定地址连接 AT+BIND=XXXX // 绑定从模块地址地址可以从从模块的AT+ADDR?查询获得。绑定后重新上电两个模块,能看到两者 LED 同时进入慢闪状态。这个我在后续双机通信专篇里会给出完整可复现的步骤和排障记录,先占个位。
6.4 关于供电稳定性的一点建议
做蓝牙项目供电问题往往最后才暴露。HC05 工作时峰值电流在 30 到 50mA 左右,UNO 板载稳压芯片能撑住,但如果你外接多个传感器或继电器,USB 口的 5V 供电就可能不够。继电器吸合瞬间的电流冲击很大,会让电压波动,表现为蓝牙频繁断开。
通常我会建议用外接 5V 2A 以上的适配器为 UNO 供电,或者直接用 9V 1A 适配器插 DC 接口。电源纹波大时,可以在 VCC 和 GND 之间并联一个 10V 1000uF 的电解电容和一个 104 的瓷片电容,低成本能过滤大部分杂波。新手看到别人加了电容不要觉得玄学,这确实是因为模块受电源干扰所迫。
另外如果电机和传感器较多,更科学的做法是把电源分成两路,数字电路一路,功率外设一路,共地但不共源。很多遥控小车跑到一半蓝牙断开,不是代码问题,而是电机把电源拉垮了,共地不共源是最直接的解决方案。
7. 实操心得总结
整套流程跑下来,我对 HC05 这个模块的脾气算是摸清了。它的稳定性足够好,前提是严格按照 AT 配置顺序来,并且在烧录和通信之间做好引脚管理。很多同学做完第一遍之后会困惑:为什么别人说 HC05 好用,我却连不上?我碰到过最多的原因其实就两个——波特率没对上,或者硬件接线搞反了。
从我个人的经验看,做这类项目的正确姿势是:先把链路最短化。所有的疑难杂症都靠“分段验证”来解决——模块本身用 AT 指令验证、手机连接用 LED 状态验证、代码执行用串口监视器验证。三段各自确认没问题后,合起来就一定通。不要试图一次解决所有问题,那只会让问题更难排查。
还有一个小经验:配置 HC05 时,把 AT 模式下的波特率统一设成 38400,通信模式设成 9600,是经过很多项目检验过的稳妥组合。虽然 HC05 也支持到 115200,但手机端很多串口 APP 对高波特率支持不完美,容易丢包。9600 完全够我传指令和回传传感器数据,选它纯粹是因为省心。
最后再多提一句板载 LED 这个设计。看起来只是控制了个最小外设,但它真正教会了你如何把一个云端概念落地到硬件。下一次做 WiFi 控制、做云端控制、做手机 APP 开发,你会发现底层的套路都是一模一样的——“解析指令、驱动外设、反馈状态”这条主线永远不变。把这个最小闭环吃透,后面的路会很顺。