--- title: 2025 電資創客營 - 程式語言 tags: 電資創客營 --- :::info # 2025 電資創客營 - 程式語言 **時間**:2025/08/11 13:00 ~ 16:55 **地點**:挺生大樓 A3 - 200 教室 ::: [TOC] ## Hello World 基礎C語言語法 ```cpp= int main(){ printf("Hello World"); return 0; } ``` > [!Note] !重點! > 1. 程式敘述結束時要有半形分號「;」 > 2. 字串型態要用**雙引號**包起來 -> "Hello" > 3. 大括號{}表示**程式的範圍** 在 Arduino 裡的程式區塊有兩個,setup和loop,功能分別為: ```Arduino void setup(){ // 只執行一次,用於初始化設定 } void loop(){ // 重複執行直到斷電 } ``` :::info 可以使用下列語法印出字串! ```Arduino Serial.println("Hello World") //印出字串並換行 Serial.print("Hello World") //印出字串 Serial.print("Hello World\n") // \n手動換行 ``` ::: ## 迴圈 ### for迴圈 for的用法 for (初始化; 條件判斷; 更新) {     // 迴圈要執行的程式 } - 例如: ```cpp= int main(){ for(int i = 0;i < 5;i++){ // 迴圈要執行的程式 } return 0; } ``` > i++ 的意思是 i的數值會增加1 0->1->2->3->4->5 **迴圈會執行五次!!** :::info delay(number); number以**毫秒**為單位,也就是千分之一秒 delay(1000)就是隔一秒執行的意思 ::: ### while迴圈 while的用法 while (條件判斷) {     // 迴圈要執行的程式 } - 例如: ```cpp= int main(){ int i = 0; // 要先初始化 while (i < 5) { // 迴圈要執行的程式 i++; // 變數更新在while裡面 } return 0; } ``` > [!Warning] > 上述兩個舉例for、while**執行結果**是相同的!! ## 序列通訊與位元 > Serial.begin(9600); 是什麼意思? 答案是:每秒傳送9600個**位元** 傳輸速率慢->**抗干擾能力強** 傳輸速率快->具有**即時性** > 那位元(bit)又是什麼? 每個位元只能是0或1,像是電燈開跟關。 位元(bit)是電腦傳輸資料的**最小單位**,像是以前的人認為物質最小的組成單位是原子 單位換算表 > 8 bits = 1 byte > 1 KB = 1,024 bytes > 1 MB = 1,024 KB = 1,048,576 bytes > 1 GB = 1,024 MB = 1,073,741,824 bytes 9600 bits / 8 = 1200 bytes/s -> 1200 bytes / 1024 ≈ 1.17 KB/s > 1.17 KB/s 快嗎?還是慢呢? 比如一張大小 1.57MB 的 gif 檔,要傳輸約 1373 秒才傳出去!! 計算: 1.57 MB * 1024KB/MB = 1607.68 KB 1607.68 KB / 1.17KB/s ≈ 1373.23 s **速率非常慢、非常慢!** :::info 如何選擇傳輸速率? - 速率慢一點 -> 精確度高 - 照片、音樂、視訊 -> 不要有雜訊、高畫質、高音質 - 速率快 -> 即時性 - 電話通訊 -> 低延遲 ::: ### ASCII Code 電腦只知道0101,他不知道ABCD。 對電腦來說 H 是 01001000 ### 進位系統 H = 72(十進位) = 01001000(二進位) = 110(八進位) = 0x48(十六進位) > 八進位或十六進位是為了讓人們更好看懂二進位資料。 ### 資料型態 char = 1 byte int = 4 bytes ... ### 宣告 1. 第一種 一次宣告一個變數 dataType name; - 例如: ```cpp= int a; int c; char b; ``` 2. 第二種 使用 `,` 來連續宣告 dataType name1, name2 [,...]; - 例如: ```cpp= int a, c; char b, x; ``` 3. 第三種 邊宣告可以邊賦值 dataType name1 = [value], name2 = [value]; - 例如: ```cpp= int a = 2019, c = 1; char b = 'B'; ``` #### 有號與無號 變數宣告預設(default)是**有號(signed)** 但有時候我們也不會用到負數部分 就可以用 unsigned 增加**正數**的範圍 unsigned dataType name; - 例如: ```cpp= unsigned char a = 'A'; // 範圍(Range):0 ~ 255 char b = 'B'; // 範圍(Range):-128 ~ 127 ``` ### uint8_t 前面我們有提到 int 是 4bytes 但在記憶體較少的裝置,我們希望可以盡可能的**利用**記憶體空間 就可以利用`uint8_t`這個資料型態 數字代表**位元數量**,上面的例子就是讓 int 只使用 8 bits 的空間 :::success | 型別 | 大小 | signed/unsigned | 範圍 | | -------- | ---- | --------------- | -------------- | | int8_t | 8 | signed | -128 ~ 127 | | uint8_t | 8 | unsigned | 0~255 | | int16_t | 16 | signed | -32768 ~ 32767 | | uint16_t | 16 | unsigned | 0 ~ 65535 | 以此類推(and so on...) ::: ### sizeof() ```Arduino void setup ( ) { Serial.begin (9600) ; int a; Serial.print("int 的大小 :"); Serial.println(sizeof(a)); } ``` :::info 可以利用 sizeof() 知道這個變數用了多少 byte ::: ## 數學運算 除了一般的加減乘除(+ - * /),還有取餘數(%) 舉例: 5 % 2 = 1 > [!Tip] abs() > abs()可以用來取絕對值(absolute value) > ex: |-5| = 5 ## 判斷式組合 ### if ```cp if (條件) { //條件成立才會執行 } ``` > (條件):任何能回傳 true 或 false 的運算(比較、邏輯運算、布林變數等) > > `true` 能和任何非 0 的整數進行轉換 > `false` 等同於整數的 0 ### 巢狀if ```cp if (外層條件) { // 當外層條件成立時執行 if (內層條件) { // 當外層條件成立且內層條件成立時執行 } } ``` :::danger if 敘述後面不加分號「;」 但是要記得加**大括號{}** :bulb:讓程式知道哪一行在if裡面、哪一行在if外面 ::: ### 比較運算子 | 運算子 | 意思 | 範例 | |:------:|:----------:|:----------:| | == | 等於 | if(a == b) | | != | 不等於 | if(a != b) | | > | 大於 | if(a > b) | | < | 小於 | if(a < b) | | >= | 大於或等於 | if(a >= b) | | <= | 小於或等於 | if(a <= b) | :::danger :bulb:注意! 邏輯判斷的等於要打兩次 `==` 賦值運算才是一個 `=` ::: :::danger if 的條件式不能像我們平常寫數學作業時一樣 a<b<c; (二元運算子) 要使用 &&(AND) 或是 ||(OR) 把他們接起來 - 例如: 數學中的 a<b<c 要用下方方法寫 ```cpp= if (a < b && b < c) { Serial.println("a 小於 b 小於 c"); } ``` ::: ### if-else ```c if (條件1) { // 當條件1成立時執行 } else if (條件2) { // 當條件1不成立,且條件2成立時執行 } else { // 當前面所有條件都不成立時執行 } ``` :::danger - if 可以**單獨存在**(可以只寫 if,但後面沒有接著 else if 或 else) 相反的說,else if 和 else 一定要接在 if 後面。 - 中間的 else if 可以有很多個。 - else 不用加上條件!!! ::: ## 字元、字串、陣列(char、string and array) ### 字元 字元(char)表示一個字母(character),使用單引號包裹,例如'A' 同一個字母有**不同進位**的**表示法** - 例如: ```cpp= char a, b, c, d; a = 65; // 十進制表示'A' b = 0x41; // 十六進制表示'A' c = 0101; // 八進制表示'A' d = 'A'; // 以字元常數表示'A',最為方便不須記憶 ``` a,b,c,d都會表示字母A ### 陣列(array) 定義:存放同型別的多個資料 宣告方式: ```c int arr[3] = {1,2,3}; // 宣告陣列大小(array size)為3的陣列,且有初始值1,2,3。 int arr[3]; // 宣告陣列大小(array size)為3的陣列,但沒有初始值 int arr[] = {1,2,3}; // 自動推算大小為3的陣列,且有初始值1,2,3。 ``` - 例如: ```c int score[50]; // 大小為 50*2(int 佔2bytes) = 100 Bytes 的 int 陣列 char address[100]; // 大小為 100*1(char 佔1byte) = 100 Bytes 的 char 陣列 ``` 陣列最特別的是可以利用 **索引(index)** 取值 - 例如: ```c int score[3] = {10 , 20 , 30}; int a = score[0]; // a = 10 ``` :::warning 索引(index)從0開始數 ::: ### memset 可以使用 memset(陣列位置, 0 , 陣列大小) 初始化陣列 - 例如要初始化一個叫做 arr 的陣列 ```c memset(arr, 0, sizeof(arr)); ``` ## 註解與定義名稱 ### 註解 註解有兩種寫法: - **單行註解**由兩條斜線構成,斜線後的文字或程式碼都不會被執行 ```clike= int a = 10; //這邊是註解,寫給自己或是其他人看的 ``` - **多行註解**由跨行的/* */構成,可以用來讓程式碼不被執行,**暫時關掉** 程式 ```clike= /* 被夾住的區域 通通都是註解 不會被執行 * / ``` ### #define 巨集 稱作**預設輸入處理器**(白話文:幫你把**某個字**全部替換成**某個值**) 使用格式:#define 名稱 值 還記得我們的[印三角形](https://wokwi.com/projects/438790938230731777)的範例嗎? ```Arduino= #define LED_PIN 13 // 下方所有 LED_PIN 都換成 13 const int DELAY_TIME = 1000; // DELAY_TIME 的值(1000)不能更動 void setup() { pinMode(LED_PIN, OUTPUT); } void loop() { digitalWrite(LED_PIN, HIGH); delay(DELAY_TIME); digitalWrite(LED_PIN, LOW); delay(DELAY_TIME); } ``` 適合用來設定**腳位**或是**常數** :::warning 但不會檢查!!!會導致在找錯時,非常難找到錯誤! ::: 於是就用到... ### const 常數宣告 const 就是 constant 常數的意思 使用格式 const 資料型別 名稱 = 值 - 例如: ```c const int LED_PIN = 13; const float PI = 3.14159; ``` 讓變數成為**不能改變**的常數,如果後續程式中不小心更動到,會**報錯提醒** ## 函式寫法 在大型程式的開發案中,main函式實際上的內容會很短。 因為我們會把**小功能**寫成一個可以**重複使用**的函式。 寫法:(就跟一開始的main函式很像!) ```c 回傳型態 函式名稱 (參數列表) { // 程式區塊 return 回傳值; } ``` 分成**有回傳值**和**沒有回傳值**。 - 有回傳值的例如: ```c int add(int a, int b) { return a + b; } ``` - 無回傳值的例如: ```c void sayHi(String name) { Serial.println("Hi " + name); } // 只執行println這個動作 ``` ### 差別說法 1. **Parameter(參數)** - 在函式宣告或定義時,寫在小括號裡的**變數名稱**。 - 像是函式的「收件人欄位」,先告訴電腦「我需要什麼東西」。 - **出現位置**:函式定義 - 範例: ```cpp void printSum(int x, int y) { // 這裡的 x、y 就是 parameters Serial.println(x + y); } ``` 2. **Argument(引數)** - 在呼叫函式時,實際傳進去的**資料或變數**。 - 像是你真的寄的「包裹內容」。 - **出現位置**:函式呼叫 - 範例: ```cpp printSum(3, 5); // 這裡的 3、5 就是 arguments ``` 3. **完整程式** ```cpp= void printSum(int x, int y) { // 這裡的 x、y 是接受值 Serial.println(x + y); } void setup(){ printSum(3, 5); // 傳遞 3、5 的值給副程式 peintSum } void loop(){ //沒用到 } ``` ## 指標 指標會指向記憶體的位置(所以是一個**地址**) ### 宣告指標 ```c int a = 10; int *ptr = &a; ``` 變數前面有星號( * )代表指標,&是取址運算子 所以 ptr指標 存著 a 的記憶體位置,而不是a的值(10) > 為什麼要使用指標? 除了可以搭配陣列和迴圈作索引外,**函式**要實際改動到**變數本身**也需要用到指標! 大倫老師舉例: ```Arduino= void add(int a) { a = a + 1; } void setup(){ Serial.begin(9600); int homework = 0; add(homework); Serial.println(homework); } ``` 相當於你「影印」了一份作業給其他同學寫,自己的還是沒寫到啊!!(小貓抱頭.gif) 但如果你使用指標,讓他去寫「你的」那份作業... ~~好孩子請勿模仿大倫哥哥~~ ```Arduino= void add(int *a) { *a = *a + 1; } void setup(){ Serial.begin(9600); int homework = 0; int *address = &homework; add(address); Serial.println(homework); } ``` ### 動態陣列 我們剛剛說:陣列是一塊「連續」的記憶體,但是如果我的陣列大小不夠、還想放更多東西進去呢? 可以利用malloc()幫我們用**指標**連接空著的記憶體,稱為**動態陣列**。 - 例如: ```cpp= int *arr; arr = (int*) malloc(10 * sizeof(int)); // ... free(arr); // 用完要釋放 ``` ## 結構與類別 <!-- 這邊更正一下,應該是類別,而不是物件 --> ### 什麼是結構(structure)? 像是一種**自定義**的資料型態(int,char...),可以把很多變數包在一起,預設權限為 public(公開的),也就是不管在程式的哪個地方都能用。 例如,可以定義一個學生具有名字(name)、學號(number)等屬性,稱為**成員(member)**: ```cpp struct Student { String name; int number; }; ``` 或是,再例如:定義一個二維平面上的點,有x座標(x coordinate)和y座標(y coordinate)這兩個屬性。 ```cpp struct Point { int x; int y; }; ``` 我們上面提到,結構像是資料型態,所以就像一般的變數宣告一樣。 ```cpp int a; //資料型態 變數名稱 Student s; //資料型態 變數名稱 ``` **差別**在於要存取成員(member)的時候要使用.(dot) - 例如: ```cpp Student s; //去找 s 本人 s.name = "Tom"; //使用 . 去訪問 s.number = 081461789; ``` ### 什麼是類別(class)? 類別可以說是安全版的結構,預設權限為 private(私人的) >那麼你有發現嗎? Serial是一個class的物件! 如果我們不引用 #include<Arduino> 在C++的環境下大約是下方這樣... ```cpp class Serial { public: // <<--- 這裡開始,這幾個成員是公開的 void begin(unsigned long);   void print(String str); void println(String str); private: // <<--- 這以下的成員是封起來的 int tx_pin; int rx_pin; int buffer[64]; }; ``` ### (struct)結構 VS 類別(class)? `struct` - 裡面的資料 **全部公開**(`public`),外面可以直接存取。 - 通常用在 **單純存資料的大型資料結構**,不特別保護內容。 `class` - 可以自由設定哪些成員公開(`public`)、哪些不公開(`private`)。 - 比較適合 **封裝程式功能**,保護內部資料不被隨意更改。 ### 指標&結構和物件 想要使用指標(位置、座位表)存取結構或物件的成員時,要用->(像一個箭頭),而不是用.來存取 `&` 是指後面變數的位置 ```cpp student *ptr = &s; //去位置上找s,ptr存了s的位置(第三排第四個) ptr->name = "Tom"; ``` ## 常用Arduino語法 pinMode(腳位編號, 模式) //注意字母大小寫 ```Arduino pinMode(2, INPUT); // 設定為輸入 pinMode(3, OUTPUT); // 設定為輸出 pinMode(4, INPUT_PULLUP); // 使用內建上拉電阻(想像成是按鈕) ``` digitalRead(pin) 讀取某個數位腳位的電壓狀態(HIGH 或 LOW) 可以存進某個變數裡,讓我們方便做條件判斷(是 有電 還是 沒電?) ```Arduino int state = digitalRead(2); //讀取第2腳的狀態,存進變數 state ``` digitalWrite(pin) 設定某個**輸出**腳位要輸出 HIGH(高電壓)或 LOW(低電壓) ```Arduino digitalWrite(13, HIGH); //讓第13腳輸出高電壓 (LED亮) digitalWrite(13, LOW); //讓第13腳輸出低電壓 (LED暗) ``` <!-- 聊天區: 甚麼漢語拼音 你說輸入法? 32G記憶體 羨慕了 64G的比較香 需要更多錢錢 -->