本节开始介绍Arduino蓝牙模块,配合Android应用,实现一个蓝牙聊天应用。
简单说就是一种不同设备之间点对点通讯的技术。
有大篇大篇的蓝牙各种协议,各种规范。。。
本课程只讲用到的内容,不展开更多内容了。
Service Discovery Protocol,简称SDP,是允许设备发现其他设备所支持服务的协议。
蓝牙协议给每个服务分配一个UUID,用来区分各种服务。
SDP的UUID是00001101-0000-1000-8000-00805F9B34FB
.
Android提供了一个叫BluetoothChat的蓝牙实例
这里是相关介绍
https://developer.android.com/samples/BluetoothChat/index.html
右上角有个Download,点击下载到一个Eclipse下的Android工程。
这个应用程序是针对Android系统的聊天应用,需要修改其UUID才能和Arduoni蓝牙模块聊天。
或者你也可以直接下载我在安豆网共享的apk。
Arduino把蓝牙封装成了一个串口。
我们只需要把蓝牙芯片连接到特定的串口,之后就可以当做一个串口来处理了。
再复习一下Serial硬件定义
Uno示例
USB接口和0、1引脚是Serial对象
Mega示例
USB接口和0、1引脚是Serial对象。
14、15引脚是Serial3对象。
16、17引脚是Serial2对象。
18、19引脚是Serial1对象。
如果用Uno开发蓝牙应用,只能电脑连接USB口,蓝牙也连接0、1引脚。
两者同时连接会导致USB口不能烧写代码。
必须要拔下蓝牙连线,才能烧写代码。
然后再接上蓝牙连线,才能调试蓝牙。
简直是一场噩梦。
这是我在本文开头推荐选用Mega开发板的理由之一。
用Mega就简单了,它提供了4个串口,我们用Serial以外的其他口就没有上边的冲突了。
下图是我的连接方式
蓝牙模块的VCC,GND引脚分别连接Mega的正负引脚。
蓝牙模块的TX引脚连接Mega的RX3引脚,RX引脚连接Mega的TX3引脚。
现在,USB口是Serial对象,蓝牙是Serial3对象。
/*******************************************************************/
* 版权声明
* 本教程只在CSDN和安豆网发布,其他网站出现本教程均属侵权。
/*******************************************************************/
Arduino按上一节的线路连接,并用USB线连接到电脑。
打开蓝牙,安装BTChat.apk到手机,打开应用,参考下图。
因为要使用Serial和Serial3,所以两个串口都需要初始化
void setup() {
Serial.begin(9600);
Serial3.begin(9600);
}
用Serial3.available()
函数检查蓝牙串口是否有数据输入。
用Serial3.read()
读取蓝牙串口的输入内容。
用Serial.print(Serial3.read())
将上一步读取到的内容输出到PC端的串口监视器。
void loop() {
while (Serial3.available()) {
Serial.print(Serial3.read());
}
}
再加一段相反方向读取输出的代码
void loop() {
while (Serial3.available()) {
Serial.print(Serial3.read());
}
while (Serial.available()) {
Serial3.print(Serial.read());
}
}
试试看吧,手机和Arduino可以简单通讯了。
通过串口监视器输入一个很长的字符串,比如“abcdefghijklmnopqrstuvwxyz1234567890”。
手机显示的数据是这样子的,显然不是我们希望的结果。
我们看看Android这边是怎么收数据的。
收数据的相关代码在
BluetoothChat\Application\src\main\java\com\example\android\bluetoothchat\BluetoothChatService.java文件,ConnectedThread类的run()
函数中。
一开始运行run函数,先申请一块内存。
...
byte[] buffer = new byte[1024];
...
收取数据代码段不断循环。
...
while (true) {
...
读取串口数据到buffer中
...
bytes = mmInStream.read(buffer);
...
把收到的数据发送给Fragment,在界面显示内容。
...
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
...
这是run()
函数相关代码
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
...
这个例子中,Android这边先收到‘a’,发送给界面显示。
又收到‘bcdefghij’,继续发送给界面显示。
一直到最后收到‘567890’。
一切看起来都挺完美。
但,问题出在几次收数据共用一个buffer,而界面显示是异步处理。前一次界面还没有更新,后一次新的数据已经收到了。这时候界面就错误的显示了后一次的数据。
本教程以Arduino为主,所以Android的代码简单修改,能用就行了。
把申请内存的代码挪到while循环内。
byte[] buffer = new byte[1024];
修改后的代码。
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
int bytes;
// Keep listening to the InputStream while connected
while (true) {
byte[] buffer = new byte[1024];
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
...
/*******************************************************************/
* 版权声明
* 本教程只在CSDN和安豆网发布,其他网站出现本教程均属侵权。
*另外,我们还推出了Arduino智能硬件相关的教程,您可以在我们的网店跟我学Arduino编程中购买相关硬件。同时也感谢大家对我们这些码农的支持。
*最后再次感谢各位读者对安豆
的支持,谢谢:)
/*******************************************************************/