與之前的MCU按鍵debounce移植代碼類似,MCULCD1602' style='outline-style: none;顏色: RGB(51, 51, 51); text-decoration: none;'LCD1602驅動代碼也可以移植到這裏。這個例程並非Bingo 原創。是根據一位“年少不識月”的網友的代碼編寫的。經過移植修改,最終定型為Bingo版本(O(_)O哈哈~)。
電路圖這裏就不解釋了,太簡單了。
1. 驅動說明
因為FPGA'style='outline-style: none;顏色: RGB(51, 51, 51);文本裝飾:無;' FPGA的高速並行運算不是順序執行的,代碼與MCU不同。這裏先解釋一下驅動原理:
(1)分頻得到固定頻率500KHz並對LCD1602進行初始化。如下圖,LCD_EN的頻率要控製在2M以內(不同的LCD1602參數會不同)。
(2)通過三階段狀態機初始化並提供數據。
(3)通過循環讀取某個“數組”,並將數據循環到LCD1602中,以接口的形式方便地進行更改。
2.FPGALCD1602 FSM
1. 代碼
/********************************************************
* 模塊名稱: lcd1602_driver
* 工程師: 瘋狂賓果
* 目標設備: EP2C8Q208C8
* 工具版本: Quartus II 11.0
* 創建日期: 2011-7-3
* 修訂版: v1.0
* 描述:
****************************************************** * /
模塊lcd1602_驅動程序
(
輸入時鍾,
輸入rst_n,
輸出lcd_en, //液晶屏使能
輸出reg lcd_rs, //記錄、語句
輸出液晶屏_rw,
輸出寄存器[7:0] lcd_data
);
參數[127:0] line_rom1='我是CrazyBingo!';
參數[127:0] line_rom2='Hello World*^_^*';
//----------------------------------------------------
reg [15:0] cnt;
始終@(posege clk或negedge rst_n)
開始
如果(!rst_n)
碳納米管=0;
別的
cnt=cnt + 1'b1;
結尾
賦值lcd_en=cnt[15]; //lcd使能,保持時間相同
賦值lcd_rw=1'b0; //隻寫
線cmd_flag=(cnt==16'h7FFF) ? 1'b1 : 1'b0; //當lcd_en穩定時,寫入cmd
//--------------------------------------------------------
//格雷碼: 40種狀態
參數IDLE=8'h00; //閑置的
//液晶屏初始化
參數DISP_SET=8'h01; //顯示模式
參數DISP_OFF=8'h03; //關閉顯示
參數CLR_SCR=8'h02; //清除液晶屏
參數CURSOR_SET1=8'h06; //光標設置
參數CURSOR_SET2=8'h07; //顯示時,光標設置
//顯示第1行
參數ROW1_ADDR=8'h05;
參數ROW1_0=8'h04;
參數ROW1_1=8'h0C;
參數ROW1_2=8'h0D;
參數ROW1_3=8'h0F;
參數ROW1_4=8'h0E;
參數ROW1_5=8'h0A;
參數ROW1_6=8'h0B;
參數ROW1_7=8'h09;
參數ROW1_8=8'h08;
參數ROW1_9=8'h18;
參數ROW1_A=8'h19;
參數ROW1_B=8'h1B;
參數ROW1_C=8'h1A;
參數ROW1_D=8'h1E;
參數ROW1_E=8'h1F;
參數ROW1_F=8'h1D;
//顯示第2行
參數ROW2_ADDR=8'h1C;
參數ROW2_0=8'h14;
參數ROW2_1=8'h15;
參數ROW2_2=8'h17;
參數ROW2_3=8'h16;
參數ROW2_4=8'h12;
參數ROW2_5=8'h13;
參數ROW2_6=8'h11;
參數ROW2_7=8'h10;
參數ROW2_8=8'h30;
參數ROW2_9=8'h31;
參數ROW2_A=8'h33;
參數ROW2_B=8'h32;
參數ROW2_C=8'h36;
參數ROW2_D=8'h37;
參數ROW2_E=8'h35;
參數ROW2_F=8'h34;
//--------------------------------------------------------
reg [5:0] 當前狀態,下一個狀態;
//FSM: 始終1
始終@(posege clk或negedge rst_n)
開始
如果(!rst_n)
當前狀態=空閑;
否則如果(cmd_flag)
當前狀態=下一個狀態;
結尾
//--------------------------------------------------------
//FSM: 總是2
總是@*
開始
案例(當前狀態)
//液晶屏初始化
空閑: next_state=DISP_SET;
DISP_SET : next_state=DISP_OFF;
DISP_OFF: next_state=CLR_SCR;
CLR_SCR : next_state=CURSOR_SET1;
CURSOR_SET1 : next_state=CURSOR_SET2;
CURSOR_SET2 : next_state=ROW1_ADDR;
//顯示第1行
ROW1_ADDR : next_state=ROW1_0;
ROW1_0 : next_state=ROW1_1;
ROW1_1 : next_state=ROW1_2;
ROW1_2 : next_state=ROW1_3;
ROW1_3 : next_state=ROW1_4;
ROW1_4 : next_state=ROW1_5;
ROW1_5 : next_state=ROW1_6;
ROW1_6 : 下一個狀態=ROW1_7;
ROW1_7 : next_state=ROW1_8;
ROW1_8 : 下一個狀態=ROW1_9;
ROW1_9 : next_state=ROW1_A;
ROW1_A : next_state=ROW1_B;
ROW1_B : next_state=ROW1_C;
ROW1_C : next_state=ROW1_D;
ROW1_D : 下一個狀態=ROW1_E;
ROW1_E : 下一個狀態=ROW1_F;
ROW1_F : next_state=ROW2_ADDR;
//顯示第2行
ROW2_ADDR : next_state=ROW2_0;
ROW2_0 : 下一個狀態=ROW2_1;
ROW2_1 : next_state=ROW2_2;
ROW2_2 : next_state=ROW2_3;
ROW2_3 : 下一個狀態=ROW2_4;
ROW2_4 : next_state=ROW2_5;
ROW2_5 : 下一個狀態=ROW2_6;
ROW2_6 : 下一個狀態=ROW2_7;
ROW2_7 : 下一個狀態=ROW2_8;
ROW2_8 : 下一個狀態=ROW2_9;
ROW2_9 : next_state=ROW2_A;
ROW2_A : next_state=ROW2_B;
ROW2_B : 下一個狀態=ROW2_C;
ROW2_C : next_state=ROW2_D;
ROW2_D : 下一個狀態=ROW2_E;
ROW2_E : 下一個狀態=ROW2_F;
ROW2_F : next_state=ROW1_ADDR;
默認: next_state=IDLE;
端殼
結尾
//--------------------------------------------------------
//FSM: 總是3
始終@(posege clk或negedge rst_n)
開始
如果(!rst_n)
開始
液晶屏_RS=0;
液晶數據=8'hXX;
結尾
否則如果(cmd_flag)
開始
//寫語句
案例(下一個狀態)
空閑: lcd_rs=0; //陳述
//液晶屏初始化
DISP_SET : lcd_rs=0; //陳述
DISP_OFF: lcd_rs=0; //陳述
CLR_SCR : lcd_rs=0; //陳述
CURSOR_SET1 : lcd_rs=0; //陳述
CURSOR_SET2 : lcd_rs=0; //陳述
//顯示第1行
ROW1_ADDR : lcd_rs=0; //陳述
ROW1_0 : lcd_rs=1; //記錄
ROW1_1 : lcd_rs=1; //記錄
ROW1_2 : lcd_rs=1; //記錄
ROW1_3 : lcd_rs=1; //記錄
ROW1_4 : lcd_rs=1; //記錄
ROW1_5 : lcd_rs=1; //記錄
ROW1_6 : lcd_rs=1; //記錄
ROW1_7 : lcd_rs=1; //記錄
ROW1_8 : lcd_rs=1; //記錄
ROW1_9 : lcd_rs=1; //記錄
ROW1_A : lcd_rs=1; //記錄
ROW1_B : lcd_rs=1; //記錄
ROW1_C : lcd_rs=1; //記錄
ROW1_D : lcd_rs=1; //記錄
ROW1_E : 液晶屏_rs=1; //記錄
ROW1_F : lcd_rs=1; //記錄
//顯示第2行
ROW2_ADDR : lcd_rs=0; //陳述
ROW2_0 : lcd_rs=1; //記錄
ROW2_1 : lcd_rs=1; //記錄
ROW2_2 : lcd_rs=1; //記錄
ROW2_3 : lcd_rs=1; //記錄
ROW2_4 : lcd_rs=1; //記錄
ROW2_5 : lcd_rs=1; //記錄
ROW2_6 : lcd_rs=1; //記錄
ROW2_7 : lcd_rs=1; //記錄
ROW2_8 : lcd_rs=1; //記錄
ROW2_9 : lcd_rs=1; //記錄
ROW2_A : lcd_rs=1; //記錄
ROW2_B : lcd_rs=1; //記錄
ROW2_C : lcd_rs=1; //記錄
ROW2_D : lcd_rs=1; //記錄
ROW2_E : 液晶屏_rs=1; //記錄
ROW2_F : lcd_rs=1; //記錄
端殼
//寫入液晶數據
案例(下一個狀態)
空閑: lcd_data=8'hxx;
//液晶屏初始化
DISP_SET : 液晶數據=8'h38; //設置16X2,5X7,8位記錄
DISP_OFF: lcd_data=8'h08; //關閉顯示
CLR_SCR : lcd_data=8'h01; //清除液晶屏
CURSOR_SET1 : lcd_data=8'h06; //光標設置
CURSOR_SET2 : lcd_data=8'h0C; //展示中
//顯示第1行
ROW1_ADDR : lcd_data=8'h80;
ROW1_0 : lcd_data=line_rom1[127:120];
ROW1_1 : lcd_data=line_rom1[119:112];
ROW1_2 : lcd_data=line_rom1[111:104];
ROW1_3 : lcd_data=line_rom1[103: 96];
ROW1_4 : lcd_data=line_rom1[95: 88];
ROW1_5 : lcd_data=line_rom1[87: 80];
ROW1_6 : lcd_data=line_rom1[79: 72];
ROW1_7 : lcd_data=line_rom1[71: 64];
ROW1_8 : lcd_data=line_rom1[63: 56];
ROW1_9 : lcd_data=line_rom1[55: 48];
ROW1_A : lcd_data=line_rom1[47: 40];
ROW1_B : lcd_data=line_rom1[39: 32];
ROW1_C : lcd_data=line_rom1[31: 24];
ROW1_D : lcd_data=line_rom1[23: 16];
ROW1_E : lcd_data=line_rom1[15: 8];
ROW1_F : lcd_data=line_rom1[7: 0];
//顯示第2行
ROW2_ADDR : lcd_data=8'hC0;
ROW2_0 : lcd_data=line_rom2[127:120];
ROW2_1 : lcd_data=line_rom2[119:112];
ROW2_2 : lcd_data=line_rom2[111:104];
ROW2_3 : lcd_data=line_rom2[103: 96];
ROW2_4 : lcd_data=line_rom2[95: 88];
ROW2_5 : lcd_data=line_rom2[87: 80];
ROW2_6 : lcd_data=line_rom2[79: 72];
ROW2_7 : lcd_data=line_rom2[71: 64];
ROW2_8 : lcd_data=line_rom2[63: 56];
ROW2_9 : lcd_data=line_rom2[55: 48];
ROW2_A : lcd_data=line_rom2[47: 40];
ROW2_B : lcd_data=line_rom2[39: 32];
ROW2_C : lcd_data=line_rom2[31: 24];
ROW2_D : lcd_data=line_rom2[23: 16];
ROW2_E : lcd_data=line_rom2[15: 8];
ROW2_F : lcd_data=line_rom2[7: 0];
端殼
結尾
結尾
終端模塊
2. 狀態機
(1) 狀態機如下圖所示:
(2)模塊可分為以下狀態:
3.“Hello World”實體展示
參數[127:0] line_rom1='我是CrazyBingo!';
參數[127:0] line_rom2='Hello World*^_^*';