1. 项目概述与核心价值搞嵌入式开发或者物联网项目的朋友估计都遇到过类似的需求想做个能远程更新信息的显示终端比如放在实验室门口的活动通知牌或者家里的智能留言板。传统的有线方式布线麻烦用Wi-Fi呢对于简单的单向信息推送又有点“杀鸡用牛刀”配置网络也复杂。这时候蓝牙特别是经典的HC-05这类模块它的优势就出来了——配对即用功耗低成本也便宜简直是短距离无线透传的“万金油”。我这个项目就是一个基于Arduino和HC-05蓝牙模块的无线电子公告牌。核心思路特别直接用你的安卓手机装个简单的APP通过蓝牙把想显示的文字发送给ArduinoArduino收到后驱动一块16x2的LCD液晶屏把内容展示出来。别看它简单这里面包裹了嵌入式开发里几个非常基础又关键的技术点串口通信的数据收发与解析、I2C总线驱动LCD以节省单片机IO口、以及如何设计一个稳定可靠的数据传输协议。对于刚接触Arduino或者想理解物联网设备“端到端”数据流的朋友来说这是一个绝佳的练手项目。你不仅能得到一个可以实际使用的无线显示工具更能把串口通信、外设驱动这些概念从理论落到实实在在的代码和电路上。整个系统的骨架很清晰Android手机发送端 - 蓝牙无线链路 - HC-05模块接收/转发 - Arduino UNO主控与解析 - I2C接口 - LCD显示屏显示终端。下面我就把从硬件选型、电路连接、代码编写到手机端配置的完整过程以及我踩过的坑和总结的经验毫无保留地拆解给你看。2. 硬件选型、电路设计与核心原理解析2.1 硬件清单与选型考量做项目第一步永远是备料。这个系统对硬件要求不高但每一样的选择都有它的道理主控核心Arduino UNO 或 Nano为什么是Arduino对于快速原型开发Arduino的生态丰富的库、简单的IDE和稳定性是首选。UNO接口丰富适合在面包板上搭建测试Nano体积小巧更适合最终成品嵌入。核心参数使用ATmega328P微控制器有14个数字IO和6个模拟输入运行频率16MHz完全能满足本项目需求。其内置的UART通用异步收发传输器是与蓝牙模块通信的硬件基础。显示单元16x2 LCD 液晶屏 I2C 适配板为什么用16x2 LCD16字符x2行是最常见、性价比最高的显示方案足够显示简短的通知、标语或两行信息。为什么一定要加I2C适配板这是本项目的一个关键优化点。传统的1602 LCD需要连接7个以上的数据和控制线RS, RW, E, D4-D7非常占用IO口且接线混乱。I2C适配板通过PCF8574T等芯片将并行接口转换为I2C总线仅需2根信号线SDA, SCL和2根电源线即可驱动极大简化了电路。注意不同厂商的I2C适配板其默认I2C设备地址可能不同常见的是0x27或0x3F后续编程需要对应。无线模块HC-05 蓝牙串口模块为什么是HC-05它是经典的蓝牙2.0EDR模块支持主从一体模式但本项目通常将其设置为从机Slave模式等待手机连接。其本质是一个串口透传模块即把从蓝牙无线收到的数据原封不动地通过TTL串口发送给Arduino反之亦然。这让我们无需处理复杂的蓝牙协议栈只需像操作串口一样编程即可。关键引脚VCC(5V),GND,TXD(发送端),RXD(接收端)。这里有一个极易接错的点模块的TXD要接Arduino的RX(0号引脚)模块的RXD要接Arduino的TX(1号引脚)。因为“发送”总是对应对方的“接收”。其他面包板、杜邦线公对公、公对母、USB数据线为Arduino供电并上传程序、安卓智能手机一部。2.2 电路连接详解与原理图解读正确的连接是成功的一半。我们按照“电源 - 显示 - 通信”的顺序来搭建第一步建立公共电源轨在面包板上用两根长排针建立一条正极5V线和一条负极GND线。将Arduino UNO的5V引脚连接到面包板的正极线GND引脚连接到负极线。这样面包板上就有了稳定的5V电源可供其他模块取用。第二步连接LCD与I2C适配板通常LCD屏已经焊好在I2C适配板上了。我们只需连接适配板的四个引脚GND- 面包板负极线。VCC- 面包板正极线。SDA- Arduino UNO的A4引脚。注意在Arduino上A4引脚除了模拟输入功能也是硬件I2C总线的数据线SDA。SCL- Arduino UNO的A5引脚。同样A5是硬件I2C的时钟线SCL。提示I2C总线是共享总线理论上可以挂载多个设备通过地址区分。这里我们只接了一个LCD。第三步连接HC-05蓝牙模块这是通信的关键务必仔细VCC- 面包板正极线5V。HC-05工作电压通常是3.3V-5V接5V稳定。GND- 面包板负极线。TXD- Arduino UNO的RX引脚即数字引脚0。模块发送Arduino接收。RXD- Arduino UNO的TX引脚即数字引脚1。模块接收Arduino发送。重要注意事项在给Arduino上传程序时必须暂时断开HC-05模块与RX/TX引脚的连接或者至少断开TXD-RX这根线。因为Arduino的RX/TX引脚也用于通过USB与电脑通信上传程序时两者会产生冲突导致上传失败。这是一个非常常见的坑。连接示意图文字描述Arduino UNO 面包板及其他模块 --------- ------------------ | | | | | 5V |-------------------| 正极电源线 |-----| I2C适配板 VCC | | | | |-----| HC-05 VCC | | GND |-------------------| 负极电源线 |-----| I2C适配板 GND | | | | |-----| HC-05 GND | | A4 |-------------------| I2C适配板 SDA | | A5 |-------------------| I2C适配板 SCL | | RX |-------------------| HC-05 TXD | | TX |-------------------| HC-05 RXD | | | | | --------- ------------------2.3 系统工作原理深度剖析硬件连接好后我们来理解数据是如何流动的用户输入你在安卓APP的输入框里打字比如第一行输入“Welcome!”第二行输入“Meeting 3PM”。协议封装APP不会直接发送“Welcome!Meeting 3PM”这么简单。为了防止两行信息在接收端混淆需要定义一个简单的应用层协议。一个常见且有效的做法是用特殊字符分隔两行内容并用另一个特殊字符标记消息结束。例如发送字符串Welcome!,Meeting 3PM*。这里逗号,分隔第一行和第二行星号*作为结束符。蓝牙传输APP通过手机蓝牙将封装好的字符串发送到已配对的HC-05模块。串口透传HC-05模块收到蓝牙数据后其内部的芯片不做任何处理直接通过TTL串口将原始的字节流发送到Arduino的RX引脚。Arduino解析Arduino的loop()函数中通过Serial.available()不断检查串口是否有数据。一旦检测到便使用Serial.read()逐个字节读取。代码逻辑会持续拼接这些字节直到遇到约定的结束符*。然后它再根据分隔符,将完整的字符串拆解成messageStatic第一行和messageToScroll第二行。显示驱动Arduino调用LiquidCrystal_I2C库的函数将解析出的字符串发送到I2C总线。I2C适配板上的芯片将I2C命令转换为LCD能理解的并行信号最终控制液晶分子偏转显示出文字。整个过程Arduino代码的核心任务就是可靠地接收数据、准确地解析协议、正确地驱动显示。蓝牙和I2C的底层通信细节都有成熟的硬件和库函数帮我们处理这正是Arduino生态高效的地方。3. 软件实现从基础显示到无线通信3.1 开发环境准备与核心库安装安装Arduino IDE从Arduino官网下载并安装最新版IDE。这是我们的编程和烧录工具。安装必要的库本项目最关键的一个库是用于驱动I2C LCD的LiquidCrystal_I2C。打开Arduino IDE点击“工具” - “管理库...”。在库管理器中搜索“LiquidCrystal I2C”通常会找到由Frank de Brabander开发的版本。点击安装。这个库封装了通过I2C控制LCD的所有复杂操作我们只需要调用简单的print(),setCursor(),clear()等函数即可。3.2 三步代码演进从点亮屏幕到无线控制我建议分三步来编写和测试代码这符合从易到难的调试逻辑能帮你清晰地定位问题。第一步基础显示测试 - 确认LCD与I2C地址这一步的目的是排除硬件连接和地址错误。上传以下代码如果LCD亮起并显示“Hello World”说明LCD和I2C连接正确。#include Wire.h #include LiquidCrystal_I2C.h // 初始化LCD对象参数I2C地址列数行数 // 关键点地址必须是0x27或0x3F根据你的模块二选一。如果都不对需要运行I2C扫描程序查找。 LiquidCrystal_I2C lcd(0x27, 16, 2); void setup() { lcd.init(); // 初始化LCD lcd.backlight(); // 打开背光 // 在第一行第0列开始打印 lcd.setCursor(0, 0); lcd.print(Hello, Line 1!); // 在第二行第0列开始打印 lcd.setCursor(0, 1); lcd.print(Hello, Line 2!); } void loop() { // 空循环静态显示 }实操心得如果屏幕不亮或显示乱码首先检查接线然后尝试更换I2C地址0x3F。可以使用专门的I2C Scanner示例代码在IDE的示例中来扫描总线上设备的准确地址。第二步实现滚动显示 - 增加动态效果静态显示有点枯燥我们让第二行文字滚动起来这在实际公告牌中很常用。#include Wire.h #include LiquidCrystal_I2C.h LiquidCrystal_I2C lcd(0x27, 16, 2); // 根据实际情况修改地址 // 定义LCD的尺寸 int lcdColumns 16; int lcdRows 2; // 定义要显示的文字 String staticMessage DOFBOT.COM; String scrollMessage Wireless Notice Board Project is Running...; // 自定义滚动显示函数 void scrollText(int row, String message, int delayTime, int totalColumns) { // 在消息前添加空格使其从屏幕外滚入 for (int i 0; i totalColumns; i) { message message; } // 在消息后添加空格使其完全滚出屏幕 message message ; // 实现滚动动画 for (int pos 0; pos message.length(); pos) { lcd.setCursor(0, row); // 从消息字符串中截取当前应显示的一屏内容 lcd.print(message.substring(pos, pos totalColumns)); delay(delayTime); // 延迟时间控制滚动速度 } } void setup() { lcd.init(); lcd.backlight(); } void loop() { // 清屏可选根据效果决定是否每次循环清屏 // lcd.clear(); // 显示静态信息第一行 lcd.setCursor(0, 0); lcd.print(staticMessage); // 显示滚动信息第二行 scrollText(1, scrollMessage, 300, lcdColumns); // 300ms延迟速度适中 }这段代码的关键在于scrollText函数它通过不断改变显示字符串的起始位置来模拟滚动效果。delayTime参数很重要太小会滚得太快看不清太大则显得卡顿需要根据实际观感调整。第三步集成蓝牙通信与协议解析 - 实现无线控制这是最终的核心代码。它结合了串口数据接收和上述显示功能。#include Wire.h #include LiquidCrystal_I2C.h // 定义LCD int lcdColumns 16; int lcdRows 2; LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows); // 修改为你的地址 // 全局变量用于处理接收的数据 char incomingChar; // 存储每次从串口读取的单个字符 String receivedString ; // 用于拼接完整的接收字符串 String line1Msg ; // 解析后的第一行信息 String line2Msg ; // 解析后的第二行信息 // 滚动显示函数同上此处省略以节省篇幅实际代码中需保留 void scrollText(int row, String message, int delayTime, int totalColumns) { // ... (函数体与第二步完全相同) } void setup() { // 初始化LCD lcd.init(); lcd.backlight(); lcd.clear(); lcd.setCursor(0, 0); lcd.print(System Ready!); delay(1000); lcd.clear(); // 初始化串口通信波特率必须与HC-05模块匹配默认通常是9600 Serial.begin(9600); // 可以在LCD上显示等待连接状态 lcd.setCursor(0,0); lcd.print(BT:Waiting...); } void loop() { // 检查串口是否有数据到达 if (Serial.available() 0) { incomingChar Serial.read(); // 读取一个字节 // 如果收到的不是结束符就拼接到字符串中 if (incomingChar ! *) { receivedString incomingChar; } // 如果收到结束符*说明一条完整消息接收完毕 else { // 可选将接收到的原始数据回传到串口监视器方便调试 // Serial.println(Received: receivedString); // 解析协议假设格式为 第一行内容,第二行内容* int separatorIndex receivedString.indexOf(,); // 查找分隔符位置 if (separatorIndex ! -1) { // 成功找到分隔符进行解析 line1Msg receivedString.substring(0, separatorIndex); line2Msg receivedString.substring(separatorIndex 1); // 清屏并显示新内容 lcd.clear(); lcd.setCursor(0, 0); lcd.print(line1Msg); lcd.setCursor(0, 1); // 如果第二行信息过长则启用滚动显示否则静态显示 if (line2Msg.length() lcdColumns) { scrollText(1, line2Msg, 250, lcdColumns); } else { lcd.print(line2Msg); } // 可选在串口监视器打印解析结果用于验证 // Serial.print(Line1: ); // Serial.println(line1Msg); // Serial.print(Line2: ); // Serial.println(line2Msg); } else { // 没有找到分隔符可能协议错误或消息只有一行 lcd.clear(); lcd.setCursor(0,0); lcd.print(Msg Error:); lcd.setCursor(0,1); lcd.print(receivedString); } // 处理完毕清空接收字符串准备接收下一条消息 receivedString ; } } // 如果第二行信息正在滚动需要维持滚动循环当非滚动时此部分不执行 // 注意简单的loop结构下滚动显示会阻塞loop直到滚动完成。 // 更高级的做法是使用状态机和非阻塞延时但为了初学者理解此处使用阻塞式。 }这段代码是项目的核心。它定义了一个简单的协议以逗号,分隔两行文本以星号*作为消息结束标志。loop()函数不断监听串口拼接字符遇到*后触发解析和显示。务必注意上传此代码前记得断开或拔掉HC-05与ArduinoRX引脚的连接上传成功后再接回去。3.3 安卓端配置与通信测试Arduino端准备好后我们需要一个发送端。蓝牙配对给整个系统上电通过USB线或外部电源。打开手机蓝牙设置搜索新设备。你应该能找到一个名为“HC-05”的设备默认名称。点击配对输入配对码通常是1234或0000。配对成功后HC-05模块上的LED指示灯应从快闪变为慢闪或常亮取决于模式。选择发送工具方案一最简单使用现成的“蓝牙串口”APP。在应用商店搜索“蓝牙串口”会有很多选择如“Serial Bluetooth Terminal”。安装后打开APP连接“HC-05”设备然后在发送框输入第一行文字,第二行文字*点击发送。LCD屏幕应立即更新。方案二自定义APP如果你想完全控制可以用MIT App Inventor或Android Studio开发一个简易APP上面放两个输入框和一个发送按钮按钮的逻辑就是将两个输入框的内容用逗号连接加上星号然后通过蓝牙串口发送。这对于学习完整的物联网应用开发链路更有帮助。4. 系统优化、调试与深度问题排查项目基本跑通后我们可以让它更稳定、更实用。这里分享一些进阶优化和必然遇到的坑。4.1 稳定性与功能优化建议增加连接状态指示可以在LCD第一行固定显示蓝牙连接状态如“BT:Connected”或“BT:Waiting”。这需要Arduino代码能检测串口链路层的状态对于HC-05简单的办法是定时发送AT指令查询但会复杂些。一个取巧的办法是在手机APP端每次连接成功后发送一个特定字符串如“CONNECTED*”Arduino收到后更新状态显示。实现非阻塞式滚动当前代码中scrollText函数里的delay()会阻塞整个loop()。这意味着在文字滚动期间系统无法接收新的蓝牙信息。对于需要实时更新的公告牌这是不行的。优化方法是使用状态机和millis()函数进行非阻塞延时。核心思想是记录每次滚动步骤的时间戳时间到了才移动一格并刷新显示这样loop()函数在等待期间可以快速循环处理其他任务如检查串口。设计更健壮的通信协议添加帧头/帧尾当前协议“A,B*”如果文本本身包含逗号或星号就会乱套。可以定义更复杂的协议如“$START,A,B,END*”。添加校验和在消息末尾加入一个简单的校验和如所有字符ASCII码之和取低字节Arduino收到后计算校验和比对不一致则要求重发或丢弃提高抗干扰能力。增加指令集除了显示文本还可以定义其他指令如“CLEAR*”清屏“BACKLIGHT,OFF*”关闭背光等让系统更可控。电源优化如果打算长期独立运行可以考虑用9V电池配合降压模块为Arduino供电或者使用手机充电宝。注意HC-05模块在通信时电流可能达到几十毫安确保电源能带动。4.2 常见问题与故障排查实录即使按照步骤操作你也可能会遇到以下问题。这里是我的“踩坑”记录问题现象可能原因排查步骤与解决方案LCD屏幕无任何显示1. 电源未接通或接反。2. I2C地址错误。3. 对比度问题虽罕见但1602需调节。1. 用万用表检查LCD的VCC和GND间是否有5V电压。2. 运行I2C Scanner示例代码在串口监视器查看扫描到的地址并修改代码。3. 找到LCD模块上的电位器如果有用小螺丝刀缓慢旋转调节对比度。LCD显示乱码或黑色方块1. 初始化失败或通信不稳定。2. 代码中行列参数与实物不符。1. 检查lcd.init()是否执行I2C线SDA, SCL连接是否松动。2. 确认LiquidCrystal_I2C lcd(0x27, 16, 2)中的16和2与你的屏幕规格一致。蓝牙配对失败1. HC-05未进入配对模式。2. 配对码错误。3. 手机蓝牙与模块不兼容极少见。1. 确保模块已通电且指示灯处于快闪状态配对模式。有些模块有按键需长按进入配对模式。2. 尝试1234或0000。3. 换一部手机试试。手机APP连接成功但发送数据无反应1.最常见接线错误特别是TXD/RXD交叉。2. 波特率不匹配。3. 上传代码时未断开RX线导致程序未正确烧录。4. 代码中串口初始化波特率与HC-05不匹配。1.重点检查HC-05的TXD是否接Arduino的RX(0)RXD是否接TX(1)。2. 确认APP和Arduino代码中的串口波特率均为9600HC-05默认。可在APP设置中查看或修改。3.务必养成习惯上传代码前断开HC-05与ArduinoRX引脚的连接。4. 检查Serial.begin(9600);语句。只能接收部分字符或显示错乱1. 串口接收缓冲区处理不当数据丢失。2. 协议解析逻辑有bug比如字符串拼接溢出或分隔符处理错误。3. 发送的数据包含中文等非ASCII字符需特殊处理。1. 在代码中增加调试输出将receivedString打印到串口监视器连接电脑USB看原始数据是否完整。2. 仔细检查if (incomingChar ! *)和separatorIndex的逻辑。确保receivedString在解析后被清空。3. 对于简单项目建议手机APP和Arduino端都只使用英文和标准符号。系统运行一段时间后死机或无响应1. 电源功率不足带载后电压下降。2. 代码中存在内存泄漏如String对象在循环中不断拼接未释放。3. 无线干扰。1. 使用稳压电源或容量更大的电池供电观察现象是否改善。2. 优化代码避免在loop()中频繁创建大的String对象。对于固定字符串使用字符数组(char array)可能更稳定。3. 远离大功率无线设备如路由器。4.3 项目扩展思路这个基础框架可以玩出很多花样显示升级将16x2 LCD换成20x4 LCD甚至换成OLED显示屏可以显示更多内容或更酷炫的图形。无线升级将HC-05换成ESP8266或ESP32模块系统就具备了Wi-Fi功能可以通过局域网甚至互联网远程更新公告实现真正的“物联网公告牌”。功能升级结合传感器比如温湿度传感器DHT11让公告牌自动显示环境信息。或者加上RTC实时时钟模块显示精确时间。交互升级在Arduino上连接一个按键或红外接收头实现手动翻页或切换显示模式。这个基于Arduino和蓝牙的无线公告牌项目虽然硬件简单但它完整地走通了一个物联网终端的数据采集手机输入、无线传输蓝牙、数据处理Arduino解析和信息呈现LCD显示的闭环。最重要的是它让你亲手触摸到了串口通信、协议设计、外设驱动这些嵌入式开发的核心概念。希望你在实现它的过程中不仅收获了一个有趣的小工具更能理解其背后每一个环节“为什么”要这么做。遇到问题别怕对照上面的排查表一步步来硬件项目的乐趣一半就在这解决问题的过程里。
基于Arduino与HC-05蓝牙模块的无线电子公告牌设计与实现
1. 项目概述与核心价值搞嵌入式开发或者物联网项目的朋友估计都遇到过类似的需求想做个能远程更新信息的显示终端比如放在实验室门口的活动通知牌或者家里的智能留言板。传统的有线方式布线麻烦用Wi-Fi呢对于简单的单向信息推送又有点“杀鸡用牛刀”配置网络也复杂。这时候蓝牙特别是经典的HC-05这类模块它的优势就出来了——配对即用功耗低成本也便宜简直是短距离无线透传的“万金油”。我这个项目就是一个基于Arduino和HC-05蓝牙模块的无线电子公告牌。核心思路特别直接用你的安卓手机装个简单的APP通过蓝牙把想显示的文字发送给ArduinoArduino收到后驱动一块16x2的LCD液晶屏把内容展示出来。别看它简单这里面包裹了嵌入式开发里几个非常基础又关键的技术点串口通信的数据收发与解析、I2C总线驱动LCD以节省单片机IO口、以及如何设计一个稳定可靠的数据传输协议。对于刚接触Arduino或者想理解物联网设备“端到端”数据流的朋友来说这是一个绝佳的练手项目。你不仅能得到一个可以实际使用的无线显示工具更能把串口通信、外设驱动这些概念从理论落到实实在在的代码和电路上。整个系统的骨架很清晰Android手机发送端 - 蓝牙无线链路 - HC-05模块接收/转发 - Arduino UNO主控与解析 - I2C接口 - LCD显示屏显示终端。下面我就把从硬件选型、电路连接、代码编写到手机端配置的完整过程以及我踩过的坑和总结的经验毫无保留地拆解给你看。2. 硬件选型、电路设计与核心原理解析2.1 硬件清单与选型考量做项目第一步永远是备料。这个系统对硬件要求不高但每一样的选择都有它的道理主控核心Arduino UNO 或 Nano为什么是Arduino对于快速原型开发Arduino的生态丰富的库、简单的IDE和稳定性是首选。UNO接口丰富适合在面包板上搭建测试Nano体积小巧更适合最终成品嵌入。核心参数使用ATmega328P微控制器有14个数字IO和6个模拟输入运行频率16MHz完全能满足本项目需求。其内置的UART通用异步收发传输器是与蓝牙模块通信的硬件基础。显示单元16x2 LCD 液晶屏 I2C 适配板为什么用16x2 LCD16字符x2行是最常见、性价比最高的显示方案足够显示简短的通知、标语或两行信息。为什么一定要加I2C适配板这是本项目的一个关键优化点。传统的1602 LCD需要连接7个以上的数据和控制线RS, RW, E, D4-D7非常占用IO口且接线混乱。I2C适配板通过PCF8574T等芯片将并行接口转换为I2C总线仅需2根信号线SDA, SCL和2根电源线即可驱动极大简化了电路。注意不同厂商的I2C适配板其默认I2C设备地址可能不同常见的是0x27或0x3F后续编程需要对应。无线模块HC-05 蓝牙串口模块为什么是HC-05它是经典的蓝牙2.0EDR模块支持主从一体模式但本项目通常将其设置为从机Slave模式等待手机连接。其本质是一个串口透传模块即把从蓝牙无线收到的数据原封不动地通过TTL串口发送给Arduino反之亦然。这让我们无需处理复杂的蓝牙协议栈只需像操作串口一样编程即可。关键引脚VCC(5V),GND,TXD(发送端),RXD(接收端)。这里有一个极易接错的点模块的TXD要接Arduino的RX(0号引脚)模块的RXD要接Arduino的TX(1号引脚)。因为“发送”总是对应对方的“接收”。其他面包板、杜邦线公对公、公对母、USB数据线为Arduino供电并上传程序、安卓智能手机一部。2.2 电路连接详解与原理图解读正确的连接是成功的一半。我们按照“电源 - 显示 - 通信”的顺序来搭建第一步建立公共电源轨在面包板上用两根长排针建立一条正极5V线和一条负极GND线。将Arduino UNO的5V引脚连接到面包板的正极线GND引脚连接到负极线。这样面包板上就有了稳定的5V电源可供其他模块取用。第二步连接LCD与I2C适配板通常LCD屏已经焊好在I2C适配板上了。我们只需连接适配板的四个引脚GND- 面包板负极线。VCC- 面包板正极线。SDA- Arduino UNO的A4引脚。注意在Arduino上A4引脚除了模拟输入功能也是硬件I2C总线的数据线SDA。SCL- Arduino UNO的A5引脚。同样A5是硬件I2C的时钟线SCL。提示I2C总线是共享总线理论上可以挂载多个设备通过地址区分。这里我们只接了一个LCD。第三步连接HC-05蓝牙模块这是通信的关键务必仔细VCC- 面包板正极线5V。HC-05工作电压通常是3.3V-5V接5V稳定。GND- 面包板负极线。TXD- Arduino UNO的RX引脚即数字引脚0。模块发送Arduino接收。RXD- Arduino UNO的TX引脚即数字引脚1。模块接收Arduino发送。重要注意事项在给Arduino上传程序时必须暂时断开HC-05模块与RX/TX引脚的连接或者至少断开TXD-RX这根线。因为Arduino的RX/TX引脚也用于通过USB与电脑通信上传程序时两者会产生冲突导致上传失败。这是一个非常常见的坑。连接示意图文字描述Arduino UNO 面包板及其他模块 --------- ------------------ | | | | | 5V |-------------------| 正极电源线 |-----| I2C适配板 VCC | | | | |-----| HC-05 VCC | | GND |-------------------| 负极电源线 |-----| I2C适配板 GND | | | | |-----| HC-05 GND | | A4 |-------------------| I2C适配板 SDA | | A5 |-------------------| I2C适配板 SCL | | RX |-------------------| HC-05 TXD | | TX |-------------------| HC-05 RXD | | | | | --------- ------------------2.3 系统工作原理深度剖析硬件连接好后我们来理解数据是如何流动的用户输入你在安卓APP的输入框里打字比如第一行输入“Welcome!”第二行输入“Meeting 3PM”。协议封装APP不会直接发送“Welcome!Meeting 3PM”这么简单。为了防止两行信息在接收端混淆需要定义一个简单的应用层协议。一个常见且有效的做法是用特殊字符分隔两行内容并用另一个特殊字符标记消息结束。例如发送字符串Welcome!,Meeting 3PM*。这里逗号,分隔第一行和第二行星号*作为结束符。蓝牙传输APP通过手机蓝牙将封装好的字符串发送到已配对的HC-05模块。串口透传HC-05模块收到蓝牙数据后其内部的芯片不做任何处理直接通过TTL串口将原始的字节流发送到Arduino的RX引脚。Arduino解析Arduino的loop()函数中通过Serial.available()不断检查串口是否有数据。一旦检测到便使用Serial.read()逐个字节读取。代码逻辑会持续拼接这些字节直到遇到约定的结束符*。然后它再根据分隔符,将完整的字符串拆解成messageStatic第一行和messageToScroll第二行。显示驱动Arduino调用LiquidCrystal_I2C库的函数将解析出的字符串发送到I2C总线。I2C适配板上的芯片将I2C命令转换为LCD能理解的并行信号最终控制液晶分子偏转显示出文字。整个过程Arduino代码的核心任务就是可靠地接收数据、准确地解析协议、正确地驱动显示。蓝牙和I2C的底层通信细节都有成熟的硬件和库函数帮我们处理这正是Arduino生态高效的地方。3. 软件实现从基础显示到无线通信3.1 开发环境准备与核心库安装安装Arduino IDE从Arduino官网下载并安装最新版IDE。这是我们的编程和烧录工具。安装必要的库本项目最关键的一个库是用于驱动I2C LCD的LiquidCrystal_I2C。打开Arduino IDE点击“工具” - “管理库...”。在库管理器中搜索“LiquidCrystal I2C”通常会找到由Frank de Brabander开发的版本。点击安装。这个库封装了通过I2C控制LCD的所有复杂操作我们只需要调用简单的print(),setCursor(),clear()等函数即可。3.2 三步代码演进从点亮屏幕到无线控制我建议分三步来编写和测试代码这符合从易到难的调试逻辑能帮你清晰地定位问题。第一步基础显示测试 - 确认LCD与I2C地址这一步的目的是排除硬件连接和地址错误。上传以下代码如果LCD亮起并显示“Hello World”说明LCD和I2C连接正确。#include Wire.h #include LiquidCrystal_I2C.h // 初始化LCD对象参数I2C地址列数行数 // 关键点地址必须是0x27或0x3F根据你的模块二选一。如果都不对需要运行I2C扫描程序查找。 LiquidCrystal_I2C lcd(0x27, 16, 2); void setup() { lcd.init(); // 初始化LCD lcd.backlight(); // 打开背光 // 在第一行第0列开始打印 lcd.setCursor(0, 0); lcd.print(Hello, Line 1!); // 在第二行第0列开始打印 lcd.setCursor(0, 1); lcd.print(Hello, Line 2!); } void loop() { // 空循环静态显示 }实操心得如果屏幕不亮或显示乱码首先检查接线然后尝试更换I2C地址0x3F。可以使用专门的I2C Scanner示例代码在IDE的示例中来扫描总线上设备的准确地址。第二步实现滚动显示 - 增加动态效果静态显示有点枯燥我们让第二行文字滚动起来这在实际公告牌中很常用。#include Wire.h #include LiquidCrystal_I2C.h LiquidCrystal_I2C lcd(0x27, 16, 2); // 根据实际情况修改地址 // 定义LCD的尺寸 int lcdColumns 16; int lcdRows 2; // 定义要显示的文字 String staticMessage DOFBOT.COM; String scrollMessage Wireless Notice Board Project is Running...; // 自定义滚动显示函数 void scrollText(int row, String message, int delayTime, int totalColumns) { // 在消息前添加空格使其从屏幕外滚入 for (int i 0; i totalColumns; i) { message message; } // 在消息后添加空格使其完全滚出屏幕 message message ; // 实现滚动动画 for (int pos 0; pos message.length(); pos) { lcd.setCursor(0, row); // 从消息字符串中截取当前应显示的一屏内容 lcd.print(message.substring(pos, pos totalColumns)); delay(delayTime); // 延迟时间控制滚动速度 } } void setup() { lcd.init(); lcd.backlight(); } void loop() { // 清屏可选根据效果决定是否每次循环清屏 // lcd.clear(); // 显示静态信息第一行 lcd.setCursor(0, 0); lcd.print(staticMessage); // 显示滚动信息第二行 scrollText(1, scrollMessage, 300, lcdColumns); // 300ms延迟速度适中 }这段代码的关键在于scrollText函数它通过不断改变显示字符串的起始位置来模拟滚动效果。delayTime参数很重要太小会滚得太快看不清太大则显得卡顿需要根据实际观感调整。第三步集成蓝牙通信与协议解析 - 实现无线控制这是最终的核心代码。它结合了串口数据接收和上述显示功能。#include Wire.h #include LiquidCrystal_I2C.h // 定义LCD int lcdColumns 16; int lcdRows 2; LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows); // 修改为你的地址 // 全局变量用于处理接收的数据 char incomingChar; // 存储每次从串口读取的单个字符 String receivedString ; // 用于拼接完整的接收字符串 String line1Msg ; // 解析后的第一行信息 String line2Msg ; // 解析后的第二行信息 // 滚动显示函数同上此处省略以节省篇幅实际代码中需保留 void scrollText(int row, String message, int delayTime, int totalColumns) { // ... (函数体与第二步完全相同) } void setup() { // 初始化LCD lcd.init(); lcd.backlight(); lcd.clear(); lcd.setCursor(0, 0); lcd.print(System Ready!); delay(1000); lcd.clear(); // 初始化串口通信波特率必须与HC-05模块匹配默认通常是9600 Serial.begin(9600); // 可以在LCD上显示等待连接状态 lcd.setCursor(0,0); lcd.print(BT:Waiting...); } void loop() { // 检查串口是否有数据到达 if (Serial.available() 0) { incomingChar Serial.read(); // 读取一个字节 // 如果收到的不是结束符就拼接到字符串中 if (incomingChar ! *) { receivedString incomingChar; } // 如果收到结束符*说明一条完整消息接收完毕 else { // 可选将接收到的原始数据回传到串口监视器方便调试 // Serial.println(Received: receivedString); // 解析协议假设格式为 第一行内容,第二行内容* int separatorIndex receivedString.indexOf(,); // 查找分隔符位置 if (separatorIndex ! -1) { // 成功找到分隔符进行解析 line1Msg receivedString.substring(0, separatorIndex); line2Msg receivedString.substring(separatorIndex 1); // 清屏并显示新内容 lcd.clear(); lcd.setCursor(0, 0); lcd.print(line1Msg); lcd.setCursor(0, 1); // 如果第二行信息过长则启用滚动显示否则静态显示 if (line2Msg.length() lcdColumns) { scrollText(1, line2Msg, 250, lcdColumns); } else { lcd.print(line2Msg); } // 可选在串口监视器打印解析结果用于验证 // Serial.print(Line1: ); // Serial.println(line1Msg); // Serial.print(Line2: ); // Serial.println(line2Msg); } else { // 没有找到分隔符可能协议错误或消息只有一行 lcd.clear(); lcd.setCursor(0,0); lcd.print(Msg Error:); lcd.setCursor(0,1); lcd.print(receivedString); } // 处理完毕清空接收字符串准备接收下一条消息 receivedString ; } } // 如果第二行信息正在滚动需要维持滚动循环当非滚动时此部分不执行 // 注意简单的loop结构下滚动显示会阻塞loop直到滚动完成。 // 更高级的做法是使用状态机和非阻塞延时但为了初学者理解此处使用阻塞式。 }这段代码是项目的核心。它定义了一个简单的协议以逗号,分隔两行文本以星号*作为消息结束标志。loop()函数不断监听串口拼接字符遇到*后触发解析和显示。务必注意上传此代码前记得断开或拔掉HC-05与ArduinoRX引脚的连接上传成功后再接回去。3.3 安卓端配置与通信测试Arduino端准备好后我们需要一个发送端。蓝牙配对给整个系统上电通过USB线或外部电源。打开手机蓝牙设置搜索新设备。你应该能找到一个名为“HC-05”的设备默认名称。点击配对输入配对码通常是1234或0000。配对成功后HC-05模块上的LED指示灯应从快闪变为慢闪或常亮取决于模式。选择发送工具方案一最简单使用现成的“蓝牙串口”APP。在应用商店搜索“蓝牙串口”会有很多选择如“Serial Bluetooth Terminal”。安装后打开APP连接“HC-05”设备然后在发送框输入第一行文字,第二行文字*点击发送。LCD屏幕应立即更新。方案二自定义APP如果你想完全控制可以用MIT App Inventor或Android Studio开发一个简易APP上面放两个输入框和一个发送按钮按钮的逻辑就是将两个输入框的内容用逗号连接加上星号然后通过蓝牙串口发送。这对于学习完整的物联网应用开发链路更有帮助。4. 系统优化、调试与深度问题排查项目基本跑通后我们可以让它更稳定、更实用。这里分享一些进阶优化和必然遇到的坑。4.1 稳定性与功能优化建议增加连接状态指示可以在LCD第一行固定显示蓝牙连接状态如“BT:Connected”或“BT:Waiting”。这需要Arduino代码能检测串口链路层的状态对于HC-05简单的办法是定时发送AT指令查询但会复杂些。一个取巧的办法是在手机APP端每次连接成功后发送一个特定字符串如“CONNECTED*”Arduino收到后更新状态显示。实现非阻塞式滚动当前代码中scrollText函数里的delay()会阻塞整个loop()。这意味着在文字滚动期间系统无法接收新的蓝牙信息。对于需要实时更新的公告牌这是不行的。优化方法是使用状态机和millis()函数进行非阻塞延时。核心思想是记录每次滚动步骤的时间戳时间到了才移动一格并刷新显示这样loop()函数在等待期间可以快速循环处理其他任务如检查串口。设计更健壮的通信协议添加帧头/帧尾当前协议“A,B*”如果文本本身包含逗号或星号就会乱套。可以定义更复杂的协议如“$START,A,B,END*”。添加校验和在消息末尾加入一个简单的校验和如所有字符ASCII码之和取低字节Arduino收到后计算校验和比对不一致则要求重发或丢弃提高抗干扰能力。增加指令集除了显示文本还可以定义其他指令如“CLEAR*”清屏“BACKLIGHT,OFF*”关闭背光等让系统更可控。电源优化如果打算长期独立运行可以考虑用9V电池配合降压模块为Arduino供电或者使用手机充电宝。注意HC-05模块在通信时电流可能达到几十毫安确保电源能带动。4.2 常见问题与故障排查实录即使按照步骤操作你也可能会遇到以下问题。这里是我的“踩坑”记录问题现象可能原因排查步骤与解决方案LCD屏幕无任何显示1. 电源未接通或接反。2. I2C地址错误。3. 对比度问题虽罕见但1602需调节。1. 用万用表检查LCD的VCC和GND间是否有5V电压。2. 运行I2C Scanner示例代码在串口监视器查看扫描到的地址并修改代码。3. 找到LCD模块上的电位器如果有用小螺丝刀缓慢旋转调节对比度。LCD显示乱码或黑色方块1. 初始化失败或通信不稳定。2. 代码中行列参数与实物不符。1. 检查lcd.init()是否执行I2C线SDA, SCL连接是否松动。2. 确认LiquidCrystal_I2C lcd(0x27, 16, 2)中的16和2与你的屏幕规格一致。蓝牙配对失败1. HC-05未进入配对模式。2. 配对码错误。3. 手机蓝牙与模块不兼容极少见。1. 确保模块已通电且指示灯处于快闪状态配对模式。有些模块有按键需长按进入配对模式。2. 尝试1234或0000。3. 换一部手机试试。手机APP连接成功但发送数据无反应1.最常见接线错误特别是TXD/RXD交叉。2. 波特率不匹配。3. 上传代码时未断开RX线导致程序未正确烧录。4. 代码中串口初始化波特率与HC-05不匹配。1.重点检查HC-05的TXD是否接Arduino的RX(0)RXD是否接TX(1)。2. 确认APP和Arduino代码中的串口波特率均为9600HC-05默认。可在APP设置中查看或修改。3.务必养成习惯上传代码前断开HC-05与ArduinoRX引脚的连接。4. 检查Serial.begin(9600);语句。只能接收部分字符或显示错乱1. 串口接收缓冲区处理不当数据丢失。2. 协议解析逻辑有bug比如字符串拼接溢出或分隔符处理错误。3. 发送的数据包含中文等非ASCII字符需特殊处理。1. 在代码中增加调试输出将receivedString打印到串口监视器连接电脑USB看原始数据是否完整。2. 仔细检查if (incomingChar ! *)和separatorIndex的逻辑。确保receivedString在解析后被清空。3. 对于简单项目建议手机APP和Arduino端都只使用英文和标准符号。系统运行一段时间后死机或无响应1. 电源功率不足带载后电压下降。2. 代码中存在内存泄漏如String对象在循环中不断拼接未释放。3. 无线干扰。1. 使用稳压电源或容量更大的电池供电观察现象是否改善。2. 优化代码避免在loop()中频繁创建大的String对象。对于固定字符串使用字符数组(char array)可能更稳定。3. 远离大功率无线设备如路由器。4.3 项目扩展思路这个基础框架可以玩出很多花样显示升级将16x2 LCD换成20x4 LCD甚至换成OLED显示屏可以显示更多内容或更酷炫的图形。无线升级将HC-05换成ESP8266或ESP32模块系统就具备了Wi-Fi功能可以通过局域网甚至互联网远程更新公告实现真正的“物联网公告牌”。功能升级结合传感器比如温湿度传感器DHT11让公告牌自动显示环境信息。或者加上RTC实时时钟模块显示精确时间。交互升级在Arduino上连接一个按键或红外接收头实现手动翻页或切换显示模式。这个基于Arduino和蓝牙的无线公告牌项目虽然硬件简单但它完整地走通了一个物联网终端的数据采集手机输入、无线传输蓝牙、数据处理Arduino解析和信息呈现LCD显示的闭环。最重要的是它让你亲手触摸到了串口通信、协议设计、外设驱动这些嵌入式开发的核心概念。希望你在实现它的过程中不仅收获了一个有趣的小工具更能理解其背后每一个环节“为什么”要这么做。遇到问题别怕对照上面的排查表一步步来硬件项目的乐趣一半就在这解决问题的过程里。