在各式應用當中,常會使用 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 模組相連:
它們分別接到模組上的:
對應的電路接線圖如下:
[模組背面示意圖。黃色框為接線排針位置]
完成線路連接後,即可執行 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 組使用者自定義字元,因此可註冊的索引值範圍為 0 到 7。
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 裝置地址。