arduino 官網 arduino uno

Arduino 物聯網應用 - 上課教材

動畫互動網頁程式設計 > 課程內容 > 第 02 章 -初步了解 arduino IDE 基本語法

第 02 章 -初步了解 arduino IDE 基本語法

上次更新日期 2022/09/14

上一章我們知道如何處理 arduino 與 IDE 整合開發環境的連結,也大致知道怎麼將程式碼燒錄到 arduino 上頭! 接下來,我們就先來玩一玩 arduino 開發環境的基本程式吧!不過,在搞定基本程式碼的運作之前, 可能需要了解一下透過 USB 的連接埠訊息傳遞方式,這樣才有辦法將 arduino 的輸出『互動』的傳送到 IDE 環境中。

學習目標:

  1. 應用 USB serial connection 方式傳輸訊息
  2. 了解變數的設定與使用
  3. 了解流程控制 (if) 與迴圈 (for, while) 的應用
  4. 使用自訂函數的功能
  5. 由序列埠讀入資料,並加以判斷使用
  6. 資料型別的轉換功能

2.1: 了解 USB 序列埠連接訊息傳遞方式

前一章我們已經大致了解如何燒錄程式到 arduino 上面,現在,讓我們來學習一下在 arduino IDE 上面的基本語法。 基本上,IDE 的語法是從 C 修改來的,而之前學的 PHP 也是有點 C 的影子,因此,同學們可能會覺得, 底下的語法都會有點似曾相似的感覺喔!無論如何,讓我們來學習學習!

不過,跟一般 PC 不一樣,一般 PC 已經設計好,所有的輸出,大致上都是從顯示卡傳送到螢幕來顯示, arduino 只是簡簡單單的一塊板子,原本就沒有接顯示卡...所以,如果你要取得從 arduino 來的訊號, 就得要先了解怎麼讓這些訊息透過 USB 傳送/接收到 arduino IDE 開發軟體中!

  • 使用 Serial 函數

arduino 與 IDE 開發軟體之間的傳輸,最簡單的方法當然就是透過那條原本的 USB 傳輸線!在 arduino 裡面, 可以透過已經撰寫好的 Serial (注意大小寫) 函數來處理!而一開始要處理的,就是 arduino 與 IDE 之間的傳輸速率, 或稱為鮑率 (baud rate)。想像一下,你在大隊接力的時候,最終接棒時,傳棒與接棒的人,速度應該要一致才好! 後面的人太快就會撞在一起,前面的人太快就會無法接棒!所以在接棒區,應該速度要一致!同樣的道理, 你的 arduino 硬體與 IDE 軟體之間傳輸的速率 (鮑率) 也要相同,否則傳輸就會出問題!

現在,接上你的 arduino 到 USB 上,然後打開 IDE 軟體之後,點選小按鈕列最右邊的『序列埠監控視窗』, 或者透過『工具』、『序列埠監控視窗』來打開也行!打開之後,觀察一下右下角的按鈕,你會看到類似如下的畫面:

序列埠監控視窗

如上圖所示,你可以額外勾選『Show timestamp』項目,然後觀察一下傳輸速率,預設大部分都是 9600 baud, 這個鮑率在文末的維基百科解釋,其實是每秒鐘傳輸的符號資料量,再次強調,arduino 與 IDE 軟體,這兩者要相同比較好。 因為 IDE 軟體預設使用 9600 baud,那我們等等在 arduino 『初始化序列埠傳輸速率』時,也指定 9600 這樣即可。 指定的方法為,在 setup() 函數內,使用 Serial.begin(9600); 就好了!

現在,請打開 IDE 開發軟體,新增一個新的專案,然後處理序列埠的傳輸速率,有點像這樣:

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

那如何將資料透過 USB 序列埠回傳到 IDE 的監控視窗當中呢?可以透過幾個常見的函數:

  • Serial.print(資料);
    可以是字串("字串")、數值(38.38)、十進位轉為二進位的數值(38,BIN),這個資料之間是相連的,不會主動斷行, 斷行可以加 ("\n") 處理。至於字串資料,建議使用雙引號來處理!
  • Serial.println(資料);
    與 Serial.print 類似,只是資料結尾會主動加上斷行字元而已
  • Serial.write(資料);
    可以直接輸出字串 ("字串"),如果填寫數值時,則會輸出該數值代表的 ASCII 符號!

