Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 手把手教你做藍牙小車(二)

手把手教你做藍牙小車(二)

編輯:關於Android編程

第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();
...
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved