點陣字符液晶顯示模塊的驅動程序設計
眾所周知液晶(LCD)顯示器件以其低功耗的特點被廣泛應用于各種領域,如智能儀表.辦公自動化.通訊.軍工等。
本文將以常用的1602系列顯示模塊詳細介紹其驅動程序的設計及在設計中需要注意的一些問題。1602系列液晶顯示模塊常用的驅動芯片有HD44780(日立公司) 對應的兼容芯片有 KS0066(韓國三星) SED1278(Seiko Epson) NJU6408(New Japan Radio Co.Ltd)等。
下面以采用日本日立公司的HD44780驅動片為例簡要介紹其內部功能,如果讀者需要更詳細的資料請查閱相關手冊,而且貴報在2006年第29期也有相關介紹。
1:HD44780驅動片具有字符發生器ROM , 可顯示192 種字符(160 個5 ×7 點陣字符及32 個5 ×11 點陣字符) 。
2:具有64 個單元的自定義字符RAM , 可自定義8 個5 ×7 點陣字符或4 個5 ×11 點陣字符。
3:具有80 個單元的顯示RAM 。
4:標準的接口特性, 適配M6800 系列M PU 的操作時序。
下表為1602顯示模塊接口引腳功能表
引腳號 符號 功能
1 VSS 電源地
2 VDD + 5V 邏輯電源
3 VLCD 液晶驅動電源
4 RS 寄存器選擇:“1”選傳送數據數據;“0”選控制指令
5 R/ W 讀/ 寫操作選擇:“1”為讀;“0”為寫
6 E 使能信號端口
7~10 DB0~DB3 數據總線低4位(采用4位數據傳送時不用)
11~14 DB4~DB7 數據總線高4位
15 LED+ LCD背光+電源輸入端
16 LED- LCD背光-電源輸入端
了解了其接口功能后,現在就可以設計硬件原理圖了,本文采用Microchip公司的PIC單片機進行驅動程序設計,限于筆者調試設備支持原因,故選用一款16F716進行實驗,考慮到能兼容54等芯片故程序中基本沒有用到716的其他硬件資源,如中斷等,加之HI-TECH公司強大的C編譯軟件,使代碼變得更加精簡。由于HD44780系列驅動芯片的數據傳送方式為并行傳送,其缺點就是大大占用了單片機寶貴的IO口資源,考慮到這點,生產廠家也在該驅動片中擴展了另外一種驅動方式即4位數據傳送方式,下圖為8位數據連接圖,4位數據連接只要把低4位數據連接線空出就可以,讀者可以根據實際情況合理選擇,但4位連接也需要占用單片機7個IO口,這跟串行數據傳送方式的HT1621系列驅動片是不可比的,但相比之下這種并行數據傳送方式作為軟件編程就顯得簡單些。
有了驅動原理圖,再畫好PCB板圖接下來的工作就是軟件設計了,在進行程序設計之前讓我們再去了解和熟悉一下有關HD44780驅動片的控制指令.
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 0 0 1
清屏 1.64MS(250KHZ)
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 0 1 *
AC清0 1.64MS(250KHZ)
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 0 1 I/D S
輸入方式 40US(250KHZ)
I/D=1: 數據讀寫后AC(地址)自動增1
I/D=0: 數據讀寫后AC(地址)自動減1
S=1: 數據讀寫后畫面平移
S=0: 數據讀寫后畫面不動
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 0 1 D C B
顯示開關控制 40US(250KHZ)
D=1: 打開顯示 D=0: 關閉顯示
C=1: 打開光標 C=0: 關閉光標
B=1: 打開閃爍 B=0: 關閉閃爍
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 0 1 S/C R/L * *
光標畫面位移 40US(250KHZ)
S/C=1: 畫面平移一個字符位
S/C=0: 光標平移一個字符位
R/L=1: 右移
R/L=0: 左移
RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
0 0 0 0 1 DL N F * *
功能設置 40US(250KHZ)
DL=1: 8位數據接口 DL=0: 4位數據接口
N=1: 2行顯示 N=0: 1行顯示
F=1: 5*10點陣 F=0: 5*7點陣
說明:表格中*符號為二進制任意數字0/1
了解了以上功能指令后就可以開始寫程序了,首先根據硬件原理圖來定義下單片機IO口,這樣做的好處有利于程序的移植和后續的維護,也使程序看上去清晰明了.
#define RS RA0 //RA0為數據(1)或指令(0)控制端
#define E RA1 //RA1為時鐘端口,下降沿寫入數據,上升沿讀出數據
#define RW RA2 //RA2為讀寫控制端
#define LCD_DATA PORTB //RB為8位或者4位數據連接端口,4位時空出RB0~RB3
#define LCD_DATATRIS TRISB //方向口
#define INPUT 0XFF
#define OUTPUT 0
#define BF lcddata_temp&0x80 //HD44780 “忙”檢測標志位
建立一個單片機初始化函數,此函數建議在主循環程序分時調用,這樣做的好處是能有效避免在強干擾環境中誤改方向口和其他特殊RAM的值從而造成單片機工作不正常甚至死機
void init_mcu (void)
{ CLRWDT();
TRISA=0;
TRISB=0;
ADCON1=7;
INTCON=0;
OPTION=0X80;
}
建立一個查詢HD44780忙標志信號的函數,由于HD44780在數據寫入需要有一定的延時,如果在前次操作還未完成前又有新的數據寫入,這時的數據寫入是無效的。
bit lcd_busy (void) //檢測"忙"
{ unsigned char lcddata_temp;
CLRWDT();
LCD_DATATRIS=INPUT; //設為數據接收
RS=0; //命令類型
RW=1; //讀
E=1;
lcddata_temp=LCD_DATA;
E=0;
if (BF) return (0); //忙標志
else
return (1); //不忙
}
此函數用于8位數據傳送方式,帶有一個返回標志位,查詢其“真”“假”就可判斷HD44780現在的工作狀態,具體操作在下面“寫數據函數”中作介紹。至于4位數據傳送方式只要在增加一個周期的時鐘信號就可以了,對應程序如下:
bit lcd_busy (void) //檢測"忙"
{ unsigned char lcddata_temp;
CLRWDT();
LCD_DATATRIS=INPUT; //設為數據接收
RS=0; //命令類型
RW=1; //讀
E=1;
NOP();
lcddata_temp=LCD_DATA;
E=0;
NOP();
E=1;
NOP();
E=0;
if (BF) return (0); //忙標志
else
return (1); //不忙
}
從程序中不難看出HD44780在進行4位數據傳送中,在第一個時鐘的上升沿讀取的高4位數據即DB7~DB4的值。
然后再建立一個數據寫操作函數,由于HD44780驅動在每輸入一個命令或數據后必須要CPU接收一個HD44780的響應信號(這點我在前面已經提起),表明其現在的工作狀態,這很像24**系列EEPROM。初始化命令最長時間為1.64MS(250KHZ)這個時間用CPU循環檢測作為一般的程序我想應該沒問題,但是考慮到HD44780由于意外損壞等原因造成其長時間不作 “忙” 標志應答,所以我個人認為還是別死等待,給定一個時間,比如3MS,在3MS內檢測不到應答信號就自動跳出去執行其他的子程序,或者進行錯誤處理,從中也可以判別LCD模塊的好壞,這樣CPU的執行就顯得不是那么被動,也不會影響其他程序的正常工作.
基于以上思路對應8位數據傳送的控制程序如下:
void write_bytelcd (unsigned char lcddata,unsigned char r_s) //命令數據寫函數
{ unsigned int i;
for (i=2000;i!=0;i--) //給定一個時間進行查詢“忙”標志
{ if (lcd_busy()) //調用檢測忙標志函數從中判斷其工作狀態
{ LCD_DATATRIS=OUTPUT; //設為數據發送
RS=r_s; //0=寫指令, 1=寫數據
RW=0; //寫操作
E=1;
LCD_DATA=lcddata; //送入數據
NOP();
NOP();
E=0; //寫入HD44780
break;
}
}
}
函數中帶有兩個字符型形式參數,用于載入主調函數的實參值,這樣做的好處是使命令控制和數據傳送都統一由此函數完成,從而使程序變得更加精簡。對于4位數據寫也就多加一個時鐘周期,在這里就不再加以說明,請參考上面的。
有了以上的寫數據函數現在我們想建立一個HD44780初始化程序就簡單多了。
void lcd_init (void)
{ write_bytelcd(0X38,0); //8位接口2行顯示 5*7
write_bytelcd(8,0); //關顯示,光標不閃爍
write_bytelcd(1,0); //清屏
write_bytelcd(2,0); //AC清0
write_bytelcd(0xC,0); //開顯示
write_bytelcd(0X14,0); //光標右移,文字不動
}
以上命令參數讀者可以根據實際情況加以調整以滿足您現有模塊的顯示標準。
下面就以筆者在實際實驗中調試成功的范例加以組合,使其成為一個完整的顯示驅動程序。如果讀者還有不明白之處或者有更好的改進思路請EMAIL與我聯系,謝謝。
先定義顯示內容,建立一張顯示表:
const unsigned char Disp_tab[]=
{" <LCD Display> \
date:2007.01.18 \
layout:feng zhe jun \
qq:62363**** ^_^ \
Tel:137******** \
E-mail:fengzhejunmcu@21cn.com"
};//113(0-112)
建立一個延時函數,使每顯示完一行內容保留一段顯示時間.
void delayms (unsigned char i)
{ unsigned int k;
while (i)
{ i--;
for (k=800;k!=0;k--) ;
}
}
再建立一個主函數
void main (void)
{ unsigned int i;
unsigned char fg_ddram,ddram_ress,count=16;
unsigned char count1;
unsigned char data_lcd;
PORTA=0;
PORTB=0;
fg_ddram=ddram_ress=count1=0;
ddram_ress=0x80;
init_mcu();
lcd_init();
for (i=10000;i!=0;i--) {init_mcu();}
lcd_init();
while (1)
{ write_bytelcd( ddram_ress,0); //DDRAM地址設置
do{
data_lcd=Disp_tab[count1];
count1++;
write_bytelcd(data_lcd,1); //寫數據
if (count1>=113) count1=0;
delayms(30);
}
while (--count);
count=16;
++fg_ddram;
if (fg_ddram&0x1) ddram_ress=0xc0; //two
else
{ ddram_ress=0x80; //one
delayms(250);
lcd_init();
delayms(50);
}
}
}
以上程序只要再增加個頭文件和設置一下配置位就是一個完整的顯示驅動程序,筆者已經在MPLAB IDE 7.41+PICC8.05環境下調試通過,感興趣的讀者不妨一試。