本文中使用的是软件模拟串口,附有完整例程.
目录
0.相关软件
0.1下载链接:
链接: https://pan.baidu.com/s/1cFXqshrRk7hNMwSu7eCPbQ?pwd=ahao 提取码: ahao
1.HC05与USB转TTL
2.进入AT命令模式
2.1连线
HC-05 | USB转TTL |
---|---|
STATE | NC(不连) |
RXD | 9 |
TXD | 8 |
GND | GND |
VCC | +5V |
EN | NC |
连接好线路后,按住HC05的按键,然后给模块重新上电,HC05指示灯慢闪(2秒闪一次)代表进入AT模式
2.2发送指令
在串口调试助手上发送指令,HC05的指令模式的波特率默认是38400.
勾选回车换行后依次发送(期间每个指令都会回传OK)
AT+NAME=HC-05 修改蓝牙模块名称为HC-05
AT+ROLE=0 蓝牙模式为从模式
AT+CMODE=1 蓝牙连接模式为任意地址连接模式,也就是说 该模块可以被任意蓝牙设备连接
AT+PSWD=1234 蓝牙配对密码为1234
AT+UART=9600,0,0 蓝牙通信串口波特率为9600,停止位1位, 无校验位
完成指令配置.
之后就是arduino与HC05的连接.
3.简略版demo
3.1 HC05与arduino连线图
//arduino的GND接蓝牙或串口工具的GND,共地
//arduino的9接蓝牙或串口工具的RX
//arduino的8接蓝牙或串口工具的TX
//arduino的5V接蓝牙的5V
//根据自己的实际改为对应的串口,我这里接的是8和9
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(8,9);
int led = 13;
void setup()
{
Serial.begin(9600);
pinMode(led,OUTPUT);//定义小灯为输出模式
BTSerial.begin(9600);
}
void loop()
{
if (BTSerial.available())
{
char var;
var = BTSerial.read(); //从串口接收数据
if (var == '1') {
digitalWrite(led, HIGH);
Serial.println("LED is on!");
}
if (var == '0') {
digitalWrite(led, LOW);
Serial.println("LED is off");
}
}
}
3.2实验现象
发射端(主机)(手机的蓝牙调试助手)
接收端(从机)
4.软件模拟串口 HEX格式接收 帧头 帧尾 校验代码
4.1实验现象
主机
从机
4.2代码
//arduino的GND接蓝牙或串口工具的GND,共地
//arduino的9接蓝牙或串口工具的RX
//arduino的8接蓝牙或串口工具的TX
//arduino的5V接蓝牙的5V
//根据自己的实际改为对应的串口,我这里接的是8和9
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(8,9);
#define FRAME_LENGTH 7
char str[100];
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("CongHC-05 is opened:");
BTSerial.begin(9600);
while (BTSerial.read() >= 0); //清空BT串口缓冲区
}
void loop() {
// put your main code here, to run repeatedly:
receive();
}
void receive()
{
//当串口缓冲区大于等于6时
while (BTSerial.available() >= FRAME_LENGTH) {
unsigned char ubuffer[FRAME_LENGTH];
//从串口缓冲读取1个字节但不删除
unsigned char frame_header = BTSerial.peek();
//当获取的数据是包头(0x55)时
if (frame_header == 0x55)
{
//从串口缓冲区读取7字节
BTSerial.readBytes(ubuffer, FRAME_LENGTH);
if (ubuffer[4] == 0xff && ubuffer[5] == 0xff && ubuffer[6] == 0xff) {
if(ubuffer[1] == 0x01)
{
//下发的是LED信息
sprintf(str,"led %d %s\r\n", ubuffer[2], ubuffer[3] ? "打开" : "关闭");
Serial.print(str);
}else if(ubuffer[1] == 0x02)
{
//下发的是风扇
sprintf(str, "风扇 %d %s\r\n", ubuffer[2], ubuffer[3] ? "打开" : "关闭");
Serial.print(str);
}else if(ubuffer[1] == 0x03)
{
//下发的是继电器的信息
sprintf(str, "继电器 %d %s\r\n", ubuffer[2], ubuffer[3] ? "打开" : "关闭");
Serial.print(str);
}
}
} else {
BTSerial.read(); //从串口缓冲读取1个字节并删除
}
}
}
//例子1:上位机代码 55 01 01 00 ff ff ff 含义:1号led关闭
//例子2:上位机代码 55 01 04 01 ff ff ff 含义:4号led打开
//例子3:上位机代码 55 02 01 01 ff ff ff 含义:1号风扇打开
//例子4:上位机代码 55 03 04 00 ff ff ff 含义:4号继电器关闭
5.软串口 字符串格式 无校验 (处理函数中有阻塞)
5.1实验现象
主机
从机
5.2代码
//arduino的GND接蓝牙或串口工具的GND,共地
//arduino的9接蓝牙或串口工具的RX
//arduino的8接蓝牙或串口工具的TX
//arduino的5V接蓝牙的5V
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(8,9);
void setup() {
Serial.begin(9600); // 设置串口波特率
BTSerial.begin(9600);
while (BTSerial.read() >= 0); //清空BT串口缓冲区
}
void loop() {
receive();
}
void receive()
{
if (BTSerial.available() > 0) { // 判断是否有数据可用
String inStr = ""; // 初始化字符串
inStr.reserve(128); // 预分配内存空间,避免多次动态分配(根据实际需要调整大小)
// 读取串口数据,直到没有更多数据
while (BTSerial.available() > 0) {
inStr += (char)BTSerial.read(); // 拼接读取的字符
delay(5); // 小延时,避免阻塞,允许其他任务运行
}
// 移除输入数据中的换行符和回车符
inStr.trim(); // trim() 会移除字符串两端的空格、换行符和回车符
// 输出清理后的字符串
//Serial.println(inStr); // 输出读取的字符串
// 检查inStr中是否包含"txt"
if (inStr.indexOf("ledon") >= 0) { // indexOf返回匹配子字符串的起始位置,若找不到则返回-1
Serial.println("led打开"); // 如果包含"ledon",输出"ok"
}
if (inStr.indexOf("ledoff") >= 0) { // indexOf返回匹配子字符串的起始位置,若找不到则返回-1
Serial.println("led关闭"); // 如果包含"ledon",输出"ok"
}
if (inStr.indexOf("jion") >= 0) { // indexOf返回匹配子字符串的起始位置,若找不到则返回-1
Serial.println("继电器打开"); // 如果包含"ledon",输出"ok"
}
}
}
6.软串口 字符串格式 无校验 无阻塞
6.1实验现象
主机
从机
6.2代码
//arduino的GND接蓝牙或串口工具的GND,共地
//arduino的9接蓝牙或串口工具的RX
//arduino的8接蓝牙或串口工具的TX
//arduino的5V接蓝牙的5V
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(8,9);
void setup() {
Serial.begin(9600); // 设置串口波特率
BTSerial.begin(9600);
while (BTSerial.read() >= 0); //清空BT串口缓冲区
}
void loop() {
receive();
}
void receive()
{
static String inStr = ""; // 使用静态变量保持输入字符串
static unsigned long lastReadTime = 0; // 记录上次读取的时间
// 每次循环检查串口是否有数据可用
if (BTSerial.available() > 0) { // 判断是否有数据可用
unsigned long currentMillis = millis(); // 获取当前时间
// 判断是否距离上次读取时间超过一定间隔(避免过快读取)
if (currentMillis - lastReadTime > 10) { // 每10ms读取一次数据
inStr += (char)BTSerial.read(); // 拼接读取的字符
lastReadTime = currentMillis; // 更新上次读取时间
}
// 如果读取到完整的一行数据(假设换行符为结束标志)
if (inStr.indexOf('\n') >= 0) {
// 移除输入数据中的换行符和回车符
inStr.trim(); // trim() 会移除字符串两端的空格、换行符和回车符
// 输出清理后的字符串
//Serial.println(inStr); // 输出读取的字符串
// 检查inStr中是否包含"txt"
if (inStr.indexOf("txt") >= 0) { // indexOf返回匹配子字符串的起始位置,若找不到则返回-1
Serial.println("ok"); // 如果包含"txt",输出"ok"
}
if (inStr.indexOf("ledon") >= 0) { // indexOf返回匹配子字符串的起始位置,若找不到则返回-1
Serial.println("led已经打开"); // 如果包含"txt",输出"ok"
}
if (inStr.indexOf("ledoff") >= 0) { // indexOf返回匹配子字符串的起始位置,若找不到则返回-1
Serial.println("led已经关闭"); // 如果包含"txt",输出"ok"
}
// 重置字符串,准备下一次输入
inStr = "";
}
}
}