使用 PCF8574 / PCF8574A 驅動 1602 LCD

在各式應用當中,常會使用 LCD 作為互動顯示的裝置,其中 Hitachi HD44780 1602 LCD 為一常見的 LCD 顯示模組。本文將介紹如何使用 LinkIt 7697 連接 1602 I2C LCD 顯示模組 (使用 PCF8574A 驅動 IC),並提供函式庫範例說明如何驅動此顯示器。

下載及安裝函式庫

下載驅動程式

以 Francisco Malpartida 開發的函式庫作為移植基礎,LinkIt 7697 的 Arduino BSP 提供了精簡版本的 LCD 驅動程式。開發者可下載並依照「安裝驅動程式」章節的說明於 Arduino 開發環境中設置此驅動程式;安裝完成後,可執行 File / Examples / LiquidCrystal_I2C / HelloLinkIt7697 範例來點亮 LCD 模組。在實際執行 HelloLinkIt7697 前,可先參考後續章節的說明,以了解硬體接線配置及函式庫的使用方式。

硬體接線

透過 LinkIt 7697 上的這四根腳與 LCD 模組相連:

  • 5V

  • GND

  • I2C Clock (P8)

  • I2C Data (P9)

它們分別接到模組上的:

  • VCC

  • GND

  • SCL

  • SDA

對應的電路接線圖如下:

[模組背面示意圖。黃色框為接線排針位置]

完成線路連接後,即可執行 HelloLinkIt7697 範例並看見如影片中的顯示畫面:

疑難排除

執行上述範例時,若遇到不如預期的狀況,可查看是否是以下的問題:

  • LCD 螢幕沒有顯示畫面:可轉動模組背後的可變電阻 (黃框處) 進行顯示器對比的調整。

  • LCD 顯示字元為實心方塊:這是由於程式碼沒有正確指定 I2C 裝置的地址。以範例程式為例,預設使用的驅動 IC 為 PCF8574A,其對應到的 I2C 地址是 0x3F。若開發者的顯示模組是使用另一顆驅動 IC:PCF8574 (型號中沒有後綴的 "A"),那麼其地址則為 0x27。指定裝置地址的方式將在後續文章介紹,若要獲得更多模組 I2C 地址設定方式的說明,請參考附錄章節。

LiquidCrystal_I2C 函式庫

透過使用 LiquidCrystal_I2C 函式庫,開發者可以輕易地控制 1602 顯示模組。接下來將介紹如何利用相關的 API,進行顯示模組的基本操作。

LiquidCrystal_I2C()

使用此建構函式初始化顯示模組並指定裝置 I2C 地址。例如下面的程式碼將 PCF8574A LCD 模組 I2C 地址設定為 0x3F

// set the I2C address of the LCD controller
//    0x3F for PCF8574A
//    0x27 for PCF8574
LiquidCrystal_I2C lcd(0x3F);

若該 LCD 模組的驅動 IC 為 PCF8574 (而非 PCF8574A),則需將地址設定為 0x27 (而非 0x3F) 才能正確驅動 LCD。

begin()

此函式定義 LCD 顯示區域。以 1602 LCD 為例,需以 (16, 2) 做為此 API 的輸入參數:

// init the 1602 (2 rows / 16 columns) LCD
lcd.begin(16, 2);

home()

將游標移動至顯示器的起點位置。

clear()

清除顯示器上的所有內容及設定。

setCursor()

將游標移動至指定的位置。

print()

於游標所在處顯示字元。開發者可使用 ASCII 字元指定欲顯示的字、或是自訂字元供顯示器顯示。若要顯示 ASCII 字元,直接將該字串傳入 API 即可:

// display ASCII characters directly
lcd.print("LinkIt 7697");

如果要顯示自訂字元,需先透過下面介紹的 API 註冊對應的點陣圖。

createChar()

透過此 API 定義自訂字元。在 1602 LCD 上,每個字元都可被表示為 5x8 的矩陣、並透過一個 8 bytes 的陣列定義。陣列中每個 byte 的最低 5 位元定義了矩陣中每個點的狀態。以「向上箭頭」符號為例,該點陣圖的定義方式為:

所以該陣列的內容表示為:

// define the up-arrow bitmap
const uint8_t up_arrow[8] = {0x04, 0x0E, 0x1F, 0x04, 0x04, 0x04, 0x00, 0x00};

藉由呼叫 createChar() API,即可將此點陣圖搭配指定的索引值設定至顯示模組中:

// register the bitmap to index 3
lcd.createChar(3, (uint8_t *)up_arrow);

上面這段程式碼將「向上箭頭」點陣圖指定至索引值 3 的位置,所以開發者若要顯示此字元,可如下呼叫 print() API 傳入索引值 3

// show the bitmap (with index 3) on the LCD
lcd.print(char(3));

使用限制

1602 LCD 最高支援 8 組使用者自定義字元,因此可註冊的索引值範圍為 07

display() / noDisplay()

開啟 / 關閉顯示器 (僅文字部分,不包括背光)。此 API 的其中一種應用為在保留背光點亮的狀況下,進行文字閃爍效果。

backlight() / noBacklight()

開啟 / 關閉顯示模組的背光 (不包含文字部分)。

scrollDisplayLeft() / scrollDisplayRight()

將螢幕上的文字左移 / 右移一個字元的位置。模組透過改變顯示器的座標系來達成平移效果,實際上每個字元本身的座標位置並沒有改變。

leftToRight() / rightToLeft()

定義游標移動的方向。

HelloLinkIt7697 範例

