# 第三課 Arduino 內部函式庫引用
## 學習目標
1. 開啟 LCD 背光,顯示文字
2. 文字滾動效果
3. 自訂表情 / 小圖案顯示
4. 跳躍遊戲小練習
5. 音樂遊戲小練習
## **LCD 簡介**

詳細可以參考Youtube頻道=>愛上半導體 深入淺出的講LCD原理
https://www.youtube.com/watch?v=GEKVSmihi3Y
I2C 通信原理
https://www.youtube.com/watch?v=u62_Rjd5oMY
- **LCD(Liquid Crystal Display)** 是液晶顯示器,利用液晶分子控制光線顯示文字或圖案。
- **常見用途**:電子產品、計算機、家電、Arduino 專案顯示。
- **文字型 LCD**:
- 顯示固定格數文字,如 16x2、20x4。
- 每格 5×8 點陣,可顯示字母、數字或自訂圖案。
- **介面類型**:
- **I²C**:只需 SDA、SCL + 電源,省接腳,常見地址 0x27 或 0x3F。
- **平行(Parallel)**:需多條資料線,較複雜。
- **特性**:
- 每格大小固定,可自訂字元(最多 8 個)。
- 可控制背光、游標閃爍、文字滾動。
- **應用場景**:
- 顯示感測器數值(溫度、濕度、距離)
- 簡單遊戲或互動專案
- 提示訊息或狀態顯示
- Arduino 輸出控制與圖形設計學習
## 函式庫安裝
- **LCD外部元件導入**
- 如果想要使用一些特殊溝通的元件,一般不會自己寫,不然程式太繁雜,會直接搜尋別人或廠商已經定義好的函式庫來做為使用工具
- **找到適合元件,並且安裝**
- 個人常用=>LiquidCrystal_PCF8574

## 接線圖

SDA=>A4
SCL=>A5
## 函式庫
```cpp
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
```
## 常見指令
| 功能 | 函式 |
| ------- | --------------------------- |
| 初始化 LCD | `lcd.begin(16,2);` |
| 開啟背光 | `lcd.setBacklight(255);` |
| 關閉背光 | `lcd.setBacklight(0);` |
| 清除螢幕 | `lcd.clear();` |
| 設定游標 | `lcd.setCursor(列, 行);` |
| 顯示文字 | `lcd.print("文字");` |
| 顯示自訂字元 | `lcd.write(byte(編號));` |
| 滾動左 | `lcd.scrollDisplayLeft();` |
| 滾動右 | `lcd.scrollDisplayRight();` |
| 建立自訂字元 | `lcd.createChar(編號, 陣列);` |
## **階段 1:基本亮燈與文字**

引入函式庫 =>建立地址 =>確認開始位置=>顯示內建文字
```cpp
#include <Wire.h> // I2C 通訊函式庫
#include <LiquidCrystal_PCF8574.h> // LCD I2C 控制函式庫
LiquidCrystal_PCF8574 lcd(0x27); // 建立 LCD 物件,0x27 是 I2C 地址
void setup() {
lcd.begin(16,2); // 初始化 LCD 大小 16x2
lcd.setBacklight(255); // 開啟背光
lcd.setCursor(0,0); // 設定游標到第1行第1列
lcd.print("Hello World"); // 顯示文字
lcd.setCursor(0,1); // 設定游標到第2行第1列
lcd.print("LCD Demo"); // 顯示文字
}
void loop() {
// 這個範例不需要在 loop 更新
}
```
- 練習題 1
顯示你的名字在第一行
第二行顯示今天的日期或其他字串
背光保持亮
## **階段 2:簡單文字滾動**

```cpp
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27); // LCD 物件
void setup() {
lcd.begin(16,2); // 初始化 LCD
lcd.setBacklight(255); // 開背光
lcd.setCursor(0,0); // 游標到第1行
lcd.print("Scrolling Text Demo"); // 顯示文字
}
void loop() {
lcd.scrollDisplayLeft(); // 文字往左移動一格
delay(200); // 停 200ms,控制滾動速度
}
```
- 練習題 2
顯示文字「Arduino 是好玩」
文字從右到左滾動
每滾動一次停留 150~300ms
滾完後重新從右邊出現
## **階段 3:自訂表情 / 字元**

