---
# System prepended metadata

title: 基本程式介紹
tags: [DIT]

---

---
tags : DIT
---
{%hackmd BJrTq20hE %}

# 基本程式介紹 

Arduino 的框架是建立在 ==C / C++== 的基礎上，並且把一些所需要的參數設置都函數化，因此即使不了解底層的設置也能輕鬆上手。在此，我們簡單介紹寫程式的一些基本觀念吧！

所謂的寫程式，其實包含了很多很多步驟，最重要的幾個就是： 
:::info
分析 ->  寫  ->  執行  ->  除錯  ->  完成
:::

雖然看起來「寫」好像是主體，但其實分析可以說是這裡面最重要的一個步驟了，有一句話是這麼說的 : ==越早開始寫程式，就會越晚結束==。如果分析做得太過倉促，常常會出現一些不該有的 Bugs ，讓你在後續的除錯過程當中感到痛苦，所以要記住，好好分析一下程式的輸入跟輸出應該要是甚麼東西，中間的架構、邏輯可以寫下流程圖，如此便會減少除錯的痛苦時光。

---

:::success
:::spoiler 點這裡一下
\
教學文件內有一些這種形式的說明欄，
裡面有很多有趣或是重要的資訊，記得要閱讀喔 ～
如果你準備好了，就讓我們開始一一介紹基本程式的概念吧。

:::

---

## 1. 變數 (Variables)
變數是程式中最基礎的東西，它是用來儲存資料的記憶體空間，使用者可以通過宣告不同的變數來將自己所需要的數值、資料存到記憶體當中，並且在日後從該處讀取出來。

下表為常用的資料型態與其相關資料

| 儲存類型 |   型態    | 占用記憶體大小 |                     可儲存數值範圍                      |
|:--------:|:---------:|:--------------:|:-------------------------------------------------------:|
|   整數   |   short   |    2 Bytes     |                    -32,768 至 32,767                    |
|   整數   |    int    |    4 Bytes     |             -2,147,483,648 至 2,147,483,647             |
|   整數   | long long |    8 Bytes     | -9,223,372,036,854,775,808 至 9,223,372,036,854,775,807 |
|   小數   |   float   |    4 Bytes     |                      小數點後 7 位                      |
|   小數   |  double   |    8 Bytes     |                     小數點後 15 位                      |
|   字元   |   char    |    1 Bytes     |                       -128 至 127                       |
|  布林值  |   bool    |    1 Bytes     |                      false 或 true                      |

可以儲存的數值範圍不需要特別記下來，在一般的使用情境下，我們常常利用 int / double / char / bool 這幾種變數型態來儲存資料，像是整數的部分，除非已經知道需要儲存的資料非常龐大，否則使用 int 應該就非常足夠了。

另外，只要我們理解電腦是如何利用記憶體儲存資料，就可以輕鬆計算出其可儲存的數值範圍。以 short 為例，因為 short 是 2 Bytes，每一個 Byte 相當於 8 bits，而每一個 bit 可以儲存 0 或 1，所以利用二進位的方式表示數字，就可以推算出一個 short 可以儲存的資料範圍為 0 ~ 2^16，但為了可以表示負數，習慣利用一個 bit 來判別，所以一個 short 真正可以表示的數值範圍為 -2^15 ~ 2^15 - 1，也就是上表寫的 -32,768 ~ 32,767。

千萬要記得，根據不同的資料選擇對應的資料型態儲存相當重要，否則可能會發生 ==溢位(overflow)== 的情形。
:::success
:::spoiler 舉例說明 : 溢位
\
一個 int 只有 4 Bytes (32 bits)，其中有 1 個 bit 用來表達正負號。因此它能儲存的範圍為 -2^31 ~ 2^31-1，也就是上表寫的 -2,147,483,648 至 2,147,483,647。若使用 int 來儲存範圍以外的數字，就會發生溢位而造成程式錯誤，然而因為這種錯誤在語法上是沒有任何問題的，必須等到執行時才會發現錯誤，需要額外注意。

