3.讀取輸入的資料

本篇主要學習如何由序列埠視窗的輸入欄控制Arduino,並且了解如何處理字元字串

對於往後的實作中,是相當基本且重要的學習

例如:

1.隨時輸入角度以調整Servo馬達的角度

2.隨時調整PID運算的kp、kd、ki值

3.隨時輸入變數值

4.接收藍芽模組HC-05 或 HC-06 的回傳指令

5.接收ESP8266 WiFi 回傳的訊息

使用Serial.read();讀取序列埠視窗傳來的數字時

1.會回傳ASC II碼

2.將一個數字一個數字讀取,必須使用字串的方式存取傳來的數字

翻譯ASC II碼,C語言內有幾個重要的函式可以負責。

目前有三個解決方法:

方法一:

先將傳來的數字儲存成字串,再將字串轉換為數字,可透過下表來轉換字串為數字

Serial.readBytes(傳送字串,字元數);

可以用來把傳來的數字存成字串,

再透過轉換函數 atoi(字串); 的數字部分轉換

char cmd[9] ;

void setup(){

Serial.begin(9600);

Serial.setTimeout(10); // 設定為每10毫秒結束一次讀取(數字愈小愈快)

}

void loop(){

if(Serial.available()){

Serial.readBytes(cmd,9);

Serial.println(atoi(cmd));

}

}

若上傳上列程式碼,輸入後所見即所得,代表輸入的數字可以即時進入程式碼中運算

也可以把輸入的數字存成變數 int x = atoi(cmd); 或 float y = atof(cmd);

[實例一]

若攝氏溫度轉換為華氏的轉換公式為:

F=0.6xC+32

我們可以把程式碼改寫成

(因為輸入可能為小數,故用 atof() 函數 )

char cmd[9] ;

void setup(){

Serial.begin(9600);

Serial.setTimeout(10); // 設定為每10毫秒結束一次讀取(數字愈小愈快)

}

void loop(){

if(Serial.available()){

Serial.readBytes(cmd,9);

Serial.println(atof(cmd)*0.6+32);

}

}

上傳看看,試著輸入幾個攝氏溫度,看看回傳的華氏溫度

方法二:

利用Serial.parseInt(); 函式傳送整數

利用Serial.parseFloat(); 函式傳送小數

這個方法是直接從電腦傳來的資料中攔截整數或小數的部分,自動省略字母

輸入12、13、14、15、16、23、24 之後回傳如下圖

發現每個輸入的數字下方都會有個0,作為輸入結束的代碼

我們只要第一個數字,並且避開回傳的0,所以我們先上傳這段程式碼,

研究一下資料是如何傳遞的:

int i = 0 ;

void setup(){

Serial.begin(9600);

Serial.setTimeout(10); // 設定為每10毫秒結束一次讀取(數字愈小愈快)

}

void loop(){

if(Serial.available()){

int x = Serial.parseInt();

Serial.print(i);

Serial.print(" , ");

Serial.println(x);

i++;

}

}

以上程式碼是為了要探索輸入的"12"與中止碼"0"是不是同一次讀到的

由上圖可知,若輸入12,在第0個迴圈內讀到,而終止碼0則在下一個迴圈讀到,

以下類推,若知道資料是這樣回傳的,那我們可以進一步改寫程式碼如下:

int x,y;

void setup(){

Serial.begin(9600);

Serial.setTimeout(10); // 設定為每10毫秒結束一次讀取(數字愈小愈快)

}

void loop(){

while(Serial.available()){

x = Serial.parseInt();

y = Serial.parseInt();

}

Serial.print(x); // 這邊的x就是我們輸入的值

Serial.print(" , ");

Serial.println(y); //這邊的y就是回傳的中止碼0

}

其中的while()迴圈,當序列埠有資料傳入就重複讀取數值,

直到沒有資料傳入才跳出while迴圈;

[實例一]

若攝氏溫度轉換為華氏的轉換公式為:

F=0.6xC+32

我們可以把程式碼改寫成

int x,y;

void setup(){

Serial.begin(9600);

Serial.setTimeout(10); // 設定為每10毫秒結束一次讀取(數字愈小愈快)

}

void loop(){

while(Serial.available()){

x = Serial.parseFloat();

y = Serial.parseInt();

}

Serial.println(x*0.6+32); // 這邊的x就是我們輸入的值

}

[實例二] 控制Servo 角度

可在序列埠視窗輸入角度,輸入後即可控制伺服馬達的角度

#include <Servo.h>

Servo servo;

int x,y;

void setup(){

Serial.begin(9600);

Serial.setTimeout(10); // 設定為每10毫秒結束一次讀取(數字愈小愈快)

servo.attach(9);

}

void loop(){

while(Serial.available()){

x = Serial.parseInt();

y = Serial.parseInt();

}

Serial.print(x);

Serial.print(" , ");

Serial.println(y);

servo.write(x);

delay(100);

}

方法三:

1.本方法將Serial傳來的文字儲存成字串(String) cmd,

2.因為傳來的是ASC II碼,所以需要減48轉換成數字,

3.利用 += 累加字串內容

4.負數將會使傳來的前兩位為-3,例如輸入-12,會變成-312,故把字串的第二個字元換成0

5.將字串變成整數的方法: 字串名稱.toInt();

String num = "" ;

int i = 0 ;

long cmd ;

void setup(){

Serial.begin(115200);

Serial.setTimeout(10); // 設定為每10毫秒結束一次讀取(數字愈小愈快)

}

void loop(){

command();

Serial.println(cmd);

}

long command(){

while(Serial.available()){

if(i==0){

num = "";

}

num += Serial.read()-48; // -48是要將ASC II 碼轉換為數字

i++;

}

cmd = num.toInt();

if(cmd<0){

num.setCharAt(1,'0'); //將字串的第二個位置(字元是3)轉換為0

cmd = num.toInt();

}

i=0 ;

delay(50);

}

結論

上面介紹的各種方法,皆是把輸入的數字儲存成變數(未知數),

只要把變數帶入我們想要計算的方程式中,就可以做出調整的效果

如果要搭配控制多個電器(例如servo),可以搭配編碼的技巧

觀察身分證號碼

A123456789 => A代表出生地 1代表男生

我們可以學習這種編碼的方式

把多個馬達的編碼一下 XXOOO (XX代表馬達編號,OOO代表角度)

01090 =>第一個馬達轉到90度

13045=>第13個馬達轉到45度

這樣就可以實現一次控制多個馬達