一、开始
1、软件和硬件准备:
以下软件网上都可以很容易找到。
- nrf connect APP 用于手机蓝牙连接单片机蓝牙时进行测试
- SSCOM 串口调试软件
- Arduino IDE
总的硬件需求,可以针对不同场景选择个数: - 计算机1台、可支持蓝牙的手机1台(用于手机拦截蓝牙模块的测试)
- 2个或3个JDY-10M模块和2个USB转ttl模块(用于通过一台电脑测试两个JDY蓝牙模块间的通讯)、
- 1个或2个Arduino单片机、杜邦线若干。
实际上,硬件部分得看你的需求,如果只是两个模块蓝牙通讯使用HC-05更加方便,一主一从,即插即用。而,JDY-10M的通讯相对HC-05麻烦很多,主要是它传输的数据是以十六进制的形式,且存在数据信息头,这中间会涉及数据的转换问题,如果是蓝牙组网,需要自定义数据的读取和接收方便识别,当然该模块功能也会强大一些。以下是本人踩坑笔记,网上关于Arduino+JDY-10M的教程不多,主要是官方使用说明文档,个人感觉对初学者和Arduino使用者并不友好。先上个JDY-10M模块的图片:
2、软件学习
- nrf connect APP。
这个软件比较强大,我们只需要知道如何连接蓝牙,如何发送串口数据,如何查询接收的数据。
手机与蓝牙模块配对,看这里:
nrf connect使用方法 :链接
如何使用nRF Connect的数据读取和发送功能:链接
不同app版本,可能界面会有差异,但是功能应该都差不多。
- SSCOM软件界面如图:
这里面需要注意,“加回车换行”、“HEX发送(表示以十六进制的形式显示发送和接收的字符数据)”、“HEX显示”,这是调试和踩坑的关键点。 - Arduino IDE的使用就不说了。
3、知识储备
最重要的知识储备,肯定是官方的JDY-10M使用说明书了,多看几遍。这部分文档,网上找不到,可以去淘宝卖模块的地方找下载链接,内容基本大同小异。以下是大概的内容截图,主要是那3个pdf文件了。
二、正式上菜
1、设置和配对(以3个JDY-10M模块为例,A、B、C)
(1) 设置说明:
用过蓝牙的都知道AT命令行,这个蓝牙模块也是一样有的这些命令,具体见“使用说明”。
JDY-10M蓝牙不需要通过按键来进入AT命令模式,只要在没有连接其它蓝牙模块的情况下,就可以直接输入AT命令进行蓝牙设置。其中,串口默认的波特率为115200bps,这个可以后期修改。
(AT 指令区分大小写,均以回车、换行字符结尾:\r\n,特别注意电脑串口工具发结束符,不需要输入\r\n,只需要沟选发送回车就行:资料附带串口工具)
(2) 配对:
先给出,官方文档(应该算是官方文档吧,反正红色的字不是我写的)
按照以上配置教程,应该差不多可以配置完全,主要是第3步的短地址不同而已。然后,若是想重新设置波特率,就是AT+BAUD+波特率。其它设置,如,配对密码之类的就看说明书的命令行介绍。
(3) 简单说明关键问题。:
(1)同一个网路中,每个蓝牙模块组网ID必须相同。同一个网络中,每个蓝牙模块广播名(即搜索蓝牙时显示的名称)必须相同。同一个网络中,每个蓝牙模块短地址必须不同。组网ID和广播名是不同的。
即,A、B、C的组网ID都是相同的,A、B、C的广播名也是相同的,A、B、C的短地址都是不同的。
(2)组网ID号、广播名、短地址有长度和数字或字母限制,其中,短地址只有两位字符,是十六进制表示。
(3)个人感觉增加这么多名称,组网ID是在多个蓝牙组网的情况下可以通过组网ID进行区分网络。广播名就是蓝牙名,同一个网络下相同,方便区分同一网络下的蓝牙模块。短地址是则是区分同一个网络下,该蓝牙唯一的标志。
2、数据传输
方案一:
首先,用电脑进行测试,2个USB转ttl分别连接2个JDY-10M蓝牙模块,连接方法,RX-TX,TX-RX,5V-5V,GND-GND。
再都插入同一台电脑,打开两个SSCOM软件窗口。也可以分开插入2台电脑,并分别打开SSCOM软件。
还是先看官方文档:
前期配对好后,单击“打开串口”,输入数据“AAFBFFFF313233”,单击“发送”。。。很多人在这里就没然后了。并没有出现文档说的,“组网成功,所有模块将会串口输出123信息”。
问题:
发送串口数据,不能勾选“加回车换行”,且,勾选“HEX发送”。
调试的过程中,为方便查看,可以有选择性的勾选“HEX显示”,因为这个蓝牙模块传输的数据是十六进制,方便查看串口传输过来的数据。
方案二:
JDY-10M蓝牙模块相比HC-05麻烦的就是传输数据的格式——十六进制,这是多次踩坑的关键。
如果,方案一可以走通,说明已经知道该蓝牙模块的数据传输关键了。然后就是,Arduino如何传输数据。
首先,用电脑连接1个USB转TTl再连接1个JDY-10M蓝牙模块A,一个Arduino单片机连接1个JDY-10M蓝牙模块B。
这里的关键问题就是,数据的读取和接收。如果只是简单通过以上连接来发送和接收数据,是看不到效果的。因为传输数据的格式有限制,不像HC-05发送什么就接收什么。
(1)JDY-10M传输的数据
根据以上数据格式,来解读一下。
(a)发送数据。
该模块发送的数据,每条数据前都必须带有"AAFB"的数据头+“FFFF”短地址+“~~”你的数据。这都是十六进制的写法,即两位表示一个0—255的数,最大为FF。
其中,“FFFF”表示你的短地址,如,设置的蓝牙模块A短地址为“AT+MADDR01”,设置的蓝牙模块A短地址为“AT+MADDR02”,B单独向A蓝牙模块发送数据“abc”的格式为,“AAFB0001abc”。
每次发送的数据,限制为10个字节,如“1234567890”,即,最多为“AAFBFFFF1234567890”。
(b)接收数据
接收数据,每条数据之前都会有“AA或BB”数据类型+“01”地址+“04”数据长度+“~”实际的数据。如,以上A接收到的数据为“AA0203abc”。
(2)Arduino传输的数据
Arduino的发送方式Serial.println()是将字符转成对应的ASCII码,再发送。即,Serial.println(“1”);实际上是发送的‘1’字符对应的49这个数字。
所以,使用Arduino和JDY-10M组网的一个关键问题就是,数据格式转换,如何将Arduino发送的ASCII转为十六进制数据。
JDY-10M属于低功耗蓝牙(单模),所以每次传输的数据有限,且每次发送数据中间需要有时间间隔,否则也会发送失败。
如下程序段,简单表示Arduino使用JDY-10M。
char a[7] = {0xAA, 0xFB, 0xFF, 0xFF, 0x32, 0x33, 0x38};
char head1[4] = {0xAA, 0xFB, 0x00, 0x01};
char head2[4] = {0xAA, 0xFB, 0xFF, 0xFF};
//jdy-10m的蓝牙地址,对应的是十六进制的表示方法
String testStrData = "";
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
for (int i = 0; i < 7; i++)
{
//Serial.println(a[i],DEC);//输出的是十六进制对应的ASCII码。
//Serial.println(a[i],HEX);//输出十六进制数据
//相当于这里已经保存为Ascii对应的值到数组中
testStrData += a[i];
}
testStrData += "ABC"; //将发送数据从“238”变为“238ABC”
delay(100);
Serial.print(testStrData);//向所有组网蓝牙能够发送数据。自己也会受到该数据
delay(100);
}
void loop() {
//========================发送数据========================
String str0="1234a";
delay(100);//预留的时间不能太短
for (int k = 0; k < 4; k++) //数据头
{
Serial.print(head1[k]);
//表示向蓝牙A发送数据的信息头,即代表向哪个蓝牙发送数据
}
Serial.print(str0);//向蓝牙B发送的数据,字节数小于等于10
delay(100);
//========================接收数据========================
char a;
bool inputBool = false;
String tempStrData = ""; //置空字符串
while (Serial.available() > 0)
{
a = char(Serial.read());
//以下用于确认是正在发送数据,因为蓝牙模块之间会不断的发送地址之类的数据。
//影响通过数据个数判断是否是有用的数据
if (a == 0xFFFFFFAA) //判断输入的第一个数据,这是十六进制的补码
inputBool = true;
if (inputBool == true)
{
tempStrData += a;
//将上位机输入的bytes数据转为char,再组成字符串,也是数组
}
delay(2);//必不可少的的延迟,不然数据读取不完全
}
//以上while循环是将蓝牙模块传过来的数据进行保存,保存的数为char类型。
//第一个AA对应的ASCII是170,而它对应的字符不在ASCII表中,输出则会显示乱码
String str00="";
if (tempStrData.length() > 3) //jdy接收数据前面有3个字节是串口数据信息
{
for (int ii = 3; ii < tempStrData.length(); ii++)
{//若接收的数据太长,也无法发送出去
str00 += tempStrData[ii];
}
if (str00 == "012") //输入的字符是012,即在蓝牙B中发送AAFB0002012
{
digitalWrite(13, HIGH);
delay(100);//预留的时间不能太短
for (int k = 0; k < 4; k++) //数据头
{
Serial.print(head1[k]);
}
Serial.print("qweqwe");//向蓝牙A中发送AAFB0001qweqwe
delay(100);
}
else if (str00 == "0123456789")
{
digitalWrite(13, HIGH);
delay(100);//预留的时间不能太短
for (int k = 0; k < 4; k++) //数据头
{
Serial.print(head1[k]);
}
Serial.print("asdasd");
delay(100);
}
}
//=======================结束=========================
}
注意事项:
(a)testStrData += “ABC”;和testStrData = testStrData + “ABC”;有时候是有区别的,后者有时候将字符串的‘\0’给加上,几次使用在这里也有坑。平时正常使用,两者是等价的。但是偶尔会有这种情况。。。具体没有深究。
(b)Serial.print()和Serial.println()是有区别的。发送数据时后者会加上“换行回车”两个字符,所以计算字符的时候,若加上这两个字符超过了10字节会发送失败,且PC端串口助手显示的时候也会乱码。JDY-10M若一次发送的数据超过10个字节会发送失败。
(c)每次发送数据需要有延时,否则也会失败,特别是频繁发送数据时。最低延时,亲测是50ms。
(d)注意信息头是十六进制的表示,在设计接收的时候需要注意数据格式转换。注意,字符,ASCII码,ASCII码对应的十六进制表示。
(e)顺便说明一个情况,为什么这里需要用十六进制来表示信息头而不是字符呢?因为“0xAA”=170,而它对应的字符不是字母、符号或数字,无法写出来。其次,写成和蓝牙规定的数据格式一样方便查看。Arduino在传输数据的时候,也会将0xAA对应的char字符转为它的ASCII的十进制表示170进行传输。
(f)以上代码,没有单独测试,但是关键信息都在里面了。
(3)过程
方案二的通讯过程,就是PC端使用SSCOM打开蓝牙A,再以十六进制的形式向单片机蓝牙B发送数据,记得去掉勾选"加回车换行”,如,“AAFB0002012”。单片机蓝牙B接收到数据“AA0103012”,并点亮13引脚的LED等,同时返回“qweqwe”字符串,此时,A蓝牙接收到数据“AA0206qweqwe”。
以上是从PC端主动发送数据。程序中还包括,单片机蓝牙B时刻在向PC端蓝牙发送数据“1234a”。
若将head1全部改为head2,则蓝牙会想单片机和PC所有组网内的蓝牙发送数据。
但对所有蓝牙模块发送数据,可能会导致导致陷入死循环,因为JDY-10M蓝牙模块具有转发功能,所以程序设计需要合理。
(4)PC端数据
以上(3)说的是利用SSCOM串口助手来发送的数据,那如何在程序中发送串口数据呢?
关键问题就是,数据格式,即,如何将发送数据字符串转成ASCII,再由ASCII又转为字符串,具体根据不同编程语言会有差异。
方案三:
手机连接JDY-10M蓝牙模块,该部分比较简单,了解了nrf connect APP的使用后,可以很容易的发送和接收数据。
这里需要注意的是,蓝牙模块向手机发送的数据,没有信息头或者字节数超过10,nrf app也是可以接收到的,因为手机蓝牙不熟JDY-10M蓝牙模块的限制。另外,我遇到的一个问题是,当手机nrf APP连接某一个蓝牙模块时,该蓝牙模块会自动从组网中断开。。。这个好像违背了组网的目的,具体没有深究。
方案四:
两个或多个单片机之间进行通讯,这个就需要设置接收和发送数据的交互逻辑了,根据方案二可以进行拓展,这里就不写了。总之,蓝牙组网根据短地址识别唯一的蓝牙,通过发送和接收数据的信息头,进而识别是哪个蓝牙发送和哪个蓝牙接收。
三、最后
还是有必要说明一下,JDY-10M是一个功能十分强大的蓝牙模块,属于低功耗蓝牙,有自己的应用场景,不是任何场景都适合,比如,存在每次最多只能传输10个字节、每次发送数据都需要等待时间等问题,但是也有耗电量小、可同时组成庞大的蓝牙网络、体积小等优点。
以上教程的内容只是最简单的使用。如,JDY-10M蓝牙模块本身还带有引脚,如4路PWM控制,可以之间用于电路的设计,如简单控制LED灯等。
学无止境~