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度
這樣就可以實現一次控制多個馬達