查看: 113447|回復: 90
打印 上一主題 下一主題

手機與Arduino藍牙串口通訊實驗及完整例程

  [復制鏈接]
  • TA的每日心情
    開心
    2015-6-20 22:44
  • 簽到天數: 9 天

    [LV.3]偶爾看看II

    跳轉到指定樓層
    樓主
    發表于 2015-6-10 23:57 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
    本帖最后由 xiongchp 于 2015-6-11 00:01 編輯

    安卓手機與Arduino之間采用藍牙串口通訊,是很多智能裝置和互動裝置常用的控制方法,簡單而有效,無需網絡環境,很實用的技術。

    在論壇搜了一下,帖子很少,問問題的很多。各種教材中炒來炒去,原創的很少,不能給很多愿意學習的人提供幫助。有鑒于此,最近設計了一個實驗(包括例程),在這里提供給大家。如果有更簡捷可靠的實現方法,歡迎賜教。

    實驗采用Arduino UNO板,加了一塊1602LCD屏做顯示(因為只有一個串口,用來做藍牙通訊,再用串口助手不方便,也不直觀)。藍牙模塊使用十幾元一個的HC-06。一個LED接在11腳作為演示。手機端做了一個簡單的界面,有按鍵和滑動條。用按鍵控制LED點亮和熄滅,演示開關量控制。滑動條控制LED的亮度,演示模擬量控制(0-100范圍)。LCD屏實時顯示傳送的數據。模塊接線按標準接法,大家都玩過的,請參考各種教程或書籍。硬件圖片如下。




    關于藍牙串口通訊的幾個要點:

    1. Arduino的串口,print()和println()函數都是用ASCII字符的方式傳送數據,無論是int、float還是string,都自動轉換成ASCII碼傳送。其中println()函數在傳送的數據后面加了回車和換行符("\r"和"\n")。換行符正好可以作為結束符來讓手機端識別。

    2. 藍牙串口是異步傳輸方式,每次Serial.read()只讀一個字節,在一個loop()循環中可能收不全一條數據信息,必須要有一個全局變量來收集接收到的字符。如果要通訊可靠,使用結束符來確定收到了一條完整的信息,是非常必要的。手機端也是一樣。

    3. 例程中用的Serial.parseInt()函數,作用是在收到的字符流中,找到數字字符,并累積在一起,直到收到一個非數字字符時,將前面收到的數字字符轉換成一個整數。如果要傳送多個數值,中間用逗號等分隔符隔開即可。比如三個數值,”12,325,993“,后面加一個自定義的結束符,作為字符串發給Arduino。(例程中用字符"X”作為結束符。)這樣接收數據完整而可靠。接收float可以用Serial.parseFloat()函數,用法一樣。

    安卓手機端可以用藍牙串口助手APP。但是建議自己寫一個簡單的APP,才真正完整的知道怎么通訊。再說了,如果真的做一個產品或服務,總是要自己做手機端APP的,藍牙串口助理不能當產品用。

    Arduino完整例程如下。IDE 1.6.3編譯通過,運行正常。歡迎大家修改使用,完全開源。例程內有詳細注釋。

    kittenblock中小學創客名師推薦的圖形化編程軟件

    /* 本例程演示從手機藍牙串口接收指令,點亮或熄滅11腳的LED,或者調整亮度。
     * 接收指令格式:“101X”點亮,“102X"熄滅,”000X"調整亮度。(000為0-100的整數,表示亮度值,X是結束符。)
     * 串口是異步接收的,用parseInt()查找第一個有效整數,檢測到結束符后開始處理。
     * 接收數據顯示在1602LCD屏上。
     * 點亮或熄滅LED后,將收到數據回傳給手機。用pringln()函數,數據后面加了"\r"和"\n"兩個字符,可以用作結束符。
     * 串口傳送的是ASCII字符,數據格式可以自動轉換。
     */
     
    #include <Wire.h>                  // 包含LCD庫。
    #include <LiquidCrystal_I2C.h>
    LiquidCrystal_I2C lcd(0x27,16,2);  // 初始化LCD對象,地址為0x27,每行16個字符,共兩行。
    int p;                             // 定義整數型全局變量,保存接收的數據。
    
    void setup() {
      lcd.init();                      // 初始化LCD。 
      lcd.backlight();                 // 打開LCD背光。
      Serial.begin(9600);              // 打開串口(藍牙)
      pinMode(11,OUTPUT);              // 定義11腳為輸出。(數字或PWM)
    }
    
    void loop() {
      while (Serial.available() > 0) {   // 串口收到字符數大于零。
        p = Serial.parseInt();           // 在串口數據流中查找一個有效整數。
        if (Serial.read() == 'X') {      // 收到結束符后開始處理數據。
          lcd.clear();                   // LCD清屏。
          lcd.print(p);                  // LCD顯示收到的數據(整數)。
          switch (p) {                   // 判斷數據內容。
          case 101:
            digitalWrite(11,HIGH);       // 點亮LED。
            Serial.println(p);           // 回傳數據。
            break;
          case 102:
            digitalWrite(11,LOW);        // 熄滅LED。
            Serial.println(p);           // 回傳數據。
            break;
          default:
            p = map(p,0,100,0,255);      // 轉換數據范圍到PWM輸出值。
            analogWrite(11,p);           // 調整LED亮度。(PWM)
          }
        }
      }
    }
    

    代碼的簡捷和優雅,體現了編程的教養。

    順便說一下,手機端編程用的是E4A中文安卓編程軟件,簡單省力。基本功能都是齊全的。現在版本是4.7。

  • TA的每日心情
    奮斗
    2015-3-26 09:42
  • 簽到天數: 2 天

    [LV.1]初來乍到

    沙發
    發表于 2015-6-13 16:46 | 只看該作者
    贊一個。辛苦打字不容易。
  • TA的每日心情
    奮斗
    2015-3-26 09:42
  • 簽到天數: 2 天

    [LV.1]初來乍到

    板凳
    發表于 2015-6-13 16:50 | 只看該作者
    樓主可以順便把上位機做法也寫一下。這樣就全了,可以讓版主申請加精,
  • TA的每日心情
    開心
    2015-6-20 22:44
  • 簽到天數: 9 天

    [LV.3]偶爾看看II

    地板
     樓主| 發表于 2015-6-13 19:04 | 只看該作者
    本帖最后由 xiongchp 于 2015-6-13 19:15 編輯

    安卓手機端使用E4A中文安卓編程軟件(免費版),做了一個簡單界面,9個按鍵加一個滑動條。界面布局見帖子中的照片。9個按鍵用了1和2兩個,作為點亮和熄滅LED控制,演示了開關量控制。滑動條輸出0-100的數值,控制LED亮度,演示了模擬量控制。按下1鍵點亮LED時,回返送數據回到手機,滑動條到最右邊位置,作為反饋。按2鍵熄滅LED時,也同樣反饋,滑動條回到最左端位置。例程使用了一個藍牙組件。打開E4A界面,把例程粘貼進去,編譯為apk文件,安裝到安卓手機即可。注意不可以在安卓模擬器上運行,因為模擬器沒有藍牙模塊,會退出。

    kittenblock中小學創客名師推薦的圖形化編程軟件

    /* 本例程通過藍牙串口發送指令給Arduino,點亮或熄滅LED,也可以通過滑塊調整LED亮度.
     * 手機界面上的按鍵1發送"101X",點亮LED,按鍵2發送"102X",熄滅LED.
     * 拖動界面上的滑塊后,發送0-100之間的整數,表示亮度值,后面加一個"X"為結束符..
     * 接收Arduino傳回的數據,收到"101X",滑塊到最大位置.收到"102X",滑塊的最小位置.
     * 藍牙串口接收是異步的,必須在收到數據事件中累積收到的ASCII字符,檢測到結束符后再處理.
     * Arduino的println()函數發出的數據后面會加上回車和換行符,可以作為結束符使用.
     * 處理數據時或轉換格式時,要去掉回車換行符.(字符長度要減2).
     */
    
    變量 返回值 為 文本型     // 定義全局變量,保存接收數據.
            
    事件 主窗口.創建完畢()        
        返回值 = ""
            如果 藍牙1.是否已開啟() = 假 則     //開啟手機藍牙.
                    藍牙1.開啟藍牙()
            結束 如果
    結束 事件
    
    事件 藍牙1.藍牙設置完畢(設置結果 為 整數型)
            判斷 設置結果
                    分支 1           //藍牙已開啟.
                            彈出提示("藍牙已開啟")
                            藍牙1.置可被發現()           //置可被發現
                    分支 2                        '藍牙未開啟
                            信息框("信息","藍牙未被開啟,程序將退出!","確定")
                            結束程序()
                    分支 3                       //已置可被發現
                            彈出提示("藍牙已設置為可被發現")
                    分支 4                       //不可被發現
                            信息框("信息","藍牙未被設置為可被發現,程序將退出!","確定")
                            結束程序()
            結束 判斷
            藍牙1.置工作模式(1)       //置工作模式為串口通訊.
    結束 事件
    
    事件 按鈕10.被單擊()
        藍牙1.搜索設備()          //搜索設備
            彈出提示("正在搜索")
    結束 事件
    
    事件 藍牙1.發現設備(設備名稱 為 文本型,設備地址 為 文本型,是否已配對 為 邏輯型)   //發現藍牙設備.
            列表框1.可視 = 真            //顯示列表框.
            列表框1.添加項目(設備名稱 & "_" & 設備地址 & "_" & 是否已配對)   //列表框顯示搜索到的藍牙設備.
    結束 事件
    
    事件 列表框1.表項被單擊(項目索引 為 整數型)            //單擊列表框選擇要通訊的設備.
            變量 設備信息 為 文本型
            變量 文本數組 為 文本型()
            變量 設備地址 為 文本型
            設備信息 = 列表框1.取項目內容(項目索引)
            文本數組 = 分割文本(設備信息,"_")           //可以自定義分隔符,不要與設備名稱重復即可..
            設備地址 = 文本數組(1)
            彈出提示(設備地址)
            藍牙1.連接設備(設備地址)           //連接設備
            彈出提示("正在連接")        
    結束 事件
    
    事件 藍牙1.連接完畢(連接結果 為 邏輯型,設備名稱 為 文本型,設備地址 為 文本型,連接模式 為 整數型)
            如果 連接結果 = 真 則        //已連接設備,關閉列表框顯示.
                    列表框1.可視 = 假
                    主窗口.標題 = "已連接:" & 設備名稱
                    彈出提示("連接成功")
            否則
                    彈出提示("連接失敗")         //連接失敗,可以點擊列表框再次連接.
            結束 如果
    結束 事件
    
    事件 藍牙1.收到數據(數據 為 字節型(),設備名稱 為 文本型,設備地址 為 文本型)    //收到串口數據
            返回值 = 返回值 & 字節到文本(數據,"UTF8")       //累積到文本變量中.
            如果  取文本右邊(返回值,1) = "\n" 則                //發現結束符后開始處理數據.
                判斷 取文本左邊(返回值,取文本長度(返回值)-2)     //去掉回車換行符,
                    分支 "101"                 //滑塊到最大值.
                            水平滑塊條1.位置 = 100
                    分支 "102"                 //滑塊到最小值.
                            水平滑塊條1.位置 = 0
                結束 判斷
                    返回值 = ""        //清空接收字符串,等待下一次接收.
            結束 如果
    
    結束 事件
    
    事件 按鈕1.被單擊()        
            藍牙1.發送數據(文本到字節("101X","UTF8"))      //按鍵1發送.
    結束 事件
    
    事件 按鈕11.被單擊()            //結束按鈕點擊處理.
            藍牙1.發送數據(文本到字節("102X","UTF8"))     //關掉LED.
            藍牙1.斷開連接()            //退出處理,釋放資源,結束內部處理線程
            結束程序()
    結束 事件
    
    
    事件 按鈕2.被單擊()
            藍牙1.發送數據(文本到字節("102X","UTF8"))   //按鍵2發送.
    結束 事件
    
    事件 水平滑塊條1.停止拖動()     //滑塊動作處理.
            變量 數值 為 文本型
            數值 = 整數到文本(水平滑塊條1.位置) & "X"    //添加結束符.
            藍牙1.發送數據(文本到字節(數值,"UTF8"))      //發送滑塊位置數據.
    結束 事件
    


    E4Ad源文件和編譯好的apk文件壓縮包:
    藍牙測試.zip (168.22 KB, 下載次數: 2214)

    該用戶從未簽到

    5#
    發表于 2015-6-17 12:11 | 只看該作者
    贊一個,感謝分享.
  • TA的每日心情
    郁悶
    2016-7-31 12:56
  • 簽到天數: 97 天

    [LV.6]常住居民II

    6#
    發表于 2015-6-21 00:12 | 只看該作者
    我以前也用E4A,E4A沒有OTG組件就不用了。支持一下
  • TA的每日心情
    開心
    2016-12-30 18:38
  • 簽到天數: 8 天

    [LV.3]偶爾看看II

    7#
    發表于 2015-7-5 15:01 | 只看該作者
    本帖最后由 糯米基 于 2015-7-5 15:06 編輯

    非常有用,謝謝樓主了。關于串口,不知樓主有沒有了解softserial,官方有個庫,可以用你的其他引腳來模擬串口{:soso_e100:}
    打賞作者鼓勵一下!
  • TA的每日心情
    郁悶
    2016-3-8 17:06
  • 簽到天數: 13 天

    [LV.3]偶爾看看II

    8#
    發表于 2015-7-6 20:16 | 只看該作者
    感謝分享!不知道樓主對nRF51822熟悉不?我想了解nRF51822接收到指令后,是如何發送給uno的整個過程。

    該用戶從未簽到

    9#
    發表于 2015-7-6 20:49 | 只看該作者
    贊,我也做一下
  • TA的每日心情

    2016-5-22 11:08
  • 簽到天數: 15 天

    [LV.4]偶爾看看III

    10#
    發表于 2015-7-9 16:58 | 只看該作者
    樓主面包板上右邊的那東西是什么呢{:soso_e149:}
    您需要登錄后才可以回帖 登錄 | 立即注冊  

    本版積分規則

    熱門推薦

    arduino實現L298N控制工業步進電機
    arduino實現L298N控制工業
    求助 L298N是ST公司生產的一種高電壓、大電流電機驅動芯片。該芯片采用15腳封裝。主
    arduino IDE錯誤,有點崩潰了,要搞作業!
    arduino IDE錯誤,有點崩
    無論編譯什么程序文件都是這個錯誤!程序自帶例程,最簡單的點亮led燈也是 這個 問題
    【項目】基于Arduino Nano的多功能桌面感應垃圾桶
    【項目】基于Arduino Nano
    基于Arduino Nano的多功能桌面感應垃圾桶隨著大學生活不斷往前邁進,宿舍桌面上的雜物
    在芯間投資成立的零知實驗室發布國內的STM32開源開發板
    在芯間投資成立的零知實驗
    在芯間電子元器件商城成立于2016年,是集電子元器件采購、SMT貼片、PCB打樣、于一
    【原創】全球最小口袋3D打印機mini one直播教程貼
    【原創】全球最小口袋3D打
    最近閑得蛋疼,沒事搞個掌上3D打印機,先放效果圖吧。 搞了半天,終于能正常打印,
    Copyright   ©2015-2016  Arduino中文社區  Powered by©Discuz!   ( 蜀ICP備14017632號-3 )
    快速回復 返回頂部 返回列表
    七星彩综合基本走势图