---
# System prepended metadata

title: 2025 電資創客營 - 程式語言
tags: [電資創客營]

---

---
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的比較香 需要更多錢錢
-->