0b00000 為空白陣列樣式
其中每一個格子裡仔細看都會有5X8的燈,我們可以透過byte方式控制每一顆燈的亮暗,0 為不顯示 1是顯示,smiley的是函式名稱可以自行改名字
```Cpp=
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27); // LCD 物件
// 自訂笑臉字元 (5x8 點陣)
byte smiley[8] = {
0b00000, // 空白
0b01010, // 眼睛
0b01010, // 眼睛
0b00000, // 空白
0b10001, // 嘴巴
0b01110, // 嘴巴
0b00000, // 空白
0b00000 // 空白
};
void setup() {
lcd.begin(16,2); // 初始化 LCD
lcd.setBacklight(255); // 開背光
lcd.createChar(0, smiley);// 建立自訂字元,存放在 0 號
lcd.setCursor(0,0); // 游標到第1行第1列
lcd.write(byte(0)); // 顯示自訂笑臉
lcd.setCursor(2,0); // 游標到第1行第3列
lcd.print("Hello!"); // 顯示文字
}
void loop() {
// 此範例不需要在 loop 更新
}
```
- 練習題 3
自己設計一個愛心或箭頭圖案
顯示在 LCD 第一行
第二行顯示你的名字或其他文字
## **4. 按鈕遊戲小範例**


接線圖

