I2C LCD液晶顯示器簡介與應用

16×2 LCD 是一種常見的顯示模組,具有 16 行(column)和 2 列(row)的顯示區域,總共可以顯示 32 個字元。I2C(Inter-Integrated Circuit)是一種串列通信協議,利用 SCL (CLK信號) 和 SDA (Data信號) 兩條線來傳輸數據。I2C 16×2 LCD 模組可以顯示文字、數字或其他簡單的圖形。

基本範例:

#include <LiquidCrystal_I2C.h>      // 引用LiquidCrystal_I2C函式庫
LiquidCrystal_I2C lcd(0x27,16,2);   // 建立LiquidCrystal_I2C物件,名稱為lcd

void setup() {
  //--------------------------------------------------------------
  Serial.begin(9600);   // 啟用串列埠監看視窗
  //--------------------------------------------------------------
  lcd.init();           // 初始化 lcd 
  lcd.backlight();      // 開啟背光
  //--------------------------------------------------------------  
}

void loop() {
  lcd.setCursor(0,0);           // 定位在(column 0, row 0)
  lcd.print("Hello, world.");   // 印出內容
  lcd.setCursor(0,1);           // 定位在(column 0, row 1)
  lcd.print("This a test.");    // 印出內容
  lcd.cursor();                 // 顯示游標  
  lcd.blink();                  // 游標閃爍
  delay(3000);
  lcd.clear();                  // 清除

  lcd.setCursor(1,0);           // 定位在(column 2, row 0)
  lcd.print("Here is row 0.");  // 印出內容
  lcd.setCursor(0,1);           // 定位在(column 2, row 1)
  lcd.print("Here is row 1.");  // 印出內容
  lcd.noBlink();                // 游標不閃爍
  delay(3000);
  lcd.noCursor();               // 隱藏游標
  delay(3000);
  lcd.clear();                  // 清除
}

在2025年12月18日的作業中,若將4位元七段顯示器改成I2C LCD模組,參考接線與程式如下:

//-----------------------------------------------------------------------------
#include <OneButton.h>         // 引用OneButton函式庫
#define pb 34                  // 定義按鈕引腳
OneButton button(pb, true);    // 建立OneButton物件,名稱為button,按鈕為低態動作
//-----------------------------------------------------------------------------
#include "TM1637.h"            // 引用TM1637函式庫,並定義TM1637接腳
#define CLK 22                 // CLK為時脈接腳
#define DIO 23                 // DIO為資料接腳
TM1637 tm1637(CLK, DIO);       // 創立一個TM1637物件,名稱為tm1637
//-----------------------------------------------------------------------------
int num[4] = {0, 0, 0, 0};     // 4位數字陣列 {仟位,百位,十位,個位}
//-----------------------------------------------------------------------------
bool startCount = 0;           // (0:停止,1:開始)
int count = 9999;              // 計數器,初值為0
//-----------------------------------------------------------------------------
unsigned long previousMillis = 0;     // 前一次的millis()時間
const long interval = 500;            // 預設計時的時間
//-----------------------------------------------------------------------------
int input = 0;

void setup() {
  //--------------------------------------------------------------
  Serial.begin(9600);  // 啟用串列埠監看視窗
  Serial.println("Please enter a number(0~9999):");   // 輸入提示  
  //--------------------------------------------------------------
  button.attachClick(singleClick);              // 單擊
  button.attachDoubleClick(doubleClick);        // 雙擊
  button.attachLongPressStart(longPressStart);  // 長按開始
  button.attachDuringLongPress(longPress);      // 長按過程中
  button.attachLongPressStop(longPressStop);    // 長按結束
  //--------------------------------------------------------------
  tm1637.init();               // 初始化TM1637
  tm1637.set(BRIGHT_TYPICAL);  // 設定亮度,範圍是0到7,預設值為2
  //--------------------------------------------------------------
}

void loop() {
  //----------------------------------------------------------
  //串列埠監看視窗輸入
  //----------------------------------------------------------
  if (Serial.available()) //若串列埠有輸入資料,則執行下列程式區塊
  {
    input = readNumber();
    if (input >= 0 && input <= 9999)
    {
      count = input;
    }
    else
    {
      //若輸入字串無效(其他)
      Serial.println("Unknown range.");
      Serial.println("Please enter a number(0~9999):");   // 輸入提示
    }
  } 
  
  //----------------------------------------------------------
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;
    //----每經過一個interval的時間,想做的事----
    if(startCount == 1)
    {
      count--;
      if (count==0)
      {
        startCount = 0;
      }
    }
    //--------------------------------------
  }
      
  //----------------------------------------------------------
  button.tick(); // 定期偵測按鈕狀態
  //----------------------------------------------------------
  // 設定與轉換七段顯示器每個位元要顯示的數字
  num[0] = count / 1000 % 10;   // 千位
  num[1] = count / 100 % 10;    // 百位
  num[2] = count / 10 % 10;     // 十位
  num[3] = count % 10;          // 個位
  tm1637.display(0, num[0]);    // 顯示第一位
  tm1637.display(1, num[1]);    // 顯示第二位
  tm1637.display(2, num[2]);    // 顯示第三位
  tm1637.display(3, num[3]);    // 顯示第四位
  //----------------------------------------------------------
}

// 單擊處理
void singleClick() {
  Serial.println("Button Click.");
  startCount = !startCount;           // 取反相
}

// 雙擊處理
void doubleClick() {
  Serial.println("Button Double Click.");
}

