☰
手机蓝牙控制Arduino Uno LED开关:App Inventor + HC-05实战教程
2026/10/5 4:38:43 网站建设 项目流程

说实话,Arduino 入门玩家十有八九都想过同一个问题:能不能用手机控制开发板?哪怕只是点个灯,成就感都完全不一样。我这些年带新手和给学生做演示,用得最多的方案就是App Inventor 2 + 蓝牙模块 + Arduino Uno 控制 LED 开关。这一套组合不贵、反馈直观、逻辑链路也短,走通一次就能同时搞清楚手机端图形化编程、串口通信和单片机 GPIO 控制三条线。

这篇文章我会把整个流程从头到尾写清楚,包括硬件怎么接、电平为什么要转换、Arduino 程序怎么写、手机 App 怎么搭、连不上时怎么排查。内容不强求你会写代码,只要能照着操作,基本一个下午就能跑通。有一点基础的朋友可以直接跳到后面的排错表,里面有不少是我自己踩过的坑。

1. 项目整体设计与方案选型

1.1 为什么选 App Inventor 2 而不是其他开发方式

手机端有很多种实现方式:原生 Android 用 Java/Kotlin 写,或者用 Flutter、React Native 这类跨平台框架,再或者直接买一套现成的蓝牙串口助手 App。但对一个想把精力放在硬件逻辑上的入门项目来说,这些方案都太重了。

App Inventor 2 是麻省理工推出的图形化编程平台,所有程序都用积木块拼出来,不用手写一行 Java。它最直接的优势是:你在浏览器里拖拽界面,拼好逻辑块,点击打包,手机上扫码就能装 APK。整个流程没有任何 SDK、IDE、证书之类的东西,完全绕开了“环境配置两小时,写代码五分钟”的尴尬。而且它自带蓝牙客户端组件,封装了经典蓝牙 SPP 协议的连接和数据收发,对控制 Arduino 这类串口设备来说非常顺手。

很多人担心图形化编程不够专业,但对我来说它适合两类场景:一类是完全零基础的人,想快速验证“手机控制硬件”这个想法;另一类是创客在教育场景里做快速原型 —— 先证明链路通,再考虑换成正式工程。我自己做教学演示时也用这个,因为学生能自己动手改界面、改按钮逻辑,成就感比看代码高得多。

1.2 硬件选型:HC-05、HC-06 还是 JDY-31

Arduino Uno 这块板子不用多说,5V 逻辑、引脚充裕、资料遍地,是新手期的标准答案。重点说说蓝牙模块。

市面上最常见的透传模块有三款:HC-05、HC-06 和 JDY-31。它们都基于蓝牙 3.0 的 SPP 协议,也就是传统蓝牙串口透传。区别主要在配置灵活性和价格上。

模块主从模式默认波特率特点
HC-05主从一体9600支持 AT 指令配置,经典课程标配,可改名称、改波特率、改配对密码
HC-06仅从机9600最便宜,但不可配置,适合固定从机场景,新手买它容易踩“不能改名字”的坑
JDY-31主从一体9600新款常用模块,供电范围宽,默认兼容 HC-05/06,性价比高

我首推 HC-05。原因很简单:它的 AT 指令模式让你能改波特率、改设备名称、改配对密码,这些在你排查问题时特别有用。比如模块被上一手改过 38400 波特率,而你的代码用 9600,怎么都连不上,这时候就得靠 AT 指令把它改回来。

JDY-31 我也用过,车规级贴片工艺,体积比 HC-05 小,很多新开发板上直接焊这种模块。它的 AT 指令格式和 HC-05 略有差异,但基本操作逻辑一样。如果你手头只有 JDY-31,完全可以直接参考这篇文章,接线和代码思路通用。

1.3 整个系统的控制链路

这套系统的数据流向是这样的:

手机 App 按钮 → 蓝牙 SPP 协议发送字符 → HC-05 模块接收 → 串口 TX 引脚输出 → Arduino 的 SoftwareSerial 接收 → 程序解析字符 → digitalWrite 控制 LED 引脚电平

每一段链路都不复杂,但正因为不复杂,出了问题才好排查。这也是我坚持用它做教学项目的原因:你永远知道数据卡在哪一环。手机发不出,那就是 App 或者连接问题;模块收到但板子没反应,那就是串口接线或波特率问题;引脚有信号但灯不亮,那就是 LED 电路问题。