在前面的影片中,展示了上述 API 提供的功能,開發者可參考 HelloLinkIt7697 程式碼 (如下) 了解驅動函式庫的使用方法。

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// set the I2C address of the LCD controller
//    0x3F for PCF8574A
//    0x27 for PCF8574
LiquidCrystal_I2C lcd(0x3F);

// define the custom bitmaps
// up to 8 bitmaps are supported
const uint8_t my_bitmap[][8] =
{
  // chequer
  {0x15, 0x0A, 0x15, 0x0A, 0x15, 0x0A, 0x15, 0x00},
  // up arrow
  {0x04, 0x0E, 0x1F, 0x04, 0x04, 0x04, 0x00, 0x00},
  // down arrow
  {0x00, 0x00, 0x04, 0x04, 0x04, 0x1F, 0x0E, 0x04},
  // rectangle
  {0x00, 0x1F, 0x11, 0x11, 0x11, 0x11, 0x1F, 0x00},
  // up-left arrow
  {0x1F, 0x1E, 0x1C, 0x1A, 0x11, 0x00, 0x00, 0x00},
  // up-right arrow
  {0x1F, 0x0F, 0x07, 0x0B, 0x11, 0x00, 0x00, 0x00},
  // down-left arrow
  {0x00, 0x00, 0x00, 0x11, 0x1A, 0x1C, 0x1E, 0x1F},
  // down-right arrow
  {0x00, 0x00, 0x00, 0x11, 0x0B, 0x07, 0x0F, 0x1F},
};

#define LONG_DELAY()  delay(1000)
#define SHORT_DELAY() delay(500)
#define ANIM_DELAY()  delay(400)

void setup()
{
  int i;
  int bitmap_size = sizeof(my_bitmap) / sizeof(my_bitmap[0]);

  // init the 1602 (2 rows / 16 columns) LCD
  lcd.begin(16, 2);

  // register the custom bitmaps
  for (i = 0; i < bitmap_size; i++)
  {
    lcd.createChar(i, (uint8_t *)my_bitmap[i]);
  }

  // move the cursor to 0
  lcd.home();
  lcd.print("          Hello!");
  
  // scroll left for 5 positions
  for (int i = 0; i < 5; i++)
  {
    lcd.scrollDisplayLeft();
    
    ANIM_DELAY();
  }

  // clear the LCD contents and the scrolling offset
  lcd.clear();

  // turn off the backlight
  lcd.noBacklight();
  
  LONG_DELAY();

  // turn on the backlight
  lcd.backlight();
  
  lcd.print("     Hello!     ");
  // change to the starting position of the next line
  lcd.setCursor ( 0, 1 );
  lcd.print("  LinkIt 7697   ");

  // blinks the texts
  for (i = 0; i < 2; i++)
  {
    ANIM_DELAY();
    lcd.noDisplay();
    
    ANIM_DELAY();
    lcd.display();
  }
  
  LONG_DELAY();
  LONG_DELAY();

  // clear all LCD contents and settings
  lcd.clear();
  
  SHORT_DELAY();
}

void loop()
{
  int i, ch_map;

  // clear the LCD and set the string direction to left-to-right
  lcd.clear();
  lcd.leftToRight();  
  lcd.print("    LeftToR");
  
  LONG_DELAY();

  lcd.setCursor(4, 0);
  lcd.print("12345678");
  
  SHORT_DELAY();
  
  lcd.setCursor(4, 0);

  // display the custom characters. randomly select a character bitmap
  for (i = 0; i < 8; i++)
  {
    ch_map = random(8);
    
    lcd.print(char(ch_map));

    ANIM_DELAY();
  }

  lcd.setCursor(0, 1);
  lcd.print("    RightToL");
  LONG_DELAY();

  // set the string direction to right-to-left
  lcd.rightToLeft();
  lcd.setCursor(11, 1);
  lcd.print("12345678");
  SHORT_DELAY();
  
  lcd.setCursor(11, 1);

  // display the custom characters. randomly select a character bitmap
  for (i = 0; i < 8; i++)
  {
    ch_map = random(8);

    lcd.print(char(ch_map));

    ANIM_DELAY();
  }
}

附錄

顯示模組的 I2C 地址定義

根據 datasheet 的描述,PCF8574A 預設的 I2C 裝置地址為 0x3F

PCF8574 的地址為 0x27

由於驅動函式庫使用 7-bit 的 I2C 地址格式定義,因此使用 0x3F / 0x27 作為裝置地址的設定值。除了預設的地址值外,為了避免電路中有其他 I2C 裝置佔用相同的地址,模組亦提供開發者自訂 I2C 裝置地址的彈性。透過連結下圖黃框中的 A0 / A1 / A2 焊點,即可改變模組的裝置地址。

PCF8574A / PCF8574 的裝置地址 (參見上表中 Address 欄位的 A0 / A1 / A2) 是由驅動晶片的 A0 / A1 / A2 腳位決定。這三隻腳預設為上拉至高電位,搭配上面 Table 4 及 Table 5 的表格描述,可了解為何裝置預設的地址分別為 0x3F / 0x27。相關腳位對應的電路圖如下:

舉例來說,若開發者將 0R 電阻上在 A0 焊點,那麼 A0 的地址位元就會從 1 變成 0,對應上面的 Address 定義表格,會讓 PCF8574A 的地址從 0x3F 變成 0x3E (或者是 PCF8574 的地址從 0x27 變為 0x26)。依照同樣的方法調整 A1 和 A2 位元,即可自訂出適合實際應用的 I2C 裝置地址。

Last updated