藉由按鈕控制LCD小人物跳躍
```cpp
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27); // I2C 地址
const int btnJump = 2; // 跳躍按鈕
// 自訂字元: 小人
byte player[8] = {
0b00100,
0b01110,
0b00100,
0b01110,
0b10101,
0b00100,
0b01010,
0b10001
};
// 自訂字元: 障礙
byte obstacle[8] = {
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111
};
int playerRow = 1; // 小人初始在第2行
int playerCol = 0; // 小人固定在第0列
int obstacleCol = 15; // 障礙從最右邊開始
void setup() {
pinMode(btnJump, INPUT_PULLUP); // 按鈕使用內部上拉
lcd.begin(16,2);
lcd.setBacklight(255);
lcd.createChar(0, player);
lcd.createChar(1, obstacle);
lcd.clear();
}
void loop() {
lcd.clear();
// 判斷按鈕是否按下 (LOW 表示按下)
if(digitalRead(btnJump) == LOW){
playerRow = 0; // 跳到第1行
} else {
playerRow = 1; // 站在第2行
}
// 顯示小人
lcd.setCursor(playerCol, playerRow);
lcd.write(byte(0));
// 顯示障礙
lcd.setCursor(obstacleCol,1); // 障礙永遠在第2行
lcd.write(byte(1));
// 碰撞判斷
if(obstacleCol == playerCol && playerRow == 1){
lcd.setCursor(5,0);
lcd.print("GAME OVER!");
while(1); // 停止遊戲
}
// 障礙往左移動
obstacleCol--;
if(obstacleCol < 0)
obstacleCol = 15; // 從右邊重新出現
delay(200); // 控制遊戲速度
}
```
🔹 說明
按鈕跳躍
按下按鈕,小人跳到上面一行(playerRow = 0)
放開回到原本一行(playerRow = 1)
障礙移動
障礙每次往左移一格
移到最左邊後重新出現在右邊
碰撞判定
如果障礙碰到小人且小人沒有跳(在第2行),顯示 GAME OVER
速度調整
delay(200) 控制遊戲速度,可調小一點遊戲更快,調大一點遊戲更慢
使用到指令
| 指令 | 功能 |
| ---------------------------- | -------------------------------------- |
| `lcd.begin(16, 2);` | 初始化 LCD,設定為 16 列 × 2 行。 |
| `lcd.setBacklight(255);` | 打開背光(亮度 255 = 最亮)。 |
| `lcd.clear();` | 清除螢幕內容。 |
| `lcd.createChar(num, data);` | 建立自訂字元(`num` 為 0~7,`data` 為 8 列點陣陣列)。 |
| `lcd.setCursor(col, row);` | 設定游標位置,`col` 為列(0–15),`row` 為行(0 或 1)。 |
| `lcd.write(byte(n));` | 顯示自訂字元(`n` 為 `createChar` 時設定的編號)。 |
| `lcd.print("文字");` | 在 LCD 顯示一般文字。 |
loop()
↓
lcd.clear()
↓
讀取按鈕狀態 → 更新 playerRow
↓
顯示小人
↓
顯示障礙
↓
檢查碰撞
↓
更新障礙位置 (obstacleCol--)
↓
delay(200) 控制速度
↓
[回到 loop 開頭 重複]
## **5. 按鈕遊戲小範例-音樂遊戲**
```Cpp=
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27);
const int buzzer = 8;
const int btn1 = 2;
const int btn2 = 3;
const int btn3 = 4;
int tonesList[3] = {262, 294, 330}; // 三個音符 (Do, Re, Mi)
int sequence[10]; // 系統隨機序列
int level = 1; // 起始關卡
bool gameOver = false;
void setup() {
lcd.begin(16, 2);
lcd.setBacklight(255);
lcd.print("Music Memory!");
pinMode(btn1, INPUT_PULLUP);
pinMode(btn2, INPUT_PULLUP);
pinMode(btn3, INPUT_PULLUP);
pinMode(buzzer, OUTPUT);
delay(1000);
}
void loop() {
if (gameOver) return;
lcd.clear();
lcd.print("Level "); lcd.print(level);
delay(1000);
// 1️⃣ 產生隨機序列
for (int i = 0; i < level; i++) {
sequence[i] = random(0, 3);
tone(buzzer, tonesList[sequence[i]], 300);
delay(400);
}
lcd.clear();
lcd.print("Your turn!");
delay(500);
// 2️⃣ 玩家輸入比對
for (int i = 0; i < level; i++) {
int pressed = waitForPress(); // 等待按下
if (pressed != sequence[i]) {
lcd.clear();
lcd.print("Game Over!");
tone(buzzer, 100, 1000);
gameOver = true;
return;
}
}
// 3️⃣ 全部正確 → 升級
lcd.clear();
lcd.print("Good!");
tone(buzzer, 500, 300);
delay(1000);
level++;
if (level > 10) level = 10; // 遊戲上限
}
// 等待玩家按下哪個按鈕
int waitForPress() {
while (true) {
if (digitalRead(btn1) == LOW) { tone(buzzer, tonesList[0], 200); return 0; }
if (digitalRead(btn2) == LOW) { tone(buzzer, tonesList[1], 200); return 1; }
if (digitalRead(btn3) == LOW) { tone(buzzer, tonesList[2], 200); return 2; }
}
}
```
| 主題 | 重點 |
| ------ | --------------------- |
| 陣列操作 | 儲存隨機序列、比對輸入 |
| 函式設計 | `waitForPress()` 等待事件 |
| 流程控制 | 關卡遞增、遊戲結束判斷 |
| 音效控制 | 使用 `tone()` 播放不同音符 |
| LCD 操作 | 顯示遊戲階段文字 |
### 指令大全
部分指令參考
https://hackmd.io/@_KrYKsogTfeap4EQ4jGEOw/SJWvlk9hd
## Eric簡單認識Arduino:
第一課 arduino認識數位信號與開關
https://hackmd.io/@godgods/SkaUwHi6xe
第二課 arduino認識類比信號與讀取與寫入
https://hackmd.io/@godgods/SJbpxvn0gg
第三課 arduino LCD函式控制
https://hackmd.io/@godgods/ryxXL7skWe
第四課 arduion 小電控制大電繼電器與馬達擴充版
第五課 arduino 簡單通訊藍芽與Wifi