值得注意的是,这一套走的是传统蓝牙 SPP,不是低功耗蓝牙 BLE。两者协议完全不同,HC-05 这种模块只能用传统蓝牙连接,而手机端 App Inventor 的蓝牙客户端组件默认也是经典蓝牙。如果你用的是 iPhone,事情会麻烦一些——iOS 对传统蓝牙 SPP 的开放度很低,App Inventor 的蓝牙组件只支持安卓。iPhone 想控制 Arduino,一般得换成 HM-10 这类 BLE 模块,玩法完全不同。这篇文章后面全部基于安卓手机。

2. 硬件接线与 Arduino 端程序编写

2.1 接线详解:别忽视电平转换

先看接线。HC-05 模块通常是 6 个引脚:VCC、GND、TXD、RXD、STATE、EN(有的标 KEY 或 CMD)。其中 VCC 接 Arduino 的 5V,GND 接 GND,TXD 接 Arduino 的接收引脚,RXD 接 Arduino 的发送引脚。

这里有一个很多教程都不会仔细讲的坑:HC-05 的 RXD 不能直接承受 Arduino 的 5V 逻辑高电平。也就是说,如果你把 Arduino 的 TX 直接连到 HC-05 的 RXD,长时间运行或某些模块个体差异下,很容易出现通信不稳定,甚至烧坏模块。HC-05 的逻辑电平是 3.3V,虽然板子上经常有稳压和转换电路,但很多便宜模块并不完整,稳妥起见必须做分压。

最简单的做法是串联电阻分压。我常用的接法是:Arduino 的引脚 11 先串一个 1kΩ 电阻,接到 HC-05 的 RXD;同时在 HC-05 的 RXD 和 GND 之间并一个 2kΩ 电阻。这样分压后的高点平大约在 3.3V 左右,既能被模块识别,又不会超压。

完整接线表如下:

HC-05 引脚Arduino 引脚说明
VCC5V模块供电
GNDGND共地
TXD10Arduino 的 SoftwareSerial 接收
RXD11经 1kΩ/2kΩ 分压后接入
STATE不接可选,用于检测连接状态
EN / KEY不接AT 指令模式时才用到

为什么不用 Arduino 的硬件串口 0/1 引脚来接?理论上可以,但那两个引脚同时连接着 USB 转串口芯片,烧录程序时会造成占用,而且一旦硬件串口被蓝牙占满,你就没法在 Arduino IDE 的串口监视器里看调试信息了。用 SoftwareSerial 库把蓝牙接在 10、11 上,USB 串口监视器就空出来做调试,两头不耽误。这个选择在后面排查问题时帮了大忙。

LED 部分我直接用 Arduino Uno 板载的 13 号引脚 LED,省去外接电路。如果你想外接高亮 LED,就接一个 220Ω 限流电阻到引脚 13,另一头接 LED 阳极,LED 阴极接 GND。

2.2 Arduino 端程序解析

Arduino 端的逻辑很简单:初始化 SoftwareSerial,波特率设成 9600,循环监听串口数据,收到字符1就点亮 LED,收到0就熄灭。

这是我的参考代码:

#include <SoftwareSerial.h> const int btRX = 10; const int btTX = 11; const int ledPin = 13; SoftwareSerial bt(btRX, btTX); void handleCommand(char c) { if (c == '1') { digitalWrite(ledPin, HIGH); bt.println("LED ON"); Serial.println("LED ON"); } else if (c == '0') { digitalWrite(ledPin, LOW); bt.println("LED OFF"); Serial.println("LED OFF"); } } void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); Serial.begin(9600); bt.begin(9600); bt.println("Bluetooth Ready"); Serial.println("Serial Ready"); } void loop() { if (bt.available()) { char c = bt.read(); Serial.print("BT -> "); Serial.println(c); handleCommand(c); } if (Serial.available()) { char c = Serial.read(); bt.write(c); handleCommand(c); } }

代码里我特意做了双路监听:不仅监听蓝牙串口,也监听 USB 硬件串口。这样即使手机还没连上,你也完全可以通过 Arduino IDE 的串口监视器直接发送1和0来测试 LED 是否工作。先把这条链路确认通了,再去查蓝牙,能少排查一半问题。

