Arduino 演練 - LCD顯示器實作小精靈動畫

這一次演練的主角是LCD字元顯示器,翻了書籍內的章節很稀鬆平常地是搭配溫度、濕度感

測器來顯示相關數據資料。由於所買的套件組沒有附上LCD元件,因此上了露天拍賣所買到

的是LiquidCrystal_I2C,與書上的LCD不同的是此元件組可以少接電阻及相關的數位接腳,僅

需要於UNO板上用掉四個接腳即可,方便許多但價格上應該會貴一點!

而在此要展示的是如何在LCD內顯示簡單的動畫,會使用到的是自訂字元及控制cursor位移

,因為板子一上電後就自行運作,因此這次沒有搭配麵包板來做操作上的互動。

這次使用的素材如下:
1. Arduino Uno R3
2. LiquidCrystal_I2C*1
3. 杜邦線(公對母)*4
4. 電池盒*1

實際電路接法

一、演練效果說明

1. 板子上電後LCD螢幕會顯示Map init..再來進行地圖初始化作業
2. 緊接著地圖上會亂數顯示出星星的符號分散於2*16的螢幕內
3. 此時自訂字元()會先從左上角開始由左至右移動,當碰觸到星星時則會將其吃掉
4. 再來是由右下角開始由右至左移動,重複如3.的動作
5. 當自訂字元()移動完畢後,又進行Map init繼續loop

二、簡單說明一下電路接法

請看上面的圖示,正面面對UNO板由左至右對應LCD接腳分別表示
V5  → VCC
GND → GND
A4 → SDA
A5 → SCL

三、程式說明

這支程式主要需使用到兩個外部Library,分別為
Arduino-LiquidCrystal-I2C-library
Arduino-Number-Converter

依序載入及宣告的方式如下:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Convert.h>

const String EMPTY = " ";
const String STAR  = "*";

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);
Convert convert;

3.1、地圖產生

地圖的產生主要會使用到十進位轉換成二進位外部Library,主要目的如下:

LCD上面共有2列16欄,將亂數產生0 ~ 15的十進位數字轉換成二進位後並補上0

將表示成,如 5  → 101 0101

如此一來一列只需要產生四個亂數,兩列共八個亂數就可以填滿地圖

PS. 1 → 星星, 0 → 空白

相關程式碼如下:
String makeToFour(String source){
  String newStr = "";
  for(int i = 0 ; i < (4 - source.length()) ; i++){
    newStr += "0";
  }
  return newStr + source;
}

void initMap(){
  lcd.clear(); //clear lcd
  lcd.home();  //set cursor to 0,0
  
  int row = 0;
  while(row < 2){
    lcd.setCursor(0, row);
    int i = 0;
    while(i < 4){
      int num = (int)random(16);
      String binStr = makeToFour(convert.decimalToBinary(num));
      binStr.replace("1", STAR);
      binStr.replace("0", EMPTY);
      lcd.print(binStr);
      i++;
    }
    row++;
  }
  delay(2000);
}

首先,於initMap()設定第一層迴圈表示行的產生,再來第二層迴圈表示列的亂數產生

此時取0 ~ 15的亂數由long → int,再進行convert to binary String

再透過makeToFour補上0,使得長度為固定4的binary String

3.2、移動自訂字元 (ㄈ)

靜態的地圖說明之後,此時回到Arduino的setup()、loop() method
byte smallElvesR[8] = {B11111, B11111, B11000, B11000, B11000, B11000, B11111, B11111};
byte smallElvesL[8] = {B11111, B11111, B00011, B00011, B00011, B00011, B11111, B11111};

void setup()
{
  randomSeed(analogRead(0));//set random seed
  
  lcd.begin();
  lcd.backlight();

  lcd.createChar(0, smallElvesR);
  lcd.createChar(1, smallElvesL);
}

進行LCD initialize for lcd.begin(),再來是設定LCD背景亮燈 lcd.backlight()

緊接著是載入自訂字元至LCD元件的memory,一共可以設定8個自訂5x8字元

LCD的一個空格共由一個5x8字元所表示,以陣列內的二進位來看

B11111
B11111
B11000
B11000
B11000           
B11000
B11111
B11111

圖形將顯示如下:
以此類推,變數smallElvesL剛好反過來
void loop()
{
  lcd.home();
  lcd.print("Map init..");
  delay(2000);
  initMap();
  moveAction();
  delay(2000);
}

進入loop後,呼叫剛剛定義的initMap進行地圖的初始化,再來是移動自訂字元的moveAction
void moveAction(){
  int row = 0;
  int col = 0;
  while(row < 2){
    //set smallElves
    printChar(col, row, false);
    delay(500);
    while((row == 0 && (++col < 16)) || (row == 1 && (--col >= 0))){
      //move smallElves to next
      printChar(col, row, false);
      //set original pos to empty
      printChar((row == 1) ? col + 1 : col - 1, row, true);
      delay(500);
    }
    //clear smallElves
    printChar((row == 1) ? col : col - 1, row, true);
    //move next row
    lcd.setCursor(--col, ++row);
    delay(1000);
  }
}

void printChar(int col, int row, boolean isEmpty){
   lcd.setCursor(col, row);
   if(isEmpty)
    lcd.print(EMPTY);
   else
    lcd.print(char(row));
}

在此的重點是,設定游標再print自訂字元或空白字串

第二層迴圈的row == 0 表示正在進行第1行的走訪由左至右

當自訂字元移動到第15列時跳出迴圈

此時清掉該自訂字元,並將游標移往第2行的第15列

再來又回到row == 1的迴圈內繼續由右至左移動自訂字元

基本上是土法煉鋼的方式完成簡易的小精靈動畫XD

最後DEMO影片如下:


參考資料

留言

  1. 請問如果單純地想讓英文數字繞一圈的寫法是如何

    回覆刪除
  2. 沒試過, 但應該大同小異
    你就先setCursor後印出英文數字
    delay後清成空的
    之後再setCursor後再印出英文數字
    以此類推

    比較須注意得部分應該是
    這英文數字在第一行由左至右到尾端及第二行由右至左時的開頭
    要注意印出範圍須考慮

    回覆刪除

張貼留言