Arduino序列埠通訊程式Serial.read()讀取到 ÿ 字元的補充說明

本文旨在補充《超圖解Arduino互動設計入門》第五章「序列埠通訊程式」,以及第十章「透過序列埠調整燈光亮度」的讀取序列埠值。動手做10-3與10-4的程式碼,都有一個判斷傳入值是介於’0’~’9’的條件式,例如,底下是diy10_4.ino的程式片段:

將此上傳程式到Arduino,再開啟「序列埠監控視窗」,並輸入"123″字串,將能看到Arduino接收到完整的數字123:

Arduino的序列埠監控視窗

若修改程式碼,刪除「確認輸入的字元介於’0’和’9’」的判斷條件:

再度測試程式碼,Arduino都只能收到第一個字元。

Arduino的序列埠監控視窗

這是因為當程式察覺到有序列資料進入時,就開始連續讀取三個字元。可是,序列資料的傳入速度遠不及程式迴圈的執行速度,所以存入data陣列的第2和第3個元素值都是-1(代表序列埠沒有輸入值)

Arduino的Serial序列埠程式庫,接收字元的流程。

因此,上面的程式碼必須加入判斷條件;除了篩選出數字之外,還可以用排除 -1 的方式,像這樣:

補充說明,-1的字元值會在「序列埠監控視窗」顯示成 ‘ÿ’。所以,假如序列埠監控視窗顯示出 ‘ÿ’ 字元,可能需要檢查序列通訊程式是否有正確收到資料。

