2011年1月3日 星期一

文字型 LCD 顯示控制

這篇文章是練習控制 Microchip APP013 開發板的 LCD 顯示,此開發板上的 LCD 是使用 16 個字元 x 2 列的文字型 LCD,以 4 bits 模式和 LCD 通訊。

LCD 控制方塊圖

LCD 腳位定義


LCD 的寫入及讀取的時序圖

Display address
此款 LCD 是 16 個字元 x 2 列,LCD 畫面對應到顯示位址如下,第一列是從 80H ~ 8FH,第二列是從 C0H ~ CFH。

LCD 指令集

4 bits 控制步驟

4 bits 控制命令的操作範例

開發板 LCD 電路圖
APP013 的 LCD Module 連接腳位如下

RS: RD4
RW: RD5
EN: RE2
RD3 ~ RD0: 使用 4 bits mode 的控制方式

程式碼
檔案:LCD.h
分別定義了 LCD RS、RW、EN 的狀態值,以及常用的 LCD Command
#ifndef _LCD_H
#define _LCD_H

#define LCD_RS_COMMAND  0
#define LCD_RS_DATA   1

#define LCD_RW_READ   1
#define LCD_RW_WRITE  0

#define LCD_ENABLE   1
#define LCD_DISABLE   0

// LCD Command
#define DISP_2LINE_4BITS 0x2C // Function set: DL=4 bits, N=2 lines, F=5x10 dots
#define DISP_ON    0x0C // Display On
#define DISP_ON_C   0x0E // Display On + Curror On
#define DISP_ON_B   0x0F // Display On + Curror On + Blink On
#define DISP_OFF   0x08 // Display Off
#define CLR_DISP   0x01 // Clear Display (must wait 1.64 ms)
#define ENTRY_INCR   0x06 // Entry Mode set: I/D=increment, S=0
#define ENTRY_DECR   0x04 // Entry Mode set: I/D=decrement, S=0
#define RETURN_HOME   0x02 // Cursor return home (must wait 1.64 ms)


extern void InitLCD(void);
extern void LCDCmdWrite4bits(unsigned char cmd);
extern void LCDCmdWrite(unsigned char cmd);
extern void LCDDataWrite(unsigned char data);
extern void LCDCursorPos(unsigned char row, unsigned char column);
extern void putcLCD(unsigned char data);
extern void putsLCD(const char *data);
extern void putrsLCD(const rom char *data);

#endif

檔案:LCD.c
此檔案包含了 LCD 的初始化函式、LCD 命令及資料的寫入函式,LCD 的命令分成送 4 bits 的 LCDCmdWrite4bits 及分二次送完 8 bits 命令的 LCDCmdWrite 函式。LCD 的資料顯示也是分二次送完 8 bits 的 LCDDataWrite 函式。
#include "HardwareProfile.h"

void InitLCD(void)
{ 
 LCD_RS = 0;
 LCD_RW = 0;
 LCD_EN = 0;
 
 LCD_RS_TRIS = 0;
 LCD_RW_TRIS = 0;
 LCD_EN_TRIS = 0;
 
 LCD_DATA_TRIS = 0;
 LCD_DATA = 0;
 
 delayms(2);        // Delay more than 1.5 ms for LCD Power on reset
 LCDCmdWrite4bits(0x03); delayms(5);  // Function set (Delay 4.1 ms)
 LCDCmdWrite4bits(0x03); delayus(100); // Function set (Delay 100 us)
 LCDCmdWrite4bits(0x03); delayus(100); // Function set (Delay 100 us)
 LCDCmdWrite4bits(0x02);     // Function set: DL=4 bits
 
 LCDCmdWrite(DISP_2LINE_4BITS);   // Function set: DL=4 bits, N=2 lines, F=5x10 dots
 LCDCmdWrite(DISP_ON_C);     // Display Control: D=Display On, C=Cursor On, B=Blink off
 LCDCmdWrite(ENTRY_INCR);    // Entry Mode set: I/D=increment, S=0
 LCDCmdWrite(CLR_DISP);      // Clear Display
 delayms(2);        // Wait more than 1.64 ms for Clear Display
}

static void _LCDWrite(unsigned char nibble)
{
 LCD_DATA = (LCD_DATA & 0xF0) | (nibble & 0x0F);
 
 LCD_EN = LCD_ENABLE;
 Nop(); Nop(); Nop();

 LCD_EN = LCD_DISABLE;
 Nop(); Nop(); Nop();
}

// Write LCD Command in 4 bits
void LCDCmdWrite4bits(unsigned char cmd)
{
 LCD_RS = LCD_RS_COMMAND;
 LCD_RW = LCD_RW_WRITE;
 
 _LCDWrite(cmd & 0x0F);
 delayus(100);
}

// Write LCD Command
void LCDCmdWrite(unsigned char cmd)
{
 LCD_RS = LCD_RS_COMMAND;
 LCD_RW = LCD_RW_WRITE;
 
 _LCDWrite(cmd >> 4);
 _LCDWrite(cmd & 0x0F);
 delayus(100);
}

// Write LCD Data
void LCDDataWrite(unsigned char data)
{
 LCD_RS = LCD_RS_DATA;
 LCD_RW = LCD_RW_WRITE;
 
 _LCDWrite(data >> 4);
 _LCDWrite(data & 0x0F);
 delayus(100);
}

// Cursor postion setting
// 16 characters x 2 lines Display Address:
//  Line 1:  80 81 82 83 ... 8D 8E 8F (16 characters)
//   (0,0)     (0,15)
//   Line 2:  C0 C1 C2 C3 ... CD CE CF (16 characters)
//   (1,0)     (1,15)
void LCDCursorPos(unsigned char row, unsigned char column)
{
 LCDCmdWrite(0x80 + (row * 0x40) + column);
}

// Print a character to LCD
void putcLCD(unsigned char data)
{
 LCDDataWrite(data);
 delayms(100);
}

// Print a string to LCD
void putsLCD(const char *data)
{
 while(*data) {
  putcLCD(*data++);
 }
}

// Print a rom string to LCD
void putrsLCD(const rom char *data)
{
 while(*data) {
  putcLCD(*data++);
 }
}

檔名:main.c
在 main 主程式中一開始會呼叫 InitIO 進行週邊及 LCD 的初始化設定,接著以間隔 1 秒的時間分別顯示字串變數和 ROM 中的字串到 LCD 上。
void main(void)
{
 char buff[] = "Hello World !";
 
 InitIO();
 
 while(1) {
  LCDCmdWrite(CLR_DISP);      // Clear Display
  delayms(2);        // Wait more than 1.64 ms for Clear Display
  
  putsLCD(buff);
  
  LCDCursorPos(1, 0);
  putrsLCD("I am a cool man.");
  
  delayms(250);
  delayms(250);
  delayms(250);
  delayms(250);
 }
}

void InitIO(void) {
 TRISD = PORTD = 0;
 INTCON = PIE1 = PIR1 = 0;
 
 InitLCD();

 RCONbits.IPEN = 1;
 INTCONbits.GIEH = 0;
 INTCONbits.GIEL = 0; 
}

示範影片:

參考資料:

0 意見:

張貼留言