---
# System prepended metadata

title: 第三課 LCD 與內部函式庫引用
tags: [Arduino]

---

# 第三課 Arduino 內部函式庫引用

## 學習目標

1. 開啟 LCD 背光，顯示文字
2. 文字滾動效果
3. 自訂表情 / 小圖案顯示
4. 跳躍遊戲小練習
5. 音樂遊戲小練習

## **LCD 簡介**
![image](https://hackmd.io/_uploads/H1cCpmiyWl.png)

詳細可以參考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
![image](https://hackmd.io/_uploads/BydxvQkl-g.png)



## 接線圖
![image](https://hackmd.io/_uploads/rkBnzh3Rgg.png)
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：基本亮燈與文字**
![image](https://hackmd.io/_uploads/H1cCpmiyWl.png)
引入函式庫 =>建立地址 =>確認開始位置=>顯示內建文字

```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：簡單文字滾動**
![image](https://hackmd.io/_uploads/H1XZRQoybe.png)
```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：自訂表情 / 字元**
![image](https://hackmd.io/_uploads/H1bQCXsJZg.png)


0b00000 為空白陣列樣式
其中每一個格子裡仔細看都會有5X8的燈，我們可以透過byte方式控制每一顆燈的亮暗，0 為不顯示 1是顯示，ｓｍｉｌｅｙ的是函式名稱可以自行改名字

```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. 按鈕遊戲小範例**
![image](https://hackmd.io/_uploads/BkrVAXiJ-x.png)
![image](https://hackmd.io/_uploads/SyWBCXsJWg.png)
接線圖
![image](https://hackmd.io/_uploads/Hky86fylbx.png)

藉由按鈕控制ＬＣＤ小人物跳躍　
```ｃｐｐ
#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