根據上面的說明,看起來還是 Serial.print 比較常用!當然,要主動斷行,直接使用 Serial.println 也是可以的。 現在,讓我們撰寫第一支自己寫的程式,讓 arduino 每 2 秒鐘輸出一次 hello Arduino 吧!這樣寫即可:

void setup() {
  Serial.begin(9600);
}
void loop() {
  Serial.print('hello Arduino\n');
  delay(2000);
}

寫完之後,請先自己編譯看看,按下編譯之後,系統會先要求你要儲存這個專案,如果不想寫專案名稱, 直接按下 enter 也沒關係。不過為了未來好管理,給個適當的專案檔名會比較好。因此,鳥哥這裡選擇使用 code-hello 作為專案的檔名囉。之後系統會經過一陣子的編譯,最終在左下角告知編譯的結果,如下圖所示:

第一支自己寫的 hello 程式

如果一切順利,現在你有 IDE 的軟體、COM4 的監控視窗、已經插上 USB 連結到主機的 arduino,現在, 請將這個程式碼上傳到 arduino 上吧!燒錄完畢之後,你的 arduino 就會立刻處理這隻程式碼,然後,就會看到類似如下的畫面:

第一支自己寫的 hello 程式

現在,去看一下工作中的 arduino nano,你會發現到每 2 秒鐘,那個 TX 的 LED 燈光會小小的閃光一次! TX 指的是傳送,因此,有傳送資料時,這個燈號就會閃爍!可以看得到吧!有閃爍的燈光喔!有趣吧!

2.2: 變數的宣告與運算子

在 arduino 裡面,使用變數還是很不錯的!變數要使用之前,最好先宣告,而變數的類型有底下幾種:

資料型態佔用位元數資料範圍
boolean (布林值)8true(定義!=0), false(定義=0)
char (字元)8-128~+128
unsigned char (不帶符號字元)80~255(沒有前導字元的符號)
int (整數)16-32768~+32768
unsigned int (不帶符號整數)160~65535
long (長整數)32-2147483648~+2147483648
float (小數,浮點數)32-3.4028235E+38~+3.4028235E+38
double (倍精數)32-3.4028235E+38~+3.4028235E+38
String (字串)不固定得要雙引號 "字串" 來引用
  • char 字元、字串變數的宣告

比較需要注意的是, char 為字元宣告,其實就是 ASCII 字元編碼的概念~不過,如果後面的值使用雙引號時, 該資料就會變成字串了!這個要特別注意!亦即是:

char str1 = 'a';            // 宣告為字元 a
char str2[] = "arduino";    // 宣告為一個字串 arduino
String str3 = "ARDUINO";    // 直接宣告為字串 ARDUINO

根據 arduino 官網 (請參考文末資料) 的解釋,因為 char 預設僅花 8 位元 (bit),亦即一個位元組 (byte) 做儲存, 所以,當你的資料超過一個字元時,甚至是一個字就佔用 2~3 個位元組的中文字,那 char 當然無法儲存! 就會變成空白了!所以,你需要額外開放一個空的、可以隨意填入資料的字串時,就需要在變數後面使用中括號 [] 加入位元數。 例如 str[16] 代表使用 16 位元 (兩個位元組) 進行儲存資料。如果不填寫數值,那就代表 arduino 編譯器會主動根據資料, 幫你計算足夠的位元數了!

你可能不懂差異在哪裡!沒關係,我們來指定一下輸出,你就知道了。假設 str1 與 str2 都要定義 arduino 這個字串內容, 如果沒有指定額外的儲存容量,看看會發生什麼事。請開啟新的專案,然後將專案名稱取為 code-char,輸入底下的資料:

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

void loop() {
  char str1   = "arduino";
  char str2[] = "arduino";
  String str3 = "ARDUINO";
  Serial.print("str1 = ");
  Serial.println(str1);
  Serial.print("str2 = ");
  Serial.println(str2);
  Serial.print("str3 = ");
  Serial.println(str3);
  delay(2000);
}

儲存後,上傳燒錄到 arduino 裡面,運作的結果會有點像底下這樣:

字串宣告的差異

很明顯的發現到,有額外提供儲存空間的 str2 才會正確顯示資料,預設使用一個位元組儲存資料的 str1 就會變成空白! 這就是差異!要注意!要注意!一般來說,單純使用字串的話,還是透過 String 來宣告會比較單純!因為 String 為可變儲存長度, char 必須要固定長度!在使用上 String 對於字串還是相對友善的!

  • 常見宣告方式