> 在歷史上，就曾經有一艘火箭因為沒注意到溢位問題，導致程式接收到的感測器數值錯誤，影響後面的控制，最終導致墜毀 ... [相關解釋影片](https://www.youtube.com/watch?v=5tJPXYA0Nec)
:::

以下示範如何宣告變數 : 

```cpp=
/* 
 * 語法 :
 * 變數型態 變數名稱_1, 變數名稱_2, ... ;
 */

int A;        // 宣告一個整數型態的變數，變數名稱為 A
float B;
char C, D, E; // 若是需要同時宣告多個變數，可以使用逗號連結。
```

變數的命名很自由，只有幾個規定 : 

- 只能使用大小寫英文、數字、底線
- 不能是數字開頭
- 不能使用保留字( Reserved Keywords )，避免編譯器誤解語句的意思。

:::success
:::spoiler 保留字
\
故名思義，就是編譯器保留下來的單字，儘管符合前兩點的限制，但仍然不能使用。
在 C++ 當中有許多保留字，可以參考 [這裡](https://en.cppreference.com/w/cpp/keyword)。
每一個保留字都是有其意義的，像是 int 就是為了表示一種變數型態、 for 就是為了表示迴圈等等，不需要刻意背下來有哪些保留字，只要多多練習程式就會自然記下大部分的保留字 !
:::

合法的變數名稱 : StepMotor_1, ArmServo ...
不合法的變數名稱 : 1_StepMotor, bool, while ...

另外，雖然命名的規則很自由，但普遍會根據變數的功能來命名，讓變數名稱一看就知道是做什麼用的，如此便可以提升程式的 ==可讀性==。

:::danger
:::spoiler 補充說明 : 容易被忘記的分號 :angry:
\
C / C++ 有一個比較惱人的語法，就是要在每一個敘述句後面加上分號，代表語句結束。
這是因為 C / C++ 不像是 Python 有嚴格的縮排規定。
剛開始寫程式的時候常常會忘記，要小心 ~

另外，希望大家養成好習慣，寫出乾淨整齊的程式碼，這部分可以多多參考程式專家是如何排版的。若是不喜歡把程式碼排版整齊，可以考慮報名以下比賽。 :see_no_evil: 
[International Obfuscated C Code Contest](https://en.wikipedia.org/wiki/International_Obfuscated_C_Code_Contest)
:::

:::success
:::spoiler 補充說明 : 註解
\
註解使指一段被特定符號括起來的文字，其不會被編譯器編譯，所以並不會影響程式碼的執行。寫註解是為了幫助自己與別人可以更容易看懂程式碼，就像是寫筆記般。

一個優秀的 programmer 會適時地加上註解，希望大家養成好習慣。

```=
//     -> 這個是單行註解，顧名思義，只有當前這一行不會被編譯。
/* */  -> 這個是多行註解，顧名思義，只要在兩個符號之間就可以橫跨很多行。
```
:::

:::success
:::spoiler 補充介紹 : 陣列 (Array)
\
當資料越來越多的時候，使用陣列來儲存就是一個不錯的方法。傳統的陣列就像是把數個變數綁在一起，有著連續的特性，其在記憶體當中的位置是緊鄰的，如此一來在存取相關的資料時，就可以大幅度地降低時間成本。
:::

---

## 2. 基本運算符號與表達式 (Operators and Expressions)
常見的運算符號有 *加、減、乘、除* 等等基本數學運算，另外也有邏輯的運算符號，像是 *且、或、大於、小於、等於、不等於* 等等的運算。而表達式就是由一連串的基本運算符號組成，像是 2 * 3 + 4 就是一個表達式，而表達式是從左至右來計算結果的，就像是我們計算等式的方法。

以下簡單舉例一下 : 
```cpp=
int num = 0;

num = 5 + 2;      // 7
num = num * 2;    // 14   (若是左右都有同樣的變數，可以縮寫成 num *= 2; )
num++;            // 15   (兩個加號放在一起代表加一，兩個減號就表示減一。放在變數的前後有意義上的差別。)
num = num % 2;    // 1    ( % 是指取餘數，所以 15 / 2 = 7 ... 1 )
```

:::success 
:::spoiler 介紹 : 常見的運算子
\
C / C++ 有許多種運算子，對於控制 Arduino 來說只需要常見的幾個就夠了。
有興趣的可以到 [這裡](https://en.cppreference.com/w/cpp/language/expressions) 看詳細的定義。



| 運算子 |            功能             |
|:------:|:---------------------------:|
|   +    |            相加             |
|   -    |            相減             |
|   *    |            相乘             |
|   /    |            相除             |
|   %    |           取餘數            |
|   +=   |   A += B 等同於 A = A + B   |
|   -=   |   A -= B 等同於 A = A - B   |
| ${*=}$ | A ${*=}$ B 等同於 A = A * B |
|   /=   |   A /= B 等同於 A = A / B   |
|   %=   |   A %= B 等同於 A = A % B   |
|   ++   |         加一的意思          |
|  - -   |         減一的意思          |
|   >    |            大於             |
|   <    |            小於             |
|   >=   |         大於或等於          |
|   <=   |         小於或等於          |

在邏輯上面來說 : 
- !  : 否定
- == : 等於
- != : 不等於
- || : 或 (or)
- && : 且 (and)

:::warning
:::spoiler 補充說明 : ++ 與 - -
\
這個運算子比較特殊，因為往後會常常遇到，需要特別注意一下。
若是把這個運算子放在變數的前面，代表程式會先把這個變數做加一或減一的動作，再繼續執行。相反的，若是放到變數的後面，就會先執行這一行程式碼，再做加一或減一的動作。

簡單舉例一下 : 
```cpp=
int A = 0, B = 0, C = 1;

A = ++C * 5; // 程式會先把 C 加一，再做剩下乘法的部分，也就是說到最後 A 會是 10，而 C 會是 2
B = C-- / 2; // 程式會先做除法，並儲存進 B 後再做減法，也就是說到最後 B 會是 1，而 C 也會是 1
```
:::

---

## 3. 判斷式 (Decision)
判斷式主要用於決策，當我們希望程式依照不同情境做出不同動作時，就可以使用判斷式來處理。
```cpp=
// 語法 :
if ( 判斷式 1 ) {
    // 程式片段 1
}
else if ( 判斷式 2 ) {
    // 程式片段 2
}
else if ( 判斷式 ... ) {
    // 程式片段 ...
}
else {
    // 程式片段 最後
}
```

若是 ( 判斷式 1 ) 邏輯上是對的，就會執行 ( 程式片段 1 )，
同理應用在剩下的判斷式。
如果所有判斷式邏輯上都是錯的，就會執行最後一個程式片段。

簡單舉例一下 :
```cpp=
int num;

if (num % 2 == 0) {
    // num 是偶數的話執行這裡
}
else if (num % 2 == 1) {
    // num 是奇數的話執行這裡
}
else {
    // num 不是前者的任意一個的話執行這裡
}
```

:::success
:::spoiler 補充說明 : 程式區段
\
程式區段就是一段利用左右大括號括起來程式碼，而一個程式區段是可以包含另一個程式區段。

簡單舉例一下 : 
```cpp=     
if (a == 1) {
    a = 2;
} 
else if (a > 5) {
    if (a < 10) {
        a = 0;
    }
}
```
在上述的程式碼當中， 1~3 行是一個程式區段，4~8 行是一個程式區段，而 5~7 行也是一個程式區段。

:::

:::success
:::spoiler 介紹 : 區域變數與全域變數

## 區域變數 ( Local Variable )
每一個變數都有其有效範圍，宣告在某個程式區段內的變數，其有效範圍就只在該程式區段內，離開這個有效範圍，像是在別的程式區段內，就不能夠使用這個變數了。這種僅存在程式區段內的變數，就稱為區域變數。

## 全域變數 ( Global Variable )
不同於區域變數，如果把變數宣告在所有程式區段外，就可以在所有程式區段內共用這個變數，這種變數就稱為全域變數，一旦程式配置了一個全域變數的記憶體空間，這個記憶體空間在程式執行的過程中，不論任何時間、任何位置都將是有效的，不像是區域變數只在特定的程式區域內才有效。

簡單舉例一下 : 

```cpp=
int A = 0;

void setup() {
    int B = 0;
    
    if (B > 5) {
        int C = 0;
    }
}

void loop() {
    int D;
}
```
在上述的程式碼當中，只有 A 變數為全域變數，其餘都是區域變數。

:::

---

## 4. 迴圈 (Loop)
迴圈可以重複執行片段的程式，減少程式碼的重複性，同時它也可以展現出更高維度的動作，像是多重迴圈，如同字面上的意思，就是迴圈裡面又有好幾個迴圈。通常迴圈是程式新手最頭痛的地方，但是只要多加練習，一定就可以體會出它的奧妙了。

C/C++ 有許多方式可以實現迴圈，不過我們先使用一般的 for 迴圈來帶各位體會迴圈的概念 : 
```cpp=
// 語法 :
for ( 初始化 ; 判斷式 ; 運算式 ) {
    // 重複執行的程式片段
}
```
for 迴圈可以填入三種表達式，可以三種都填入，也可以選擇性填入。
- 初始化 主要用來宣告迴圈用來迭代的變數。
- 判斷式 主要用來確認是否結束迭代。
- 運算式 主要用來調整每次迭代後的變數。

```cpp=
// 假定我們的目標是從 1 累加到 5
int num = 0;     

// 不使用迴圈 :
num += 1;
num += 2;
num += 3;
num += 4;
num += 5;

// 使用迴圈 :

// (初始化) i 從 1 開始
// (判斷式) i 大於 5 就結束迴圈 
// (運算式) 每次迭代結束後 i 加 1
for (int i = 1; i <= 5; i++) {  
    num += i;
}
```
上述的目標可以不使用迴圈就達到，但當程式的功能越來越複雜時，
使用迴圈可以有效地提升可讀性，也可以省下寫類似程式片段的時間。
所以請各位務必善用迴圈，不要暴力寫程式碼，否則編譯器會生氣喔 ! :face_with_head_bandage: 

:::success
:::spoiler 補充說明 : break 和 continue

## break

在一些特別的情況之下，我們會希望程式不要跑完全部的迴圈，在這個時候我們就可以利用 break 來強制程式跳出迴圈。

簡單舉例一下 : 

```cpp=
int count = 0; // 初始化 count 為 0

// i 從 1 開始，每次加一，結束條件沒有宣告
for (int i = 1 ; ; i++) {
    
    if (i > 5) {  // 如果 i 大於 5 就結束迴圈
        break;
    }
    
    count += i;
}
```
上面這段程式碼可以從 1 開始累加到 5 為止，也就是說 count 最後會等於 15。

## continue

類似於 break 的想法，同樣用在迴圈內部。使用 continue 會讓程式直接忽略掉剩下的程式碼，直接進入下一次的迭代。

簡單舉例一下 : 

```cpp=
int count = 0; // 初始化 count 為 0

// i 從 1 開始，每次加一，加到 10 就停止迴圈
for (int i = 1; i <= 10; i++) {   
    
    if (i % 2 == 0) {    // 如果 i 除以 2 餘零，就跳過剩下的程式碼，直接進入下次迭代
        continue;        
    }
    
    count += i;
}
```
上面這段程式碼可以計算出從 1 開始，到 10 為止的奇數總和，也就是說 count 最後會等於 25。

:::

## 5. 函式 (Function)
若要打個比方，函式就像是一本書，不論使用對象是誰，當有片段程式需要重複使用時，就可以直接翻開書本使用裡面的文章，而不需要再次從頭寫下一樣的內容，對於大型程式開發有著顯著的地位。


```cpp=
// 語法 :
回傳資料型態 函式名稱( 傳入的參數 ) {
    // 程式片段 ...
    // ...........
    // ... 程式片段
    
    return 資料;
}
```

同樣的，我們簡單舉例一下 : 
```cpp=
// 目標 : 寫一個判斷是否為偶數的函式
// 回傳值是一個布林值，傳入的參數是一個整數。

bool isEven(int num) {
    if (num % 2 == 0) {
        return true;
    }
    else {
        return false;
    }
}
```
```cpp=
// 我們要使用的時候直接呼叫函式名稱就可以
bool answer = isEven(10);
```

> 迴圈與函式都可以用來重複執行部分片段的程式碼，至於兩者有什麼差別，可以自己上網找 "遞迴" 的相關概念，因為其較為複雜，考慮到這是給程式新手的教學文件，就不在這裡解釋。

:::success
:::spoiler 補充資料 : 函式庫 ( Library )
\
若是把函式比喻成書本，那麼函式庫就會是一間超大的圖書館，在這裡可以找到許多已經完成的函式，只需要在自己的程式碼當中引入需要的函式庫，就可以快速地達成目標，將寶貴的時間省下來，這就是在程式領域裡常常提到的 : 
> Don't reinvent the wheel. :+1: 

附上 C/C++ 的參考網址，裡面涵蓋了所有標準函式庫的介紹，以後有看到不懂的函式就可以到網站中尋找解釋。
[C++ Reference](https://cplusplus.com/reference/)
:::

 
---

# 結語
看完上面的程式簡介，相信大家對於程式都有了一些基本的認識，若一時沒辦法消化也不用擔心，程式的概念本身就需要相當多的時間與練習，網路上也有各種教學文章與練習網站，希望大家可以抱持著好奇的心繼續專研程式。 :slightly_smiling_face: 

若是對 C/C++ 比較熟悉了，想要玩玩看 Arduino，但手邊沒有器材的話，可以到以下的網站練習看看，我們以後也會使用這個線上模擬環境來帶領大家使用 Arduino。

[Tinkercad](https://www.tinkercad.com/)