SoftwareSerial bt(btRX, btTX)这一行的引脚顺序有讲究:第一个参数是 RX,接 HC-05 的 TXD;第二个参数是 TX,接 HC-05 的 RXD。新手最容易在这两根线上搞反,记住“交叉对接”这个原则:模块的发送接板子的接收,模块的接收接板子的发送。

波特率这里默认 9600,这也是 HC-05 出厂默认的数据模式波特率。如果你用串口监视器测试时显示乱码,或者手机连接后发送指令没反应,大概率是波特率不匹配。后面我会讲怎么用 AT 指令改回 9600。

2.3 烧录与第一次验证

把代码复制到 Arduino IDE,选择 Board 为 Arduino Uno,选择正确的 COM 口,点击上传。上传过程中 HC-05 模块不需要断开,因为 10、11 引脚和 USB 下载互不干扰。

烧录完成后,打开串口监视器,波特率选 9600,在输入框里发送1。你如果看到 13 号引脚的黄色 LED 亮起来,串口监视器打印出LED ON,那硬件和控制逻辑就已经没有问题了。再发送0,灯灭。到这个阶段,Arduino 这一侧就完全就绪,剩下的事情只是“把手机接进来”。

有个小细节:串口监视器如果发送的是带换行的字符串1\n,程序只处理第一个字符1,所以没问题。但如果你不小心把输入法切到中文,发送出去的是全角字符,Arduino 收到的字节就不一样,灯自然没反应。这种低级错误我在现场见过很多次,排查时先看一眼你发的是什么字符。

3. App Inventor 2 手机端应用开发

3.1 新建项目与界面设计

打开 App Inventor 2 网站,用 Google 账号登录,新建一个项目,名称随便起,我用的是BluetoothLED。

进入 Designer(设计界面)后,先拖一个“水平布局”或者“垂直布局”组件,把所有控件都放进去,这样界面上电后排列会比较整齐。我通常放这几个控件:

  • ListPicker:用于选择要连接的蓝牙设备。它本质上是一个下拉列表,点一下弹出所有可连接的蓝牙设备名。
  • Label:显示当前连接状态,比如“未连接”“连接成功”“连接失败”。
  • 两个普通按钮:一个“打开 LED”,一个“关闭 LED”。
  • 一个“断开连接”按钮,方便测试时反复重连。

非可视组件区拖入一个BluetoothClient(蓝牙客户端)。这个组件不会在界面上显示,但它负责所有底层的蓝牙连接和数据收发。把它的Enabled属性先设为false,等用户点击选择设备时再动态打开,这样 App 启动时不会立刻请求蓝牙权限。

界面不用做得花哨,但要保证按钮够大、标签状态一眼能看清。实际操作时你经常要反复点击测试,按钮太小很折磨人。

3.2 积木块编程:连接逻辑与发送指令

切到 Blocks(积木)界面,核心逻辑分三块:蓝牙列表、连接事件、按钮发送。

先处理蓝牙选择列表。ListPicker有一个BeforePicking事件,发生在用户点击下拉列表但还没选择之前。这个事件里做两件事:如果蓝牙客户端没有启用,就把Enabled设为true;然后调用蓝牙客户端的连接地址和名称方法,把返回值塞进 ListPicker 的Elements属性,这样点击列表时就能看到所有蓝牙设备的名称。

接着是AfterPicking事件,也就是用户在列表里选中了某个设备。这里先调用蓝牙客户端的连接地址方法,参数就是ListPicker.Selection(选中的字符串里包含设备地址和名称)。连接是一个异步过程,调用完方法后,程序会立即往下走,所以最好的做法是:先弹出“正在连接”,然后调用连接方法,最后用一个判断判断蓝牙客户端是否已连接,再把状态更新到标签上。这样用户能明确看到连接结果。

按钮发送逻辑更简单。打开 LED 按钮的Click事件,调用蓝牙客户端的发送文本方法,参数填字符1。关闭 LED 按钮就填0。这里要注意:发送文本传的是字符串,Arduino 端按字节读取,字符串"1"在传输时就是 ASCII 字符1,十六进制是0x31,而 Arduino 读取后拿到的char类型也是'1',两边完全对得上。