底下稍微說明一下,常見的變數宣告方式:

  int myvar = 100;                   // 宣告一個整數,且數值為 100
  int myi, myj, myk;                 // 宣告三個整數變數,不給初始值
  float myf1 = 3.14159;              // 宣告一個浮點數,並給予數值 3.14159
  String mystr[] = "hello arduino";  // 宣告一個字串變數,內容為 hello arduino
  • 算術運算子

常見的運算子就是在數值之間進行加減乘除的符號,常見的符號有底下這些:

運算子行為範本說明
+加法x+y兩者相加
-減法x-y兩者相減
*乘法x*y兩者相乘
/除法x/y兩者相除
%整數取餘數x%yx除以y的餘數
++遞增x++相當於 x=x+1
--遞減x--相當於 x=x-1

我們讓 arduino 笨笨的去算一下球體的體積~設計變數,然後帶入公式: V=(4/3)*π*r3, 其中 V 為體積, r 為球體的半徑。先自己設計一下,然後在嘗試輸出看看。現在,請在開新的專案, 專案名稱取 code-ball 看看!

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

void loop() {
  float V;
  float r = 5.0;
  V = 4/3*3.14159*r*r*r;
  Serial.print("半徑為");
  Serial.print(r);
  Serial.print("的球體的體積是: ");
  Serial.println(V);
  delay(2000);
}
球體的體積計算

執行成果如上圖所示。你會發現到,預設的 float 浮點數的輸出,應該就是兩位數!問題是,如果你想要輸出較長的小數點位數, 就得要透過特殊的寫法!將上面的 V 的輸出改成這樣就好:

  Serial.println(V, 4);   // 代表浮點數後面接 4 個小數點位數!

然後重新編譯、上傳到 arduino 之後,輸出的體積就會是小數點後 4 位的輸出了!查詢看看呦!

  • 變數型態轉換、全域與區域變數

常見的變數型態轉換如下:

  String(var);
  char(var);
  var.toInt()
  var.toFloat();

另外,變數存在的區間是很特別的!有的變數可以在任何函數內存在,有的變數則只在某個函數內存在!以底下的案例來說:

int mypi = 3.14;
void setup() {
   ....
 }
void loop() {
   char mystr[] = 'arduino';
   ....
   float Q = mypi * r * r;
 }
void fun() {
   ....
 }

上面的 mypi 就是全域變數,這個變數可以在其他的函數 (loop()) 內存在!但是,那個 mystr[] 的字串變數, 就只有在 loop() 裡面才能夠有值,其他的函數內就預設沒有這個變數!這就是區域變數!

  • 關係運算子

數值之間是可以比較大小的,當然,我們也可以抓字串是否為某個單字!這就是兩個變數之間的關係,就是關係運算子。 常見的關係運算子,可能要在流程控制裡面才會用到,我們這裡只是先提出來討論討論囉!

運算子行為範本說明
==等於x==y若 x 與 y 相同,則為 true,否則是 false
!=不等於x!=y若 x 與 y 不相同,則為 true,否則是 false
>大於x>y若 x 大於 y ,則為 true,否則是 false
<小於x<y若 x 小於 y ,則為 true,否則是 false
>=大於等於x>=y若 x 大於等於 y ,則為 true,否則是 false
<=小於小於x<=y若 x 小於等於 y ,則為 true,否則是 false

基本上,用到這些關係運算子,通常用在比較上面,就得要使用 if 或者是 while 等需要判斷真或假 (true, false) 的情境下。 一般簡單運算倒是不會使用這些比較的運算子!

  • 數值運算與輸出

數值運算相對簡單!我們先說說怎麼計算 BMI 好了!BMI 的公式是『體重/身高2』,單位是公斤與公尺。 現在,讓我們來處理 BMI 輸出的問題!

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

void loop() {
  float myh = 1.76;
  float myw = 68.0;
  float mybmi = myw / myh / myh;
  Serial.print("身高: ");
  Serial.println(myh);
  Serial.print("體重: ");
  Serial.println(myw);
  Serial.print("BMI: ");
  Serial.println(mybmi);
  delay(2000);
}

上述檔名就稱為 code-bmi 好了!儲存、編譯、上傳,你就會看到你的 BMI 資料了!

2.3: 流程控制 if 與 switch

基本上,程式語法一定會學到的,就是流程控制與迴圈。這裡先談談流程控制。一般來說,使用 if (如果) 來進行流程控制! 一般基本語法如下:

void setup() {
  ....
}

void loop() {
  if ( 條件判斷 ) {
    ....
  }
}

不過,如果你的判斷結束後,只需要一條指令的回應,那可以簡化成這樣:

void setup() {
  ....
}

void loop() {
  if ( 條件判斷 ) 
    ....
}

基本上,就是大括號不見了而已!不是太困難! 另外,條件判斷除了比較之外,如果有兩個以上的條件判斷,可以透過底下的邏輯運算子來處理:

運算子行為範本說明
&&andx==y && a==b兩者皆為 true 才是 true,否則是 false
||orx==y || a==b其中一個是 true 就是 true,否則是 false

我們知道 BMI 在 18.5 到 24 之間是體重正常,其他則是不正常。如果我只想要知道『正常』與否,那可以這樣處理 code-bmi-s1 這個情況:

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

void loop() {
  float myh = 1.76;
  float myw = 68.0;
  float mybmi = myw / myh / myh;
  String mycheck = "體重不是很正常喔!";
  if ( mybmi > 18.5 && mybmi < 24 ) 
    mycheck = "體重正常" ;
  Serial.print("身高: ");
  Serial.println(myh);
  Serial.print("體重: ");
  Serial.println(myw);
  Serial.print("BMI: ");
  Serial.println(mybmi);
  Serial.print("體重狀況: ");
  Serial.println(mycheck);
  delay(2000);
}

因為只有一個變數需要重新設定而已,所以,就沒有加上大括號在 if 後面。而且因為是雙重判斷,因此, 就得要兩個同時成立 (大於 18.5 與小於 24 要同時成立)!使用的就是 && 囉!那,如果還有其他需要判斷的, 就得要使用 if ... else .. 或者是 if ... else if ... else if ... else 之類的語法!例如:

void loop() {
  if (條件判斷) {
    ....
  } else if {
    ....
  } else {
    ....
  }
} 

現在,讓我們來將 code-bmi-s1 重新改寫一下 成為 code-bmi-s2,計算出 BMI 之後, 根據底下的數據,來判斷你的 BMI 狀態:

  • BMI < 18.5 :過輕
  • 18.5 < BMI < 24 :正常!
  • 24 < BMI < 27 :偏重
  • 27 < BMI < 30 :輕度肥胖
  • 30 < BMI < 35 :中度肥胖
  • BMI > 35 :重度肥胖
  String mycheck ;
  if ( mybmi < 18.5 ) {
    mycheck = "有點太輕";
  } else if ( mybmi < 24 ) {
    mycheck = "體重狀況不錯";
  } else if ( mybmi < 27 ) {
    mycheck = "有點偏重,注意飲食";
  } else if ( mybmi < 30 ) {
    mycheck = "輕度肥胖";
  } else if ( mybmi < 35 ) {
    mycheck = "中度肥胖";
  } else if ( mybmi >= 35 ) {
    mycheck = "重度肥胖";
  }
  • 使用 switch 固定變數內容

使用 if 通常用來判斷不確定的變數內容,例如上面的 BMI 數值。有的時候,你可能只有 3, 4 個選項可以選, 那就可以透過 switch 來進行處理即可。大概是這樣:

switch (變數名稱) {
  case 變數值-1 : {
    ....;
  }
  break;
  case 變數值-2 : {
    ....;
  }
  break;
  ....
  default: {
    ....;
  } 
}

每個環節就是由 case...break 之間組成,最後,如果變數的值不在規範的範圍內,就使用 default (預設值) 來處理。 假設未來我們要偵測腳位是否有電,有就是 1,沒有就是 0,不是 1 也不是 0 就顯示不知道!那可以透過簡單的 switch 來處理也可以! 檔名可以取為 code-switch 喔!

void loop() {
  int mypw = 3;  // 分別帶入 0, 1, 2 再上傳看看
  String mycheck;
  switch (mypw) {
    case 1: {
      mycheck = "有電有電!是 ON 的!";
    }
    break;
    case 0: {
      mycheck = "停電狀態是 OFF 啦";
    }
    break;
    default: {
      mycheck = "目前是莫名其妙的狀態";
    }
  }
  Serial.println("狀態是: " + mycheck);
  delay(2000);
}

2.4: 迴圈控制

