# 第三課 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是顯示,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. 按鈕遊戲小範例** ![image](https://hackmd.io/_uploads/BkrVAXiJ-x.png) ![image](https://hackmd.io/_uploads/SyWBCXsJWg.png) 接線圖 ![image](https://hackmd.io/_uploads/Hky86fylbx.png) 藉由按鈕控制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