要實現(xiàn)對16x2點陣字符液晶模塊的高效控制,必須按照模塊設計方式,建立起相關的子程序,下面先詳細介紹驅動16x2點陣字符液晶模塊的各功能子程序。
1.寫命令到LCM子函數(shù)
vOidLCDWriteCommand(uchar CMD,uchar Attribc)
/*函數(shù)名為WriteCommandLCM的寫指令到LCM子函數(shù)。
定義CMD、Attribc 為無符號字符型變量。*/
{
if(Attribc)WaitForEnable();
/*若Arrribc為“真”,則調用WaitForEnable子函數(shù)進行忙檢測*/
LCM_RS_0;LCM_RW_0;_NOP0;
/*選中指令寄存器,寫模式*/
DataPort=CMD;_NOP();
/*將變量WCLCM中的指令傳送至數(shù)據(jù)口
LCM_EN_1;_NOP0;_NOP();LCM_EN_O:
/*LCM_EN端產(chǎn)生脈沖下降沿。*/
}
/*WriteCommandLCM 子函數(shù)結束。*/
2,寫數(shù)據(jù)到LCM子函數(shù)
void LcdWritEDAta(dchar dataW)
/*函數(shù)名為WriteDataLCM的寫數(shù)據(jù)到LCM子函數(shù)。定義
dataW 為無符號字符型變量。*/
{
?。?WriteDataLCM子函數(shù)開始。*/
WaitForEnable(); */
LCM_RS_1;LCM_RW_0;_NOP0;
/*選中數(shù)據(jù)寄存器,寫模式。*/
DataPort=dataW;_NOP();
/*將變量dataQW中數(shù)據(jù)傳送至數(shù)據(jù)口。*/
LCM_EN_1;_NOP();_NOP0;LCM_EN_O:
/*LCM_EN端產(chǎn)生脈沖下降沿。WriteDataLCM子函數(shù)
結束*/
3.檢測LCD忙信號子函數(shù)
void WaitForEnable(void)
?。?函數(shù)名為WaitForEnable的檢測忙信號子程序子函數(shù)。
/*WaitForEnable子函數(shù)開始。*/
uchar val;
/*定義局部變量val。*/
DataPOrt=Oxff;
/*置數(shù)據(jù)口為全1。*/
LCM_RS_0;LCM_RW_1;_NOP();
/*選中指令寄存器,讀模式。*/
LCM_EN_1;_NOP();_NOP();
/*置LCM_EN端為高電平,讀使能。*/
DDRA=0x00;
/*數(shù)據(jù)口置為輸入*/
val=PINA:
/*讀取數(shù)據(jù)*/
while(val&Busy)val=PINA:
/*檢測忙信號。當數(shù)據(jù)口內(nèi)容與0x80相與后不為零時,
程序原地踏步繼續(xù)讀取數(shù)據(jù)并檢測忙信號。*/
LCM_EN_O:
/*置LCM_EN端為低電平。*/
DDRA=0xff;
/*數(shù)據(jù)口置為輸出*/
}
/*WaitForEnable子函數(shù)結束。*/
4.顯示光標定位子函數(shù)
voidLOCateXY(char posx.char posy)
/*顯示光標定位子函數(shù),函數(shù)名為LocareXY,定義posx,
posxxy為字符型變量。*/
{
/*LocateXY子函數(shù)開始。*/
uchar temp;
/*定義temp為無符號字符型變量。*/
temp&=0x7f;
/*temp的變化范圍0-15。*/
temp=posx&0xof;
/*屏蔽高4位。*/
posy&=0x01;
/*posy的變化范圍0-1。*/
if(posy)tempㄧ=0x40;
/*若posy為1(顯示第二行),地址碼+0x40*/
tempㄧ=0x80;
/*指令碼為地址碼+0x80。*/
WriteCommandLCM(temp,0);
?。?將指令temp寫入LCM,忽略忙信號檢測。*/
}
/*LocateXY子函數(shù)結束。*/
5.顯示指定座標的一個字符(x=0~15,y=0~1)子函數(shù)
void DisplayOneChar(uchar x,uchar y,uchar Wdata)
/*顯示指定座標的一個字符(x=0-15.y=0-1)子函數(shù),函
數(shù)名為DispOneChar,定義x、y、Wdata為無符號字符型變量。
*/
{
/*DispOneChar函數(shù)開始*/
LocateXY(x,y):
?。?調用LocateXY函數(shù)定位顯示地址。*/
WriteDataLCM(Wdata);
?。?將數(shù)據(jù)Wdata寫入LCM。*/
}
/*DispONeChar函數(shù)結束。*/
6.演示第二行移動字符串子函數(shù)
void Display(uchar dd)
/*演示第二行移動字符串子函數(shù),函數(shù)名為Dispiay,定義
dd為無符號字符型變量。*/
{
/*Display子函數(shù)開始。*/
uchari:
/*定義;為無符號字符型變量。*/
for(i=O;i<16:i++){
/*進入for語句循環(huán)。*/
DisplayOneChar(i,1,dd++);
/*顯示單個字符。*/
dd&=Ox7f;
?。?dd的變化范圍0-127。*/
if(dd<32)dd=32:
/*dd的最小值為32,這樣dd的變化范圍為32-127。*/
}
/*for語句結束。*/
}
?。?Display函數(shù)結束。*/
7.顯示指定座標的一串字符子函數(shù)
void ePutstr(uchar x.uchar v,uchar code *ptr)
?。?顯示指定座標的一串字符(x=0-15,y=0-1)子函數(shù),函
數(shù)名為ePutstr,定義x、y為無符號字符型變量,ptr為指向
code區(qū)的無符號字符型指針變量。*/
{
/*ePutetr子函數(shù)開始。*/
uchar i,I=O;
/*定義i,i為無符號字符型變量。*/
while(ptr[I]>31)(I++;}
/*ptr[I]大于31時,為ASCII碼,進入While語句循環(huán),I累
加,計算出字符串長度。*/
for(i=0;i
/*進入for語句循環(huán)。*/
DisplayOneChar(x++,y,ptr[i]);
/*顯示單個字符,同時x軸座標遞增。*/
if(x==1 6){
/*若x等于16,進入if語句。*/
x=O;y^=1;
/*x賦0,y與1按位異或(取反)。*/
}
/*if語句結束。*/
}
/*for語句結束。*/
}
/*ePutstr子函數(shù)結束。*/
8.在AVR單片機綜合試驗板上實現(xiàn)16x2LCM演示程序1
第一行顯示“-This is a LCD-!”,第二行的第1個字符位置
顯示“A”。過2秒后變?yōu)榈谝恍械牡?個字符位置顯示“B”,第
二行顯示“-Design by ZXH-!”。然后無限循環(huán)。
在我的文檔中新建一個ac18的文件夾。建立一個ac18.prj
的工程項目,最后建立源程序文件ac18 C。輸入下面的程序:
#include
/*包含頭文件*/
#include
/*------------------------------------------*/
#define uchar unsigned char
/*變量類型的宏定義*/
#define uint unsigned int
?。?----------------引腳電平的宏定義----------------*/
#define LCM_RS_1 PORTBㄧ=BIT(PB0)
/*RS腳輸出高電平的宏定義*/
#define LCM_RS_0 PORTB&=~BIT(PBO)
/*RS腳輸出低電平的宏定義*/
#define LCM_RW_1 PORTBㄧ=BIT(PB1)
/*RW腳輸出高電平的宏定義*/
#define LCM_RW_O PORTB&=~BIT(PB1)
/*RW腳輸出低電平的宏定義*/
#define LCM_EN_1 PORTBㄧ=BlT(PB2)
/*EN腳輸出高電平的宏定義*/
#define LCM_EN_0 PORTB&=~BIT(PB2)
/*EN腳輸出低電平的宏定義*/
/*===============================*/
#define DataPort PORTA
/*數(shù)據(jù)端口宏定義*/
#define Busy 0x80
/*忙信號的宏定義*/
#define xtaI 8
/*晶振頻率宏定義*/
/*===============================*/
const uchar str0[]={“-This is a LCD-!”}
/*待顯字符*/
const uchar str1 []={"-Design by ZXH-!"};
/*待顯示字符串*/
/*==============函數(shù)說明===================*/
void Delay_1 ms(void);
void Delay_nms(uint n):
void WaitFOrEnable(void):
void LcdWriteData(uchar W):
void LcdWriteCommand(uchar CMD,uchar Attribc);
void InitLcd(void);
void Display(uchar dd):
void DispIayoneChar(uchar×.uchar y,uchar Wdata);
void ePutstr(uchar x,uchar y,uchar const*ptr);
/**********************************************/
void main(void)
?。?定義主函數(shù)*/
{
Delay_nms(400);
/*延時400mS等待電源穩(wěn)定*/
DDRA=0xff;PORTA=0x00;
?。?初始化I*O口*/
DDRB=0xff;PORTB=0x00;
InitLcd();
/*LCD初始化*/
/**************************************/
while(1)
/*無限循環(huán)*/
{
LcdWriteCommand(0x01.1):
/*清屏*/
LcdWriteCommand(0xoc,1):
?。?開顯示*/
DisplayOneChar(O,1,0x41):
/*第二行的第1個字符位置顯示A*/
ePutstr(0.0.str0);
/*第一行顯示-This is a LCD-!*/
Delay_nms(2000);
/*延時2S*/
LcdWriteCommand(0x01.1):
?。?清屏*/
LcdWriteCommand(0xoc,1):
/*開顯示*/
DisplayOneChar(8,0,0x42);
/*第一行的第8個字符位置顯示B*/
ePutstr(0.1,str1):
/*第二行顯示-Design by AXH-!*/
Delay_nms(2000);
/*延時2S*/
}
}
/*************顯示指定座標的一串字符子函數(shù)***************/
void ePutstr(uchar x,uchar y,uchar const*ptr)
{
uchar i.I=0:
while(ptr[I]>31){I++;)
for(i=0;i
DisplayoneChar(x++,Y,pt r[i]);
if(X==16){
x=0;y^=1:
}
}
}
/***************
void LocateXY(char posx,char posy)
{
uchar temp;
temp&=0x7f;
temp=posx&0xof;
posy&=0x01;
if(posy)templ=0x40;
templ=0x80;
LcdWriteCommand(temp,0):
}
/**************顯示指定座標的一個字符子函數(shù)************/
void DisplayOneChar(uchar X.uchar y,uchar Wdata)
{
LocateXY(x,y):
LcdWriteData(Wdata);
}
/**************LCD初始化子函數(shù)******************/
void lnitLcd(void)
{
LcdWriteCommand(0x38,O):
/*8位數(shù)據(jù)傳送,2行顯示,5*7字形,不檢測忙信號*/
Delay_nms(5);
LcdWriteCommand(Ox38,O):
/*8位數(shù)據(jù)傳送;2行顯示,5*7字形,不檢測忙信號*/
Delay_nms(5);
LcdWriteCommand(0x38.0):
/*8位數(shù)據(jù)傳送,2行顯示,5*7字形,不檢測忙信號*/
Delay_nms(5);
LcdWriteCommand(0x38,1):
/*8位數(shù)據(jù)傳送,2行顯示,5/7字形、檢測忙信號*/
LcdWriteCommand(0x08,1):
?。?關閉顯示,檢測忙信號*/
LcdWriteCommand(0x01,1);
/*清屏,檢測忙信號*/
LcdWriteCommand(0x06,1):
?。?顯示光標右移設置,檢測忙信號*/
LcdWriteCommand(0xoc,1):
?。?顯示屏打開,光標不顯示、不閃爍,檢測忙信號*/
}
?。?***************寫命令到LCM子函數(shù)*******************/
void LcdWfiteCommand(uchar CMD,uchar Attribc)
{
if(Attribc)WaitForEnable():
LCM_RS_0;LCM_RW_0;_NOP();
DataPort=CMD;_NOP();
LCM_EN_1;_NOP0;_NOP();LCM_EN_O;
}
/***************寫數(shù)據(jù)到LCM子函數(shù)***************/
voidLEDWriteData(uchar dataW)
{
WaitF0rEnable();
LCM_RS_1;LCM_RW_O;_NOP();
DataPort=dataW;_NOP();
LCM_EN_1:_NOP();_NOP();LCM_EN_0;
}
?。?***********檢測LCD忙忙信號子函數(shù)**************/
void WaitFOrEnable(vOid)
{
uchar val;
DataPort=0xff;
LCM_RS_0;LCM_RW_1;_NOP();
LCM_EN_1:_NOP0;_NOP();
DDRA=0x00;
vaI=PINA;
while(val&Busy)val=PINA;
LCM_EN_O;
DDRA=0xff;
}
/************************************************/
void Delay_1 ms(void)
/*1mS延時子函數(shù)*/
{ uint i;
for(i=1;i<(uint)(xtal*143-2):i++)
}
/*==========================*/
void Delay_nms(uint n)
?。?n*1mS延時子函數(shù)*/
{
uint i=0:
while(i
{Delay_1 ms();
i++:
}
}
編譯通過后,將ac18.hex文件下載到AVR單片機綜合試驗板上進行實際演示。標示“LCD16*2”的單排座上正確插上16x2液晶模塊(腳號對應,不能插反),在標示“DC5V”電源端輸入5V穩(wěn)壓電壓。我們看到液晶屏上的顯示與我們設計的目標完全一致。
9.在AVR單片機綜合試驗板上實現(xiàn)16x2LCM演示程序--2一開始第一行及第二行顯示預定的字符串(第一行顯示“--ELECTRONICS--”,第二行顯示“WORLDMAgazine”),隨后第二行顯示移動的ASCII字符。
在我的文檔中新建一個acl9的文件夾。建立一個acl9.pri的工程項目,最后建立源程序