31 thoughts on “Arduino序列埠通訊程式Serial.read()讀取到 ÿ 字元的補充說明

  1. 請問老師,在超圖解Arduino 互動設計入門(第二版),有關於IRremote.h 的使用,範例12-2 中的編繹過程有個問題
    IRrecv irrecv(RECV_PIN); 顯示"IRrecv" does not name a type. 以及以下描述:
    diy12_2.ino: In function ‘void loop()’:
    diy12_2:17: error: ‘irrecv’ was not declared in this scope
    diy12_2:17: error: ‘results’ was not declared in this scope

    請問,這個問題原因在那裡? 謝謝.

    1. hi john:

      請先把光碟「程式庫」資料夾裡的"IRremote"資料夾,複製到Arduino安裝路徑裡的"libraries"資料夾,或者「我的文件」裡的"Arduino\libraries"路徑。

      以後開啟Arduino軟體,就能正確編譯程式了。

      thanks,
      jeffrey

    1. hi eli:

      arduino軟體內建的「序列埠監控視窗」其實是一個序列埠通訊程式,你可以用其他序列埠通訊軟體取代,例如:AccessPort和CoolTerm,只要序列通訊協議(如:傳輸速率)一致即可。

      thanks,
      jeffrey

  2. 趙老師您好:
    請問Arduino的A0~A5,能當示波器一樣,讀入sin波的訊號嗎?還是只能讀入一般直流電的訊號,因為我拿來接信號產生器,讀出來的數值都是正值! 沒辦法讀出負半週期的值! 謝謝!

    1. hi jenson:

      Arduino的類比輸入埠預設只能接受0~5V的訊號,超過這個範圍的類比訊號(含負值),都要先經過額外的電路,將訊號縮限在0~5V之內。最基本的方法是採用電阻分壓,請先參閱:

      • 6-6頁,電阻分壓
      • 6-14頁,運算放大器的偏壓電路

      我週一或週二再補充說明。

      thanks,
      jeffrey

    2. 假設輸入的類比訊號電壓介於-10V和10V之間,連接Arduino控制板時,要先經過以下的電阻分壓電路,將訊號電壓限制在0~5V之內:

      電阻分壓電路

      經過電阻分壓之後,輸入Arduino的電壓值會降低,而且會低於Arduino的工作電壓(5V)。

      假設我們預期的最高輸入值是4V,R1, R2和R3電阻值的計算方式如下:當輸入訊號為負電位時,電流將朝R1和R2方向流動,不會經過R3,因為「接地」的電位高於「負電位」。

      電阻分壓,負電位。

      所以R1和R2將構成分壓電路,Arduino的類比輸入埠將檢測到0V。為了方便計算,取R2為1KΩ,我們先求取最大負電壓的分壓電阻值,從底下的算式得知R1值為400Ω:

      計算R1電阻值

      當輸入訊號高於5V時,將不會有電流流過R1,此時R2和R3形成分壓電路:

      電阻分壓電路,正電位。

      從底下的算式得知R1值約670Ω:

      計算R3電阻值

      如果你需要放大輸入的類比訊號電壓,可使用運算放大器,詳細請參閱書本6-14頁,運算放大器的偏壓電路

      thanks,
      jeffrey

  3. 老師您好,我想詢問直接將數字經由序列埠傳達給arduino在如何撰寫呢??我設定的數字是溫度值0~30度,但我如何傳達數字給arduino??請老師協助

    1. hi yuan:

      10-10頁「動手做10-3:透過序列埠調整燈光亮度」的程式碼,就能符合你需求,請自行修改程式。

      thanks,
      jeffrey

  4. 趙老師你好!我參照老師新版的ARDUINO超圖解互動設計入門2的第5-18頁
    我程式碼打跟上面完全一樣,但打開序列負監控視窗都沒有任何訊息,按下Reset鍵也是一樣
    我的版子是OZONE的,但應該也是可以用吧,我一直找不到原因,請老師協助!

    1. 你的控制板是Leonardo相容板,請在初始化序列埠敘述之後,加入底下的while迴圈試試看:

      thanks,
      jeffrey

  5. 老師您好,我目前使用Arduino MEGA 2560,想透過電腦傳訊息(經由Serial)控制Arduino,在由Arduino傳同樣的訊息(經由Serial1)控制其他模組,但是我遇到問題了!
    電腦控制Arduino沒問題,但是Arduino沒辦法經由(Serial1)傳遞同樣的訊息給其他模組,執行過Serial1.write(“有字元")後,Serial1.available()一直回傳"0″,導致Serial1.read()持續回傳"-1″,請問這大概是甚麼問題呢?是我對Serial1.write()不夠了解嗎?
    抱歉問題有點長和模糊,但困擾我很久了,希望老師能解惑,謝謝!

    1. hi andy:

      根據你的描述,你有兩個Arduino控制板,分別是A和B;電腦接A,A的Serial1(18和19腳)接B的Serial1(19和18腳),在A上執行Serial1.write(),但是B的Serial1.read()始終讀不到資料?請問你的接線正確嗎?

      thanks,
      jeffrey

    2. 老師您好,謝謝您的回覆,我目前是用USB控制Arduino,Arduino上有外接一個無線通訊晶片(從18and19接線),想測試從電腦上直接下命令(AT command),看看Arduino上的外接無線通訊晶片有沒有回應,不是有兩塊Arduino,不知道這樣敘述夠不夠清楚,謝謝老師!!

    3. 謝謝老師!我想我發現程式碼中的問題了!
      想順便請問老師,我有購買Arduino 互動設計入門第二版,請問書裡面有沒有Serial.write()的相關章節呢?
      或是更詳細的Serial函數教學(除了第五章"序列埠通信"之外),再次謝謝老師熱心回應!

    4. Serial.write()和Serial.print()的主要差異是print()會將輸入的數字或文字都轉換成字元,而write()則會把數字轉換成對應的ASCII字元。

      例如:
      Serial.print(65); // 輸出’6’和’5′
      Serial.write(65); // 輸出’A’

      thanks,
      jeffrey

  6. 老師你好,我之前想透過監控視窗顯示從0.0上升到1.0、再從1.0下降到0.0
    程式碼是:
    double brightness = 0.0;
    double fade = 0.1;

    void setup() {
    Serial.begin(9600);
    }

    void loop() {
    Serial.println(brightness);
    brightness = brightness + fade;
    if(brightness == 0.0 || brightness == 1.0)fade = -fade;
    }

    我試過把double改成int,小數改為整數就可以運作正常,但不知道為什麼小數就只會一直加上去,完全不理if的條件…請老師幫忙解惑!!

    1. hi yen:

      浮點數運算經常會遇到精確度的問題,以你的需求來說,最簡單的解決方法是先用整數運算,再換算成浮點數:

      thanks,
      jeffrey

    2. 簡單的說,十進位的小數部份轉換成二進位,要不斷地乘以2,直到小數部份為0;0.1轉成二進位會變成無限循環的數字,但電腦的記憶體容量有限,無法表示無限長度的數字,所以會出現誤差。詳細請參閱冼鏡光老師的「使用浮點數最最基本的觀念」這篇文章說明。

      thanks,
      jeffrey

  7. 老師您好,我想用Arduino來取代示波器讀取電路中訊號的頻率(300kHz附近),是否是如您上面回答,用分壓電路的方法使訊號限制在0-5V,再計數讀到最大值(1023)n次的時間t,然後得到頻率為n/t。不知道這樣的想法是否正確,還是有其他方法?

  8. 老師您好
    我是德明的學生 想請問您
    我用RN131當作wifi module
    之後用android寫了一個socket按按鈕回傳數字
    rn131跟 手機都接上熱點 而rn131也接上了arduino
    但我不知道arduino要寫什麼才能收到回傳的數字
    煩請老師解答了!!

    1. hi DanYiChen:

      我猜想你的Android程式不是採用HTTP協定,請參考Arduino IDE軟體 “檔案 > 範例 > Ethernet > Telnet Client" 範例中的loop()迴圈程式寫法。

      thanks,
      jeffrey

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *