开发工具:Quartus II 9.1;
仿真软件:Questa Sim 10.0c;
硬件平台:Terasic DE2-115(EP2C35F672C6);
外设:hd44780控制器lcd1602;
3个工程文件:"lcd1602_cgram_controller.v" + "lcd1602_cgram_driver.v" + "lcd1602_cgram_driver_tsb.v";
设计思路:
底层直接操作lcd1602的模块为"*_controller.v"文件,三段式状态机,完成初始化液晶工作模式(无光标、5X8、2行...)、在CGRAM写入自定义的8个字符(源文件里条形图,可用于音频FFT波形图显示),完成CGRAM写数据之后进入通用的显示状态,每次显示完一个字符产生的ack信号;
"_driver.v"完成循环调用显示8个自定义字符;
"_driver_tsb.v"完成仿真时的驱动(原本是和"_driver.v"在同一个文件,为了方便后续综合,分开了);
注意事项:
系统工作频率为50MHz,lcd操作的指令、数据周期为2ms(1ms下也能用);
CYCLONEII的芯片上电未复位之前的寄存器是0,因此程序下载到板子上的时候液晶是不显示的,没有复位引脚的需要自行设计软件复位;
lcd_on,lcd_blon为DE2-115板子特有设计;
源码1...
1 `timescale 1 ns / 1 ps 2 //`define SIM 3 `define SYS_CLK 50_000_000 4 //achieve lcd1602 cgram display 5 //author wuyuehang1990 6 //version 0.1 7 module lcd1602_cgram_controller( 8 sys_clk, 9 sys_rst_n, 10 sys_dat_i, 11 sys_addr_i, 12 lcd_ack_o, 13 lcd_en, 14 lcd_rw, 15 lcd_rs, 16 lcd_bus, 17 lcd_on, 18 lcd_blon 19 ); 20 21 input sys_clk; 22 input sys_rst_n; 23 input [7:0] sys_dat_i;//CGRAM ONLY DISP 8 DIFFERENT FONTS//00~07 24 input [7:0] sys_addr_i;//DDRAM ADDR 25 output reg lcd_ack_o; 26 //lcd interface 27 output lcd_en; 28 output lcd_rw; 29 output reg lcd_rs; 30 output reg [7:0] lcd_bus; 31 //spec io 32 output lcd_on; 33 output lcd_blon; 34 35 36 `ifdef SIM 37 parameter ST_WIDTH = 64; 38 parameter CLR = "CLR....."; 39 parameter FUNC = "FUNC...."; 40 parameter ONOFF = "ON/OFF.."; 41 parameter ENTRY = "ENTRY..."; 42 parameter SETCGRAM = "SETCGRAM"; 43 parameter WRCGRAM = "WR_CGRAM"; 44 parameter SETDDRAM = "SETDDRAM"; 45 parameter WRDDRAM = "WR_DDRAM"; 46 parameter ACK = "ACK....."; 47 `else 48 `define FSM 9 49 parameter ST_WIDTH = `FSM; 50 parameter CLR = `FSM'b0_0000_0001;//01 51 parameter FUNC = `FSM'b0_0000_0010;//38(8BUS-2LINE) 37(8BUS-1LINE) 52 parameter ONOFF = `FSM'b0_0000_0100;//0C(ON-SHINE) 53 parameter ENTRY = `FSM'b0_0000_1000;//06(DISP_FIXED-CURSOR_SHIFT) 54 parameter SETCGRAM = `FSM'b0_0001_0000; 55 parameter WRCGRAM = `FSM'b0_0010_0000; 56 parameter SETDDRAM = `FSM'b0_0100_0000; 57 parameter WRDDRAM = `FSM'b0_1000_0000; 58 parameter ACK = `FSM'b1_0000_0000; 59 60 `endif 61 62 //generate 1KHz(1ms) 63 reg [19:0] cnt_1KHz=0; 64 reg clk_1KHz=0; 65 reg pulse1ms=0; 66 67 always @ (posedge sys_clk) begin 68 if(sys_rst_n == 1'b0) begin 69 cnt_1KHz <= 0; 70 end 71 else if(cnt_1KHz > 20'd99999) begin 72 cnt_1KHz <= 0; 73 end 74 else begin 75 cnt_1KHz <= cnt_1KHz + 1'd1; 76 end 77 end 78 79 always @ (posedge sys_clk) begin 80 if(cnt_1KHz < 20'd49999) begin 81 clk_1KHz <= 1'd1; 82 end 83 else begin 84 clk_1KHz <= 1'd0; 85 end 86 end 87 88 always @ (posedge sys_clk) begin 89 if(cnt_1KHz == 20'd99999) pulse1ms <= 1'd1; 90 else pulse1ms <= 1'd0; 91 end 92 93 //generate lcd_en,lcd_rw; 94 assign lcd_en = clk_1KHz; 95 assign lcd_rw = 1'b0; 96 //generate spec io 97 assign lcd_on = 1'b1; 98 assign lcd_blon = 1'b1; 99 100 //FSM 101 reg [5:0] cnt64=0;//count 64 hex char 102 reg [ST_WIDTH-1:0] c_st = FUNC; 103 reg [ST_WIDTH-1:0] n_st = FUNC; 104 //fsm-1 105 always @ (posedge sys_clk) begin 106 if(1'b0 == sys_rst_n) c_st <= FUNC; 107 else c_st <= n_st; 108 end 109 110 //fsm-2 111 always @ (*) begin 112 n_st = FUNC; 113 case(c_st) 114 FUNC:begin 115 n_st = (pulse1ms == 1'b1)?ONOFF:FUNC; 116 end 117 ONOFF:begin 118 n_st = (pulse1ms == 1'b1)?ENTRY:ONOFF; 119 end 120 ENTRY:begin 121 n_st = (pulse1ms == 1'b1)?CLR:ENTRY; 122 end 123 CLR:begin 124 n_st = (pulse1ms == 1'b1)?SETCGRAM:CLR; 125 end 126 SETCGRAM:begin 127 n_st = (pulse1ms == 1'b1)?WRCGRAM:SETCGRAM; 128 end 129 WRCGRAM:begin 130 if((pulse1ms == 1'b1) && (cnt64 == 6'd63)) 131 n_st = SETDDRAM; 132 else if(pulse1ms == 1'b1) 133 n_st = SETCGRAM; 134 else 135 n_st = WRCGRAM; 136 end 137 SETDDRAM:begin 138 n_st = (pulse1ms == 1'b1)?WRDDRAM:SETDDRAM; 139 end 140 WRDDRAM:begin 141 n_st = (pulse1ms == 1'b1)?ACK:WRDDRAM; 142 end 143 ACK:begin 144 n_st = SETDDRAM; 145 end 146 default:begin 147 n_st = FUNC; 148 end 149 endcase 150 end 151 152 //FSM-3 153 //generate lcd_bus lcd_rs and lcd_ack 154 155 always @ (posedge sys_clk) begin 156 if(1'b0 == sys_rst_n) begin 157 lcd_ack_o <= 0; 158 lcd_rs <= 0; 159 lcd_bus <= 8'h38; 160 cnt64 <= 0; 161 end 162 else begin 163 case(n_st) 164 FUNC:begin 165 lcd_rs <= 0; 166 lcd_ack_o <= 0; 167 lcd_bus <= 8'h38;//3c(2-line-5*10)//38(2-line-5*8) 168 cnt64 <= 6'd63; 169 end 170 ONOFF:begin 171 lcd_rs <= 0; 172 lcd_ack_o <= 0; 173 lcd_bus <= 8'h0d;//no cursor 174 cnt64 <= 6'd63; 175 end 176 ENTRY:begin 177 lcd_rs <= 0; 178 lcd_ack_o <= 0; 179 lcd_bus <= 8'h06; 180 cnt64 <= 6'd63; 181 end 182 CLR:begin 183 lcd_rs <= 0; 184 lcd_ack_o <= 0; 185 lcd_bus <= 8'h01; 186 cnt64 <= 6'd63; 187 end 188 SETCGRAM:begin 189 lcd_ack_o <= 0; 190 lcd_rs <= 0; 191 cnt64 <= (pulse1ms == 1'b1)?cnt64 + 1'd1:cnt64; 192 lcd_bus <= {2'b01,cnt64}; 193 end 194 WRCGRAM:begin 195 lcd_ack_o <= 0; 196 lcd_rs <= 1; 197 cnt64 <= cnt64; 198 /* 199 case(cnt64) 200 6'd0,6'd1,6'd2,6'd3,6'd4,6'd5,6'd6,6'd7:lcd_bus <= 8'h00;//empty 201 6'd8,6'd9,6'd10,6'd11,6'd12,6'd13:lcd_bus <= 8'h00; 202 6'd14:lcd_bus <= 8'h1f; 203 6'd15:lcd_bus <= 8'h00;//1step 204 6'd16,6'd17,6'd18,6'd19,6'd20:lcd_bus <= 8'h00; 205 6'd21,6'd22:lcd_bus <= 8'h1f; 206 6'd23:lcd_bus <= 8'h00;//2step 207 6'd24,6'd25,6'd26,6'd27:lcd_bus <= 8'h00; 208 6'd28,6'd29,6'd30:lcd_bus <= 8'h1f; 209 6'd31:lcd_bus <= 8'h00;//3step 210 6'd32,6'd33,6'd34:lcd_bus <= 8'h00; 211 6'd35,6'd36,6'd37,6'd38:lcd_bus <= 8'h1f; 212 6'd39:lcd_bus <= 8'h00;//4step 213 6'd40,6'd41:lcd_bus <= 8'h00; 214 6'd42,6'd43,6'd44,6'd45,6'd46:lcd_bus <= 8'h1f; 215 6'd47:lcd_bus <= 8'h00;//5step 216 6'd48:lcd_bus <= 8'h00; 217 6'd49,6'd50,6'd51,6'd52,6'd53,6'd54:lcd_bus <= 8'h1f; 218 6'd55:lcd_bus <= 8'h00;//6step 219 6'd56,6'd57,6'd58,6'd59,6'd60,6'd61,6'd62:lcd_bus <= 8'h1f; 220 6'd63:lcd_bus <= 8'h00;//7step 221 endcase 222 */ 223 case(cnt64) 224 6'd0,6'd1,6'd2,6'd3,6'd4,6'd5,6'd6:lcd_bus <= 8'h00; 225 6'd7:lcd_bus <= 8'h1f;//s1 226 6'd8,6'd9,6'd10,6'd11,6'd12,6'd13:lcd_bus <= 8'h00; 227 6'd14:lcd_bus <= 8'h1f; 228 6'd15:lcd_bus <= 8'h1f;//s2 229 6'd16,6'd17,6'd18,6'd19,6'd20:lcd_bus <= 8'h00; 230 6'd21,6'd22:lcd_bus <= 8'h1f; 231 6'd23:lcd_bus <= 8'h1f;//s3 232 6'd24,6'd25,6'd26,6'd27:lcd_bus <= 8'h00; 233 6'd28,6'd29,6'd30:lcd_bus <= 8'h1f; 234 6'd31:lcd_bus <= 8'h1f;//4step 235 6'd32,6'd33,6'd34:lcd_bus <= 8'h00; 236 6'd35,6'd36,6'd37,6'd38:lcd_bus <= 8'h1f; 237 6'd39:lcd_bus <= 8'h1f;//5step 238 6'd40,6'd41:lcd_bus <= 8'h00; 239 6'd42,6'd43,6'd44,6'd45,6'd46:lcd_bus <= 8'h1f; 240 6'd47:lcd_bus <= 8'h1f;//6step 241 6'd48:lcd_bus <= 8'h00; 242 6'd49,6'd50,6'd51,6'd52,6'd53,6'd54:lcd_bus <= 8'h1f; 243 6'd55:lcd_bus <= 8'h1f;//7step 244 6'd56,6'd57,6'd58,6'd59,6'd60,6'd61,6'd62:lcd_bus <= 8'h1f; 245 6'd63:lcd_bus <= 8'h1f;//8step 246 endcase 247 end 248 SETDDRAM:begin 249 lcd_ack_o <= 0; 250 lcd_rs <= 0; 251 lcd_bus <= sys_addr_i; 252 cnt64 <= cnt64; 253 end 254 WRDDRAM:begin 255 lcd_ack_o <= 0; 256 lcd_rs <= 1; 257 cnt64 <= cnt64; 258 lcd_bus <= sys_dat_i; 259 end 260 ACK:begin 261 lcd_ack_o <= 1; 262 lcd_rs <= 0; 263 lcd_bus <= lcd_bus; 264 cnt64 <= cnt64; 265 end 266 default:begin 267 lcd_ack_o <= 0; 268 lcd_rs <= 0; 269 lcd_bus <= 8'h38; 270 cnt64 <= cnt64; 271 end 272 endcase 273 end 274 end 275 276 endmodule
源码2...
1 `timescale 1 ns / 1 ps 2 module lcd1602_cgram_driver( 3 sys_clk, 4 sys_rst_n, 5 lcd_en, 6 lcd_rw, 7 lcd_rs, 8 lcd_bus, 9 lcd_on, 10 lcd_blon 11 ); 12 input sys_clk; 13 input sys_rst_n; 14 output lcd_rs; 15 output lcd_rw; 16 output lcd_en; 17 output lcd_on; 18 output lcd_blon; 19 output [7:0] lcd_bus; 20 21 22 reg [7:0] sys_dat_i=0; 23 reg [7:0] sys_addr_i=0; 24 wire lcd_ack_o; 25 26 27 always @ (posedge sys_clk) begin 28 if(sys_rst_n == 1'b0) begin 29 sys_dat_i <= 0; 30 sys_addr_i <= 8'h80; 31 end 32 else if(lcd_ack_o == 1'b1) begin 33 if(sys_dat_i == 8'd7) begin 34 sys_dat_i <= 0; 35 sys_addr_i <= 8'h80; 36 end 37 else begin 38 sys_dat_i <= sys_dat_i + 1'd1; 39 sys_addr_i <= sys_addr_i + 1'd1; 40 end 41 end 42 else begin 43 sys_dat_i <= sys_dat_i; 44 sys_addr_i <= sys_addr_i; 45 end 46 end 47 48 49 50 lcd1602_cgram_controller hal( 51 .sys_clk( sys_clk ), 52 .sys_rst_n( sys_rst_n ), 53 .sys_dat_i( sys_dat_i ), 54 .sys_addr_i( sys_addr_i ), 55 .lcd_ack_o( lcd_ack_o ), 56 .lcd_en( lcd_en ), 57 .lcd_rw( lcd_rw ), 58 .lcd_rs( lcd_rs ), 59 .lcd_bus( lcd_bus ), 60 .lcd_on( lcd_on ), 61 .lcd_blon( lcd_blon ) 62 ); 63 64 endmodule
源码3...
`timescale 1 ns / 1 ps module lcd1602_cgram_driver_tsb(); reg sys_clk; reg sys_rst_n; initial begin sys_clk=1; sys_rst_n=0; #100 sys_rst_n=1; end always begin #10 sys_clk=~sys_clk; end wire lcd_rw; wire lcd_rs; wire lcd_en; wire [7:0] lcd_bus; wire lcd_on; wire lcd_blon; lcd1602_cgram_driver api( .sys_clk( sys_clk ), .sys_rst_n( sys_rst_n ), .lcd_en( lcd_en ), .lcd_rw( lcd_rw ), .lcd_rs( lcd_rs ), .lcd_bus( lcd_bus ), .lcd_on( lcd_on ), .lcd_blon( lcd_blon ) ); endmodule