1602應該說是很簡單的一種器件,但是許多人初次使用的時候可能總是出問題,當然可能也有一次就試驗成功的,但是像我這樣的在AVR ATMega16上調1602居然花了近3天的時間,最后調到快崩潰的地步,對自己的智商和水平都產生了懷疑,最后解決問題卻是充滿了戲劇性。解決問題期間在OURAVR上查找了許多帖子,最后才在馬超老師的一句話里發現了答案呵呵,所以我把我調1602液晶時遇到的情況描述一遍供大家參考,算是給AVRFans積攢一點資料。
硬件資料:AVR ATMega16,工作在外部晶振11.0592MHz,MS1602C字符液晶
狀態1
上電之后,1602的第一行全黑,即16個5x7黑塊
產生原因:液晶根本就沒有進行初始化操作,需要檢查連線或者程序
狀態2
屏上顯示兩排灰格
產生原因:程序中對液晶初始化不正常,應是部分初始化指令沒有正常接收,建議按照標準初始化步驟調整程序,或者調整指令之間的延時(加大一些試試)----補充:也有可能是對比度太大,建議調整對比度電阻
這個也可以用來做判斷液晶是否工作正常,即使程序不工作,將對比度調大,也可以看到黑塊的。
狀態3
此種不用解釋了呵呵,調通了已經
1602液晶大概就這三種狀態了,我調的時候很費勁,8位數據線方式接在PC口怎么都不出字符,怎么調延時都沒用,總是顯示兩行灰格,最后看見馬老師的提示,PC口有4個線默認是給JTAG用的,默認狀態不做IO口,于是重新將數據線接在PB口修改程序重新燒寫后就好使~
另外,我還發現,1602數據線接在PB口時,有時候上電之后顯示工作正常,但有些時候根本就不工作,懷疑是ISP下載線有影響,拔去下載線,恢復正常。
下面附上我的初始化程序,參考了OURAVR上的一個帖子,具體是哪個我忘了不好意思,有所調整,按照太陽人那個數據手冊里面推薦步驟進行的:
/*
本程序實現功能:在1602液晶屏上顯示預期字符
硬件平臺:AVR ATMega16,外部晶振11.0592MHz
2007.01.04
MYBlog--http://avrnewbie.21ic.org/
*/
#define LCDPORT PORTB //數據總線在PB口
#define LCDDDR DDRB
#define LCDPIN PINB
#define En_H PORTA |= _BV(PA2) //sbi(PORTA,2) //En接Pa2
#define En_L PORTA &= ~_BV(PA2) //cbi(PORTA,2)
#define RW_R PORTA |= _BV(PA0) //sbi(PORTA,0) //RW接Pa0
#define RW_W PORTA &= ~_BV(PA0) //cbi(PORTA,0)
#define RS_H PORTA |= _BV(PA3) //sbi(PORTA,3) //RS接Pa3
#define RS_L PORTA &= ~_BV(PA3) //cbi(PORTA,3)
#define DelaytE _delay_us(2)
//#define Clear_Screen Write_Command(0x01)
//延時程序
void Delay(uint16_t time)
{
while(time>0)
{
time--;
}
}
//產生一個使能脈沖
void En_Toggle(void)
{
En_H; //拉高使能位
DelaytE; //保持高電平一定時間
En_L; //拉低使能位,產生一個下降沿
DelaytE; //保持低電平一定時間
}
//不斷檢測LCD忙標志BF,直到其為0,表示可以執行下一條指令
void Wait_Until_Ready(void)
{
LCDDDR = 0x00; //單片機設為輸入,用以讀取LCD忙標志
RS_L; //所讀為狀態位
RW_R; //設為讀狀態
DelaytE;
En_H;
DelaytE;
loop_until_bit_is_clear(LCDPIN,7); //不斷循環,直至BF=0
En_L;
}
void Write_Command(uint8_t Command,uint8_t busyFlag)
{
uint8_t busy;
busy = busyFlag;
if (busy == 1) //busy=1表示系統希望檢測忙信號
Wait_Until_Ready(); //等待指令執行完畢
LCDDDR = 0xff;
RS_L; //寫入的是命令字
RW_W; //置為寫狀態
LCDPORT = Command;
_delay_us(25);
En_Toggle(); //產生使能脈沖,使之在下降沿開始執行指令
}
void Write_Data(uint8_t data)
{
Wait_Until_Ready(); //等待指令執行完畢
RS_H; //寫入的是數據
RW_W; //置為寫狀態
LCDDDR = 0xff;
LCDPORT = data;
En_Toggle(); //產生使能脈沖,使之在下降沿開始執行指令
}
void Initialize_LCD(void)
{ //主程序中在進入初始化程序前已經延時400ms
LCDDDR = 0xff; //LCD控制線在PD口,故將其設為輸出
//此處可以根據實際情況調整,或者在主程序中設置
DDRA = 0xff; //E\RS\RW等接在PA口
_delay_ms(15);
Write_Command(0x38,0); //設為8位接口模式,顯示2行字符,busy=0不檢測忙信號
_delay_ms(5);
Write_Command(0x38,0);
_delay_ms(5);
Write_Command(0x38,0);
Write_Command(0x38,1);
Write_Command(0x08,1); //顯示關閉
Write_Command(0x01,1); //顯示清屏
Write_Command(0x06,1); //寫入新數據后光標右移
Write_Command(0x0f,1); //顯示功能開,顯示光標
}