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