迴圈控制主要有三種情況,第一種是使用 for 的固定迴圈數,第二種透過 while 指定條件成立才進行, 第三種則是使用 do ... while 至少進行過一次再做條件判斷的迴圈。先來看看 for 迴圈的用法:

for (起始值; 結束條件; 數值步階) {
  ....
}

假設我要從 arduino 裡面輸出 99 乘法表,那可以這樣做看看:程式檔名就是 code-nine 好了

void loop() {
  int i, j;
  String out;
  for ( i=1; i<=9; i++ ) {
    for ( j=1; j<=9; j++ ) {
      out = String(i) + " * " + String(j) + " = " + String(i*j);
      Serial.println(out);
    }
    delay(1000);
  }
  delay(2000);
}

我想要簡化輸出,所以,直接使用 String 改變變數型態,這樣就可以進行字串的累加了!比較方便一點! 上面這種透過確認固定數值範圍的迴圈,通常就是使用 for 迴圈。

  • 使用 while 進行迴圈

while 迴圈的使用方式有點像這樣:

while (條件判斷) {
  ....
}

當 (條件判斷) 為 true 時,就會進行迴圈~否則就脫離迴圈。讓我們來做個練習。當你要初始化一個遊戲人物時, 假設有體力、魔力與戰鬥力三種數值,這三個數值都可能由亂數產生 10~50 之間的數字,但是三個數值最大只能到 100 而已。 使用 random(最小,最大) 可以產生範圍內的整數,例如 random(1,11) 可以產生 1~10 的整數。那該如何處理?

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("開始計算體力、魔力與戰鬥力");
  int myhp, mymp, mypw;
  bool check = true;
  while (check) {
    myhp = random(10,50);
    mymp = random(10,50);
    mypw = 100 - myhp - mymp;
    if (mypw > 10 && mypw < 50) 
      check = false;  // 計算成功,就離開 while 迴圈囉!
  }
  Serial.println("體力值: " + String(myhp));
  Serial.println("魔力值: " + String(mymp));
  Serial.println("戰鬥力: " + String(mypw));
  delay(5000);
}
  • 使用 do while 迴圈

使用 do while 迴圈的語法有點像這樣:

do {
  ....
  ....
} while (條件判斷)

這裡就不多說了!自己找範例玩一玩~

2.5: 自訂函數

整個 arduino 至少需要兩個函數,一個是初始化的 setup() 函數,另一個則是 loop() 函數。那我們可以自訂函數嘛? 當然是可以的!函數的定義基本上是這樣:

數值型態 函數名稱(外帶參數){ .... }

int sum(int x, int y) {
  ....
}

有個簡單的範例,如果你要算地球的平均週長、平均表面積、平均體積的話,可以使用地球的平均半徑 6371 公里來計算! 至於球體的相關計算資料如下:

  • 假設球體的半徑為 r
  • 球體的週長會是: 2πr
  • 球體的表面積會是: 4πr2
  • 球體的體積會是: (4/3)πr3

現在,依據自訂函數的功能,請自訂三個函數,分別是 perimeter, surface, volume 三個,並外帶浮點數變數 r 來處理, 檔名取為 code-earth 好了!

float pi = 3.14159;

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

void loop() {
  float r = 6371.0;
  float res1 = perimeter(r);
  float res2 = surface(r);
  float res3 = volume(r);
  Serial.println("地球平均週長: " + String(res1));
  Serial.println("地球平均表面積: " + String(res2));
  Serial.println("地球平均體積: " + String(res3));
  delay(5000);
}

float perimeter(float r) {
  float res = 2 * pi * r;
  return(res);
}
float surface(float r) {
  float res = 4 * pi * r * r ;
  return(res);
}
float volume(float r) {
  float res = (4/3) * pi * r * r * r;
  return(res);
}

如上,你就可以指定三個函數來進行各個相關的任務!要注意喔,那個 return 可以回傳數值~而不只是執行過程而已! 這個在自訂函數上面相當有用!

2.6: 陣列

許多資料整合在一起還是比較方便!這就得要用到陣列了!一般數值陣列宣告的方法有點像這樣:

int x[5] = { 1, 2, 3, 4, 5};
// x[0] = 1;
// x[1] = 2;
// x[4] = 5;