如果连接失败,可能是设备地址格式问题。App Inventor 的连接地址方法要求传入的是 MAC 地址字符串,但在实际使用中,ListPicker.Selection返回的往往是“名称\n地址”这样的组合,有些版本直接选中后就能用,有些则需要你自己从返回的字符串里截取地址。我的习惯是在AfterPicking事件里先用一个Label打印出ListPicker.Selection,看清楚返回值里到底包含了什么,再做处理。这也是图形化编程调试的常用手段——暂时把中间结果显示到界面上。

断开连接按钮,就是调用蓝牙客户端的断开连接方法,顺带把状态标签改成“已断开”。

3.3 打包安装与运行时权限

App 写完,点右上角的“Build”菜单,选择 Android App,App Inventor 会弹出两种方式:扫码直接下载 APK 到手机,或者生成下载链接。我一般用扫码,同一个局域网下速度快,而且不需要数据线。

安装时安卓系统会弹权限提示。不同安卓版本对蓝牙的权限要求差别很大:安卓 6 到 11 之间,搜索蓝牙设备通常需要“位置”权限;安卓 12 以上则收紧成“附近设备”权限。无论哪种,在 App 里第一次点击选择蓝牙设备前,系统都会弹窗询问,点允许就行。如果点了拒绝,蓝牙列表一般是空的。

如果你打包后安装到手机上,点击按钮提示“该组件未启用”或者“连接失败”,先检查系统设置里有没有把 App 的定位权限或者附近设备权限打开。这个环节的坑和我前面说的分压电阻一样,都是“教程没提,但实际必踩”。

4. 联调、排错与扩展玩法

4.1 首次联调:从电脑到手机的完整验证

硬件和 App 都准备好了,关键的时刻到:把两者连起来。

我建议按照“先电脑后手机”的节奏走,不要一上来就急着在 App 上点连接。先在电脑上打开串口监视器,发送1和0确认 LED 控制逻辑正常,这步我在前面已经说过。确认没问题后,给 HC-05 模块上电,观察指示灯:正常数据模式下,HC-05 的指示灯应该是每 2 秒慢闪一次,这说明模块处于可配对状态。

手机打开蓝牙,进入 App,点击“选择蓝牙设备”按钮。列表里应该出现HC-05这个名字。如果之前配对过,可能需要先在手机系统蓝牙设置里做一次配对,配对密码通常是1234或0000。App 里选择设备,连接,标签上显示“连接成功”,这时候模块的指示灯一般会从慢闪变成常亮,状态非常直观。

指示灯常亮后,点一下“打开 LED”按钮。正常情况下,Arduino 板载 LED 随即亮起。如果没亮,回到串口监视器看有没有收到BT -> 1这条信息。收到了说明数据链路是通的,问题在 LED 电路或引脚配置;没收到说明蓝牙接管了串口但数据没传到 Arduino,检查 SoftwareSerial 的 RX/TX 是否有接反。

4.2 高频问题速查表与避坑技巧

以下是我在实际操作中遇到过的各种问题,整理成一张速查表:

现象可能原因处理方法
手机搜不到 HC-05模块还停留在 AT 指令模式断开电源重新上电,确认进入数据模式(慢闪),不要按着按键上电
搜到但连接不上配对密码错误或模块已被其他设备占用在手机系统蓝牙设置里删除该设备,重新配对;确认 PC 或平板没连着同一模块
连接后很快断开供电不足不要用电脑 USB 口供电,换 5V/1A 充电器独立给 Arduino 供电
列表打开但空白蓝牙权限未开启到系统设置里给 App 开位置权限或附近设备权限
发送指令没反应波特率不匹配串口监视器用 9600,确认模块数据模式波特率是 9600,不对就用 AT 指令改回
Arduino 串口出现乱码模块电平不稳或共地不良确认 GND 线牢固,RXD 分压电阻焊接可靠
引脚 13 灯不亮指令字符不匹配用串口监视器直接发1测试,排除手机端问题