// 長按開始
void longPressStart() {
  Serial.println("Button Long Press Start.");
}

// 長按過程中
void longPress() {
  Serial.println("Button Long Press ......");
}

// 長按結束
void longPressStop() {
  Serial.println("Button Long Press Stop.");
  count = 1000;        // 重置計數器 
  startCount = 0;  
}

// 讀取一個整數
int readNumber()
{
  while (!Serial.available());  // 等待串列埠輸入
  String input = Serial.readStringUntil('\n');  //讀取一行的輸入資料,直到換行符號為止(按下enter鍵)
  input.trim();                 //去除輸入字串前後的空白字元
  Serial.println(input);        //印出輸入字串
  return input.toInt();         //轉換為整數
}
//---------------------------------------------------------------------------------
#include <OneButton.h>              // 引用OneButton函式庫
#define pb 34                       // 定義按鈕引腳
OneButton button(pb, true);         // 建立OneButton物件,名稱為button,按鈕為低態動作
//---------------------------------------------------------------------------------
#include <LiquidCrystal_I2C.h>      // 引用LiquidCrystal_I2C函式庫
LiquidCrystal_I2C lcd(0x27,16,2);   // 建立LiquidCrystal_I2C物件,名稱為lcd
//---------------------------------------------------------------------------------
int num[4] = {0, 0, 0, 0};          // 4位數字陣列 {仟位,百位,十位,個位}
//---------------------------------------------------------------------------------
bool startCount = 0;                // (0:停止,1:開始)
int count = 9999;                   // 計數器,初值為0
//---------------------------------------------------------------------------------
unsigned long previousMillis = 0;   // 前一次的millis()時間
const long interval = 500;          // 預設計時的時間
//---------------------------------------------------------------------------------
int input = 0;

void setup() {
  //--------------------------------------------------------------
  Serial.begin(9600);  // 啟用串列埠監看視窗
  Serial.println("Please enter a number(0~9999):");   // 輸入提示  
  //--------------------------------------------------------------
  button.attachClick(singleClick);              // 單擊
  button.attachDoubleClick(doubleClick);        // 雙擊
  button.attachLongPressStart(longPressStart);  // 長按開始
  button.attachDuringLongPress(longPress);      // 長按過程中
  button.attachLongPressStop(longPressStop);    // 長按結束
  //--------------------------------------------------------------
  lcd.init();           // 初始化 lcd 
  lcd.backlight();      // 開啟背光
  //--------------------------------------------------------------  
}

void loop() {
  //----------------------------------------------------------
  //串列埠監看視窗輸入
  //----------------------------------------------------------
  if (Serial.available()) //若串列埠有輸入資料,則執行下列程式區塊
  {
    input = readNumber();
    if (input >= 0 && input <= 9999)
    {
      count = input;
    }
    else
    {
      //若輸入字串無效(其他)
      Serial.println("Unknown range.");
      Serial.println("Please enter a number(0~9999):");   // 輸入提示
    }
  } 
  
  //----------------------------------------------------------
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;
    //----每經過一個interval的時間,想做的事----
    if(startCount == 1)
    {
      count--;
      if (count==0)
      {
        startCount = 0;
      }
    }
    //--------------------------------------
  }
      
  //----------------------------------------------------------
  button.tick(); // 定期偵測按鈕狀態
  //----------------------------------------------------------
  // 設定與轉換七段顯示器每個位元要顯示的數字
  num[0] = count / 1000 % 10;   // 千位
  num[1] = count / 100 % 10;    // 百位
  num[2] = count / 10 % 10;     // 十位
  num[3] = count % 10;          // 個位
  lcd.setCursor(0,0);
  lcd.print(num[0]);            // 顯示第一位
  lcd.setCursor(2,0);
  lcd.print(num[1]);            // 顯示第二位
  lcd.setCursor(4,0);
  lcd.print(num[2]);            // 顯示第三位
  lcd.setCursor(6,0);
  lcd.print(num[3]);            // 顯示第四位
  //----------------------------------------------------------
}

// 單擊處理
void singleClick() {
  Serial.println("Button Click.");
  startCount = !startCount;     // 取反相
}

// 雙擊處理
void doubleClick() {
  Serial.println("Button Double Click.");
}

// 長按開始
void longPressStart() {
  Serial.println("Button Long Press Start.");
}

// 長按過程中
void longPress() {
  Serial.println("Button Long Press ......");
}

// 長按結束
void longPressStop() {
  Serial.println("Button Long Press Stop.");
  count = 1000;                 // 重置計數器 
  startCount = 0;      
}

// 讀取一個整數
int readNumber()
{
  while (!Serial.available());  // 等待串列埠輸入
  String input = Serial.readStringUntil('\n');  //讀取一行的輸入資料,直到換行符號為止(按下enter鍵)
  input.trim();                 //去除輸入字串前後的空白字元
  Serial.println(input);        //印出輸入字串
  return input.toInt();         //轉換為整數
}

作業練習:請使用OneButton Library、I2C LCD完成一個計時碼表功能。

  1. 開機後,LCD顯示器顯示計時碼表的初始時間 00:00:00.00。
  2. 每按一下按鈕開關,可開始或停止計時碼表(每百分之一秒加1,直到23:59:59.99歸零)。
  3. 長按按鈕開關,計數器重置為初始時間。
  4. 任何過程中,可以透過監看視窗改變計時碼表的數值。
  5. 請在Wokwi網站模擬後,並完成實體接線。