宣告時,變數後面的中括號可以加入陣列的個數,不過,一定要加入陣列個數才行!個數不會自動累加,這個跟其他語言可能不太一樣。 我們參考上面的 code-earth 腳本,另行製作 code-earth-f1,統一使用 earth 函數,並且回傳一個陣列~該陣列就依照週長、表面積、體積來設計! 不過,由於陣列在記憶體的分配上面比較困擾,你不能在函數之內回傳陣列再分配給陣列。因此,最簡單的方式,就是 (1)先將陣列宣告成為全域變數; (2)透過函數加星號 (*) 來執行,這樣就可以讓陣列內容在自訂函數內改變!並直接帶入到 loop() 主函數內!可以這樣參考看看:

float pi = 3.14159;
float res[3];

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

void loop() {
  float r = 6371.0;
  earth(r);
  Serial.println("地球平均週長: " + String(res[0]));
  Serial.println("地球平均表面積: " + String(res[1]));
  Serial.println("地球平均體積: " + String(res[2]));
  delay(5000);
}

float *earth(float r) {
  res[0] = 2 * pi * r;
  res[1] = 4 * pi * r * r ;
  res[2] = (4/3) * pi * r * r * r;
  return res;
}

如果要使用二維陣列,就得要用到類似如下的作法了:

int array[3][3] = { {...}, {...}, {...} }

2.7: 跟序列埠互動

跟網頁差不多,我們是可以透過序列埠輸入資料給 arduino 處理的!舉例來說,輸入身高體重來計算 BMI 這樣。 讀入資料有很多種格式,這裡介紹一個通用的,就是透過 Serial.readString() 來一次性讀入從序列埠傳來的資料。 不過,預設的情況下,讀入的資料會自動加上斷行,因此,可以透過 trim() 函數來將字串前、後空白去除的功能!

  • Serial.readString()
    從序列埠讀入資料,資料型態為字串喔!
  • str.trim() 將字串 str 的前後空白刪除!

讓我們讀入一個字串好了!檔名設定為 code-read-string ,內容很簡單,當可以讀取來自序列埠的資料時, 就將資料列印出來!

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

void loop() {
  String mystr = Serial.readString();
  mystr.trim();
  if ( mystr != "" ) {
     Serial.println("讀到的字串是 ==> " + mystr);
  }
  delay(2000);
}

接下來,讓我們來讓使用者輸入身高與體重,然後讓 arduino 計算 BMI。不過要注意的是, 序列埠一次只能輸入一串資料,但是我們需要身高與體重,因此需要輸入兩次才行!所以,這過程我們就需要透過類似 while 的功能, 判斷使用者輸入的資料是否正常?可以進行的內容有點像這樣:

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

void loop() {
  
  int myh = 0;
  Serial.println("請輸入身高,單位是公分");
  while ( myh <= 0 || myh >= 300 ) {
    String mystr = Serial.readString();
    mystr.trim();
    if ( mystr != "" ) {
      Serial.println("輸入的身高是: " + mystr + " 公分");
      myh = mystr.toInt();
    }
    delay(1000);
  }
  
  float myw = 0;
  Serial.println("請輸入體重,單位是公斤");
  while ( myw <= 0 || myw >= 300 ) {
    String mystr = Serial.readString();
    mystr.trim();
    if ( mystr != "" ) {
      Serial.println("輸入的體重是: " + mystr + " 公斤");
      myw = mystr.toInt();
    }
  }

  float mybmi = myw / myh / myh * 10000;
  Serial.println("你的 BMI 是:" + String(mybmi));
  checkbmi(mybmi);
  delay(5000);
}

void checkbmi(float mybmi) {
  String mycheck ;
  if ( mybmi < 18.5 ) {
    mycheck = "有點太輕";
  } else if ( mybmi < 24 ) {
    mycheck = "體重狀況不錯";
  } else if ( mybmi < 27 ) {
    mycheck = "有點偏重,注意飲食";
  } else if ( mybmi < 30 ) {
    mycheck = "輕度肥胖";
  } else if ( mybmi < 35 ) {
    mycheck = "中度肥胖";
  } else if ( mybmi >= 35 ) {
    mycheck = "重度肥胖";
  }
  Serial.println("體重狀況: " + mycheck );
  return;
}

2.8: 課後作業

設計一個簡單的名為 code-bmi-read-show 的程式,讓使用者輸入身高後 (公分),自動算出適當的體重範圍。 亦即 BMI 在 18.5 到 24 之間都是合理的體重範圍!

自動計算 BMI 結果

2.9: 參考資料