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