码迷,mamicode.com
首页 > 其他好文 > 详细

手把手教你做蓝牙小车(二)

时间:2016-06-12 03:02:04      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:

第5节 BTChat

本节开始介绍Arduino蓝牙模块,配合Android应用,实现一个蓝牙聊天应用。

5.1 什么是蓝牙

简单说就是一种不同设备之间点对点通讯的技术。
有大篇大篇的蓝牙各种协议,各种规范。。。
本课程只讲用到的内容,不展开更多内容了。

5.2 SDP

Service Discovery Protocol,简称SDP,是允许设备发现其他设备所支持服务的协议。
蓝牙协议给每个服务分配一个UUID,用来区分各种服务。
SDP的UUID是00001101-0000-1000-8000-00805F9B34FB.

5.3 Android蓝牙应用

Android提供了一个叫BluetoothChat的蓝牙实例
这里是相关介绍
https://developer.android.com/samples/BluetoothChat/index.html
右上角有个Download,点击下载到一个Eclipse下的Android工程。

这个应用程序是针对Android系统的聊天应用,需要修改其UUID才能和Arduoni蓝牙模块聊天。
或者你也可以直接下载我在安豆网共享的apk。

5.4 Arduino实现蓝牙

Arduino把蓝牙封装成了一个串口。
我们只需要把蓝牙芯片连接到特定的串口,之后就可以当做一个串口来处理了。

5.5 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对象。

5.6 手机和Arduino连接

Arduino按上一节的线路连接,并用USB线连接到电脑。
打开蓝牙,安装BTChat.apk到手机,打开应用,参考下图。

技术分享

5.5 Arduino代码修改

因为要使用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可以简单通讯了。

5.6 BluetoothChat的bug

通过串口监视器输入一个很长的字符串,比如“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();
...

手把手教你做蓝牙小车(二)

标签:

原文地址:http://blog.csdn.net/anddlecn/article/details/51603484

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!