在这张表里,我想特别强调“供电不足”这个坑。HC-05 本身功耗不高,但如果 Arduino 同时接了蓝牙、LED 和其他传感器,再用一根质量很差的 USB 线从电脑取电,很容易出现模块反复断连的情况。我遇到过一次,现象非常诡异:灯能闪,连接能成功,但点按钮后模块立刻掉线。排查到最后发现是 USB 线压降太大,Arduino 的 5V 实际只有 4.3V。换了一根粗一点的线之后一切正常。

关于 AT 指令,如果你的模块被别人改过波特率,或者你想改设备名称方便识别,需要进 AT 模式操作。方法是:按住 HC-05 板子上的小按键不放,再给模块通电,这时候指示灯会变成约 2 秒闪一次,表示进入 AT 模式。用 USB 转 TTL 工具连接模块,电脑串口工具选 38400 波特率发送AT,返回OK就说明成功。常用指令有这几个:

  • AT:测试是否进入 AT 模式,返回OK
  • AT+NAME=MyBT:改设备名称
  • AT+UART=9600,0,0:改波特率为 9600
  • AT+ROLE=0:设为从机模式
  • AT+PSWD=1234:改配对密码

这里有一个版本差异要注意:部分 HC-05 模块的 AT 波特率是 38400,但也有少数模块出厂就是 9600。如果你用 38400 发送AT没反应,就换个波特率再试。这也是我为什么推荐先查数据手册或者卖家页面确认一下模块型号。

4.3 扩展方向:从点灯到更多玩法

一个 LED 开关项目跑通之后,你能往上加的东西其实非常多。我自己的经验是,这个项目最大的价值不是“点灯”本身,而是建立了一条可靠的双向数据通道。只要通道在,后面控制什么都是同一个套路。

最简单的扩展是 PWM 调光。Arduino 的引脚 13 不支持 PWM,但你只要把 LED 换到 9、10、11 这类带~标记的引脚上,然后把 App 改成滑块组件,发送 0 到 255 之间的数字,Arduino 端用analogWrite(ledPin, value)输出,就能实现手机端滑动调亮度。硬件逻辑完全不变,只是把字符处理从开关变成数值映射。

再往上走,可以接 DHT11 温湿度传感器,把数据通过蓝牙回传给手机,App 界面上实时显示温度和湿度。这时候你会开始用BluetoothClient的接收文本功能,也就是手机监听串口返回的数据。这一过程会涉及数据解析、字符串分割、界面刷新,难度上一个档次,但非常值得做。

如果你想控制高电压设备,比如家里的台灯,那就把 LED 换成继电器模块,用引脚电平控制继电器通断。注意这时候已经进入强电范畴,操作必须断电进行,对新手来说最好先拿 12V 的 LED 灯带做过渡测试。

还有一个方向是蓝牙小车。把 Arduino 装在底盘上,左右两个电机通过驱动板接到引脚,App 端做几个方向键按钮,发送F、B、L、R、S这些字符。Arduino 收到后控制 L298N 或 L9110S 驱动板输出。硬件链路依然是蓝牙串口,只是数据处理从单字节变成了简单指令集。很多学校机器人社团的入门作品就是这么来的。

如果你用的是 iPhone,又想走蓝牙控制这条路,那需要把 HC-05 换成 HM-10 这类 BLE 模块,App 端也得换成基于低功耗蓝牙的扩展组件或者用其他开发平台。BLE 和传统蓝牙协议不兼容,这一点千万记住,选型的时候别买错。

最后再分享一个小技巧,也是我每次带项目都会强调的操作习惯:调试阶段不要急着把所有线焊死。HC-05 和 Arduino 之间用杜邦线连接,分压电阻放在面包板上,这样每次测试完都可以随时改线、换模块。等你把整套逻辑跑通并且确认稳定之后,再考虑用洞洞板或者 PCB 把这套电路固定下来。先面包板、后焊板,能让你少走很多弯路。

这个项目的上限其实比你想象得高。我见过有人在这个基础上加了一个语音识别模块,手机不用碰按钮,说一句“开灯”就亮;也见过有人把蓝牙模块换成 Wi-Fi 模块,直接改造成了物联网远程控制。但不管后面怎么发展,串口协议、电平转换、数据解析这些基本功,都是从“App Inventor 2 通过蓝牙控制 Arduino Uno LED 开关”这个最简单的项目里练出来的。你先把它跑通,剩下的路就会越走越顺。

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

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

立即咨询