2012年2月19日 星期日

繪圖型 LCD 128x64 顯示控制

說明

本文章是使用 PIC18F65J50 來驅動 WinStar 128x64 LCD (WG12864A),PIC 使用並列方式和 LCD 通訊,程式由 WinStar 官方提供的組合語言驅動範例程式修改成 C 語言版本。

因為此款 LCD 的電源使用 5V,PIC 和 LCD 連接的通訊腳位要選擇有 5V Toleranted Input 的腳位,如 PORTD。

image

 

LCD 資料

外觀

image

腳位資訊

image

電子特性

image

電路圖

image

 

LCD 初始化步驟

在初始化設定時,送出的 LCD 命令,必須分別送給 CS1 及 CS2 兩顆晶片。

clip_image001

 

LCD 顯示畫面步驟

在顯示整個 LCD 畫面時,先送出 LCD 命令將 CS1 及 CS2 兩顆晶片切到第 1 個 page,Column 設為從最左邊開始寫入 (CS1 從 S1 開始、CS2 從 S65 開始)。接著對 CS1 送出左邊畫面資料,CS2 送出右邊畫面資料,依序的寫滿 8 個 page 後,整個 LCD 的畫面 (128 x 64 bits) 即填滿,最後加個 Delay 延遲一段時間再顯示下一個畫面,調整 Delay 的延遲時間,可以改變顯示的速度。

clip_image003

 

LCD 畫面顯示控制示意圖

每個 page 分為左、右兩邊的晶片控制,每個晶片控制 64 x 8 bits,所以 1 個 page = 128 x 8 bits,總共有 8 個 page,所以全部有 (128 x 8) x 8 = 128 x 64 = 8,192 bits。

clip_image002

 

通訊時序圖

在送出 DB0 ~ DB7 的 LCD 資料後,必須注意 RW 和 E 腳間拉的時間。

clip_image004

 

寫入時序圖

  • tASU (Address Setup time) 是 LCD 取得位址的設定時間 (取得要寫入的位址),在 R/W 腳拉 Low 和 E 腳拉 High 之間的時間,最短不能低於 140 ns。
  • tDSU (Data Setup time) 為 LCD 資料的設定時間 (取得要寫入的資料),在 R/W 拉 Low 到 E 拉 High 之間的時間,最短不能低於 200 ns。

clip_image005

 

讀取時序圖

  • tASU (Address Setup time) 是 LCD 取得位址的設定時間 (取得要寫入的位址),在 R/W 腳拉 Low 和 E 腳拉 High 之間的時間,最短不能低於 140 ns。

clip_image006

 

對比控制

LCD 的對比控制是調整 LCD 畫面亮點與暗點的深度比例,在這個電路接了一個 10K 的 VR (可變電阻) 用來調整 LCD 的對比。

如下圖,使用 10K ~ 20K 的 VR,將 Vdd 及 Vee 接到 VR 的兩端,VR 的中間腳則拉到 Vo。

clip_image007

 

背光控制

image

LCD 底部有一塊會發光的 LED,有些 LCD 在上電時會自動點亮 LCD 背光,此款 LCD 則是提供 LED 的 A (陽極) 及 K (陰極) 腳位,使用外接一個可變電阻調整背光的亮度,在此電路是直接接上一個 220Ω 固定電阻。

WinStar 官方討論區的「How to turn on the backlight by 5V」說明如何計數背光接的電阻,舉例來說,以 WH1602L 的 LCD 為例,Datasheet 說 LED 的電壓為 3.5V,順向電流為 48mA,以歐姆定律來計算背光 LED 需接的電阻值為 31.25Ω。

clip_image008

參考目前此款 WG12864A 的 Datasheet,LED 的電壓為 4.2V,順向電流為 120mA。

clip_image009

以歐姆定律計算需接的電阻值如下:

RA = (5 - 4.2) / 120mA = 6.67Ω

但實際接上 220Ω 電阻就夠亮了,此處計算方法可能有問題,擔心接上 6.67Ω 的電阻會燒掉背光 LED,所以直接接一個 220Ω 電阻,流過背光 LED 的電流計算如下。

Iled = (5V - 4.2V) / 220Ω = 3.6mA

clip_image010

 

程式碼

本程式由 WinStar 官方提供的組合語言驅動範例程式修改成 C 語言版本,此程式會輪流顯示全畫面的 7 張圖片,加上適當的延遲,形成一個動畫。

下載完整程式碼:LCD_128x64.zip (20KB)

void LCDInit(void)
{
LCD_RS_TRIS = 0;
LCD_RW_TRIS = 0;
LCD_DATA_TRIS = 0;
LCD_E_IO = 0;
LCD_E_TRIS = 0;
LCD_CS1_IO = 0;
LCD_CS1_TRIS = 0;
LCD_CS2_IO = 0;
LCD_CS2_TRIS = 0;
LCD_nRESET_IO = 1;
LCD_nRESET_TRIS = 0;

LCDSendCmd(0x40); // Set Y Column Address from 0
LCDSendCmd(0xB8); // Set Page to 0
LCDSendCmd(0xC0); // Set Display Start Line to 0
LCDSendCmd(0x3F); // Set Display ON
}

void LCDShow(void)
{
unsigned char image, page, column;
const rom unsigned char *ptrData = Page[0];

for (image = 0; image < 7; image++) {
for (page = 0; page < 8; page++) {
LCDSendCmd(0xB8 + page); // Set Page (0xB8 ~ 0xBF)
LCDSendCmd(0x40); // Set Y Column Address from 0

for (column = 0; column < 64; column++)
LCDSendData(LCD_CS1, *ptrData++);

for (column = 64; column < 128; column++)
LCDSendData(LCD_CS2, *ptrData++);
}

LED_Toggle(LED1_IO);
LED_Toggle(LED2_IO);

delay100ms(5);
}
}

void LCDSendCmd(unsigned char cmd)
{
// Send command to CS1
LCD_CS2_IO = 0;
LCD_CS1_IO = 1;
_LCDWrite(LCD_FUN_CMD, cmd);

// Send command to CS2
LCD_CS1_IO = 0;
LCD_CS2_IO = 1;
_LCDWrite(LCD_FUN_CMD, cmd);
}

void LCDSendData(unsigned char cs, unsigned char data)
{
LCD_CS1_IO = (cs == LCD_CS1);
LCD_CS2_IO = (cs == LCD_CS2);
_LCDWrite(LCD_FUN_DATA, data);
}

static void _LCDWrite(unsigned char fun, unsigned char data)
{
LCD_RS_IO = fun;
LCD_RW_IO = 0;
LCD_DATA_IO = data;
Nop();
LCD_E_IO = 1; // Address Setup time must > 140ns before high
Nop();
Nop();
Nop();
LCD_E_IO = 0; // Data Setup time must > 200ns before low
}

執行結果


電路有另外加一顆 10K 的可變電阻,用來調整 LCD 的對比度。




參考資料


0 意見:

張貼留言