- 功能描述:
透過寫入指令或資料,控制內部的驅動晶片,從而實現在LCD螢幕上顯示字串:
- 設計方案:
設計將以有限狀態機的形式完成功能設計,其中涉及的狀態及相關功能如下圖1所示,
CGRAM_ADDR前面均為LCD初始化狀態,不多贅述。CGRAM_ADDR狀態下,傳送指令:要寫入CGRAM,地址為00H;下面CGRAM_WRITE狀態下,傳送資料:其中字模資料為8行八列資料,不能一次傳入,故設計一計數器,若計數到7,則跳轉下一狀態ADDR1,否則繼續CGRAM_WRITE狀態直到完成一個字元的寫入;ADDR1和ADDR2狀態下均傳送指令:要寫入DDRAM,地址分別為00H和40H,完成後均跳轉到WRITE_DDRAM狀態;WRITE_DDRAM也需要一計數器來監控傳到了第幾行 以及是否傳送完畢,結束後跳轉至STOP狀態,維持當下顯示。
下面將說明具體實現。
①使能訊號的生成: 當LCD的時脈頻率設定錯誤時,LCD的顯示就會閃,或者沒有顯示,故選擇控制使能訊號的週期生成,來達到設計要求的500Hz,這裡選擇的是計數方法,已知我們的初始時鐘是CLOCK_50,若每逢上升沿計數,為生成500Hz的工作時鐘,需每逢計數99999,進行一次歸零進入下一計數週期,並設定使能訊號LCD_EN,每逢49999進行一次翻轉,即可對應得到使能訊號;
②延時15ms的實現: 在空閒IDLE狀態下,需延時15ms進入下一狀態,綜合考慮電路效能,選擇以計數的形式來實現,同上①;
③LCD的顯示: 在LCD上顯示字元的過程就是向DDRAM的相應地址寫入資料的過程,其中DDRAM地址與顯示位置的對應關係如下圖2所示。若想要在LCD的第一行最左顯示字母A,則過程為:傳指令DDRAM地址00H\({→}\)傳資料字母A(41H)。
④自定義字元的實現: 在晶片中內建了192個常用字元的字模,存於CGROM中,可以實現基本數字和字母的直接呼叫顯示(如上文中字母A),此外還有8個允許使用者自定義字元的CGRAM,即為下圖3中綠框中所示,我們可以透過先將自定義字元寫入CGRAM,再調入寫入DDRAM的方法實現自定義字元的顯示,下面以字元\({❤}\)為例加以說明:
- 取字模: 將圖形轉換為二進位制數,顯示出來的部分置1,未顯示的部分置0,如下圖4所示,可以得到8列八位資料;
- 寫入CGRAM: 寫入CGRAM的指令如下圖5所示,其中CGRAM的地址為00H-0FH,這裡我們選擇寫入地址為00H,將上面得到的8列八位資料依次寫入CGRAM,則CGROM中00H就代表了字元\({♥}\);
-
顯示: 即將地址指標指向DDRAM即可,寫入資料為00H。
-
關鍵程式碼:
/***main_FSM***/
//Section1
always@(posedge clk, negedge rstn) begin
if(!rstn) cur_state <= IDLE;
else if(cnt_500hz == 17'b01100001101001111)
cur_state <= next_state;
end
//Section2
always @(cur_state) begin
case(cur_state)
IDLE: begin
if(flag) next_state = CLEAR_LCD;
else next_state = IDLE;
end
CLEAR_LCD: next_state = SET_DISP_MODE;
SET_DISP_MODE: next_state = DISP_ON;
DISP_ON: next_state = SHIFT_DOWN;
SHIFT_DOWN: next_state = CGRAM_ADDR;
CGRAM_ADDR: next_state = WRITE_CGRAM;
WRITE_CGRAM: begin
if(cnt_cgram == 4'd7) next_state = ADDR1;
else next_state = WRITE_CGRAM;
end
ADDR1: next_state <= WRITE_DDRAM;
WRITE_DDRAM: begin
if(cnt_char == 6'd15) next_state = ADDR2;
else if(cnt_char == 6'd31) next_state = STOP;
else next_state = WRITE_DDRAM;
end
ADDR2: next_state = WRITE_DDRAM;
STOP: next_state = STOP;
default: next_state = IDLE;
endcase
end
//Section3
always @(posedge clk, negedge rstn) begin
if(!rstn) begin
lcd_rs <= 1'b0;
lcd_data <= 8'b00000000;
end
else begin
case(cur_state)
IDLE: begin lcd_rs<=1'b0; lcd_data<=8'b00000000; end
CLEAR_LCD: begin lcd_rs<=1'b0; lcd_data<=8'b00000001; end
SET_DISP_MODE: begin lcd_rs<=1'b0; lcd_data<=8'b00111000; end
DISP_ON: begin lcd_rs<=1'b0; lcd_data<=8'b00001100; end
SHIFT_DOWN: begin lcd_rs<=1'b0; lcd_data<=8'b00000110; end
CGRAM_ADDR: begin lcd_rs<=1'b0; lcd_data<=8'b01000000; end
WRITE_CGRAM: begin lcd_rs<=1'b1; lcd_data<=char_heart[cnt_cgram]; end
ADDR1: begin lcd_rs<=1'b0; lcd_data<=8'b10000000; end
WRITE_DDRAM: begin lcd_rs<=1'b1; lcd_data<=char; end
ADDR2: begin lcd_rs<=1'b0; lcd_data<=8'b11000000; end
STOP: begin lcd_rs<=1'b0; lcd_data<=8'b00111000; end
default: begin lcd_rs<=1'b0; lcd_data<=8'b00111000; end
endcase
end
end
- 綜合結果:
頂層模組的綜合結果如下圖6所示,僅有一lcd1602模組;
lcd1602模組的綜合結果如下圖7所示,無LATCH;
得到的狀態轉移圖如下圖8所示,與設計思路相符合;
SUMMARY的結果如下圖9所示。
- 顯示結果: