> For the complete documentation index, see [llms.txt](https://cavedu.gitbook.io/linkit-7697/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cavedu.gitbook.io/linkit-7697/linkit-7697-arduinoide/zhou-bian-yuan-jian-lian-jie-jiao-xue/shi-yong-pcf8574-pcf8574a-qu-dong-1602-lcd.md).

# 使用 PCF8574 / PCF8574A 驅動 1602 LCD

在各式應用當中，常會使用 LCD 作為互動顯示的裝置，其中 Hitachi [HD44780](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) 1602 LCD 為一常見的 LCD 顯示模組。本文將介紹如何使用 LinkIt 7697 連接 [1602 I2C LCD 顯示模組](https://robotkingdom.com.tw/product/grove-lcd-rgb-backlight-v4-0/) (使用 [PCF8574A](https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf) 驅動 IC)，並提供[函式庫](https://github.com/MediaTek-Labs/linkit-7697-peripheral-drivers-for-arduino/tree/master/LiquidCrystal_I2C)範例說明如何驅動此顯示器。

![](/files/W1m1X9XROWxdVV034Yjt)

### 下載及安裝函式庫 <a href="#driving1602lcdwithpcf8574pcf8574a-xia-zai-ji-an-zhuang-han-shi-ku" id="driving1602lcdwithpcf8574pcf8574a-xia-zai-ji-an-zhuang-han-shi-ku"></a>

[下載驅動程式](https://github.com/MediaTek-Labs/linkit-7697-peripheral-drivers-for-arduino/tree/master/LiquidCrystal_I2C)

以 Francisco Malpartida 開發的函式庫作為移植基礎，LinkIt 7697 的 Arduino BSP 提供了精簡版本的 LCD 驅動程式。開發者可[下載](https://github.com/MediaTek-Labs/linkit-7697-peripheral-drivers-for-arduino/tree/master/LiquidCrystal_I2C)並依照「安裝驅動程式」章節的[說明](https://cavedu.gitbook.io/linkit-7697/linkit-7697-arduino-ide-kai-fa-zhi-nan/kai-fa-tao-jian-yu-kuo-chong-ban/grove-starter-kit)於 Arduino 開發環境中設置此驅動程式；安裝完成後，可執行 **File / Examples / LiquidCrystal\_I2C / HelloLinkIt7697** 範例來點亮 LCD 模組。在實際執行 **HelloLinkIt7697** 前，可先參考後續章節的說明，以了解硬體接線配置及函式庫的使用方式。

### 硬體接線 <a href="#driving1602lcdwithpcf8574pcf8574a-ying-ti-jie-xian" id="driving1602lcdwithpcf8574pcf8574a-ying-ti-jie-xian"></a>

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

* 5V
* GND
* I2C Clock (P8)
* I2C Data (P9)

它們分別接到模組上的：

* VCC
* GND
* SCL
* SDA

對應的電路接線圖如下：

![](/files/VB1SdEMJ6zcjoRsfXIea)

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

![](/files/LuGmzQlhWi6hCliTnVqn)

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

{% embed url="<https://youtu.be/fYf2_1wg2iE>" %}

#### 疑難排除 <a href="#driving1602lcdwithpcf8574pcf8574a-yi-nan-pai-chu" id="driving1602lcdwithpcf8574pcf8574a-yi-nan-pai-chu"></a>

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

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

![](/files/GcDniirzmy55bv0ajunC)

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

![](/files/3qkVOOI77fn6EshwRNEv)

![](/files/Wz6huIWWffje0uzWoGRu)

### LiquidCrystal\_I2C 函式庫 <a href="#driving1602lcdwithpcf8574pcf8574aliquidcrystali2c-han-shi-ku" id="driving1602lcdwithpcf8574pcf8574aliquidcrystali2c-han-shi-ku"></a>

透過使用 [LiquidCrystal\_I2C 函式庫](https://github.com/MediaTek-Labs/linkit-7697-peripheral-drivers-for-arduino/tree/master/LiquidCrystal_I2C)，開發者可以輕易地控制 1602 顯示模組。接下來將介紹如何利用相關的 API，進行顯示模組的基本操作。

#### LiquidCrystal\_I2C() <a href="#driving1602lcdwithpcf8574-pcf8574a-liquidcrystal_i2c" id="driving1602lcdwithpcf8574-pcf8574a-liquidcrystal_i2c"></a>

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

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

{% hint style="danger" %}
若該 LCD 模組的驅動 IC 為 **PCF8574** (而非 PCF8574**A**)，則需將地址設定為 0x27 (而非 0x3F) 才能正確驅動 LCD。
{% endhint %}

#### begin() <a href="#driving1602lcdwithpcf8574-pcf8574a-begin" id="driving1602lcdwithpcf8574-pcf8574a-begin"></a>

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

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

#### home() <a href="#driving1602lcdwithpcf8574-pcf8574a-home" id="driving1602lcdwithpcf8574-pcf8574a-home"></a>

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

#### clear() <a href="#driving1602lcdwithpcf8574-pcf8574a-clear" id="driving1602lcdwithpcf8574-pcf8574a-clear"></a>

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

#### setCursor() <a href="#driving1602lcdwithpcf8574-pcf8574a-setcursor" id="driving1602lcdwithpcf8574-pcf8574a-setcursor"></a>

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

#### print() <a href="#driving1602lcdwithpcf8574-pcf8574a-print" id="driving1602lcdwithpcf8574-pcf8574a-print"></a>

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

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

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

#### createChar() <a href="#driving1602lcdwithpcf8574-pcf8574a-createchar" id="driving1602lcdwithpcf8574-pcf8574a-createchar"></a>

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

![](/files/3SkDo9GvOik5MMDsNvjh)

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

```
// 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));
```

{% hint style="danger" %}
使用限制

1602 LCD 最高支援 **8** 組使用者自定義字元，因此可註冊的索引值範圍為 **0** 到 **7**。
{% endhint %}

#### display() / noDisplay() <a href="#driving1602lcdwithpcf8574-pcf8574a-display-nodisplay" id="driving1602lcdwithpcf8574-pcf8574a-display-nodisplay"></a>

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

#### backlight() / noBacklight() <a href="#driving1602lcdwithpcf8574-pcf8574a-backlight-nobacklight" id="driving1602lcdwithpcf8574-pcf8574a-backlight-nobacklight"></a>

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

#### scrollDisplayLeft() / scrollDisplayRight() <a href="#driving1602lcdwithpcf8574-pcf8574a-scrolldisplayleft-scrolldisplayright" id="driving1602lcdwithpcf8574-pcf8574a-scrolldisplayleft-scrolldisplayright"></a>

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

#### leftToRight() / rightToLeft() <a href="#driving1602lcdwithpcf8574-pcf8574a-lefttoright-righttoleft" id="driving1602lcdwithpcf8574-pcf8574a-lefttoright-righttoleft"></a>

定義游標移動的方向。

### HelloLinkIt7697 範例 <a href="#driving1602lcdwithpcf8574pcf8574ahellolinkit7697-fan-li" id="driving1602lcdwithpcf8574pcf8574ahellolinkit7697-fan-li"></a>

在前面的影片中，展示了上述 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();
  }
}
```

### 附錄 <a href="#driving1602lcdwithpcf8574pcf8574a-fu-lu" id="driving1602lcdwithpcf8574pcf8574a-fu-lu"></a>

#### 顯示模組的 I2C 地址定義 <a href="#driving1602lcdwithpcf8574pcf8574a-xian-shi-mo-zu-de-i2c-di-zhi-ding-yi-i2caddress" id="driving1602lcdwithpcf8574pcf8574a-xian-shi-mo-zu-de-i2c-di-zhi-ding-yi-i2caddress"></a>

根據 [datasheet](https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf) 的描述，**PCF8574A** 預設的 I2C 裝置地址為 **0x3F**：

![](/files/jKAIG1gV44Qt2m3lWSw7)

而 **PCF8574** 的地址為 **0x27**：

![](/files/enAyel2YqQvGEgLRKS2T)

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

![](/files/JTYjMV4Bq9E5O1Atf2zU)

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

![](/files/XEbJb1ZvBrkhVa1PoeAy)

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