LCD12864带字库,型号:CM12864-12.其相关数据手册可以在百度中搜索“ST7920 系列中文图形液晶模块使用说明书”,里面有详细的介绍。这里就不在多描述。
其原理简图:(我们只需关心接口部分)
接口定义:这里注意V0,我一开始就栽倒这,网上搜到的资料中,这PIN可以悬空或接个滑动电阻,程序检查好多遍,没有发现问题,就是不显示,接到3.3V上也不行,后来把V0直接接到5V上,就可以正常显示。在这提醒大家数据手册仅供参考,具体还是以自己的实物为主。避免走没必要的弯路。
管脚号 |
管脚名称 |
电平 |
管脚功能描述 |
1 |
VSS |
0V |
电源地 |
2 |
VCC |
5V |
电源正 |
3 |
V0 |
- |
对比度(亮度)调整.(直接接到5V上最靠谱) |
4 |
RS(CS) |
H/L |
RS=“H”,表示DB7——DB0为显示数据 RS=“L”,表示DB7——DB0为显示指令数据 |
5 |
R/W(SID) |
H/L |
R/W=“H”,E=“H”,数据被读到DB7——DB0 R/W=“L”,E=“H→L”, DB7——DB0的数据被写到IR或DR |
6 |
E(SCLK) |
H/L |
使能信号 |
7 |
DB0 |
H/L |
三态数据线 |
8 |
DB1 |
H/L |
三态数据线 |
9 |
DB2 |
H/L |
三态数据线 |
10 |
DB3 |
H/L |
三态数据线 |
11 |
DB4 |
H/L |
三态数据线 |
12 |
DB5 |
H/L |
三态数据线 |
13 |
DB6 |
H/L |
三态数据线 |
14 |
DB7 |
H/L |
三态数据线 |
15 |
PSB |
H/L |
H:8位或4位并口方式,L:串口方式 |
16 |
NC |
- |
空脚 |
17 |
/RESET |
H/L |
复位端,低电平有效(悬空或接到5V都可以) |
18 |
VOUT |
- |
LCD驱动电压输出端(悬空) |
19 |
A |
VDD |
背光源正端(+5V) |
20 |
K |
VSS |
背光源负端(0V) |
ST7920数据手册中,提到每次在写命令之前都要判断LCD是否处于空闲状态,是为0,否则为1,本次试验全过程只写不读,为了避开LCD忙的状态,可以采取隔断时间写一次命令或数据。在指令表中,可以看到每个命令执行的时间,这里注意,除清除显示和地址归位,网上有不同的说法,有的说是1.6ms,有的4.6ms外,其他命令执行时间都是72us,不管怎么样,我们还是取最大值更为靠谱,4.6ms取个整数,好听点的6ms吧。当然可以取比这个更大(LCD在显示数据时,是一个接一个的显示出来,就可以察觉到,取的越大,显示速度就越慢),看自己的决定了。利用FPGA分频,产生一个周期6ms的时钟,给LCD的E管脚,进行控制写数据或命令。在8为并口写操作时序图中,DB0~DB7是在E为高时,写入数据。
知道了何时给LCD写数据或命令,还得知道如何把自己想要显示的东西显示在LCD屏幕上,这点也不难:
第一得知道中文字行的编码,可以查国标GB2312,来调用CGROM字库,比如"文:CEC4、少:C9D9、清:C7E5“。或可以下载“汉字十六进制转换工具”软件直接生成。
第二得知道显示文字的地址该如何设置,就是一个文字我可以摆在第一行的开头或结尾或其他行。如下图示。
第三若自带的库中没有你想要的东西时,可以自己定义,比如代码中的星星月亮组合图标,库中没有,那么我们可以自己定义(组合图标的编码可以用字模软件进行提取)。自定义字符具体操作,先设定CGRAM存储地址,其次把该组合图标的编码数据放置到该地址中,在设置该图标在LCD屏幕显示的位置,最后连续写两次数据(注意写的是数据不是命令,我也被这东东栽倒一次),先写高8it,后写低8bit,就可以了。此时知道写这数据到底是啥数据。那么就得理解0x0000,0x0002,0x0004,0x0006这四种编码.至于这四种编码有什么区别,我也不是很明白,在程序中,0x0000和0x0006没发现有区别,显示正常;0x0002,在星星的左上角有个小点;0x0004显示乱码。
第四半宽字型,数据手册中写的是”半宽字型ROM(HCGROM),总共提供126 个西文字型(16×8 点阵)“,应该就是英文字符。程序中的"LCD12864"。
在写代码之前理清思路,程序的流程该如何跑,写起代码来也比较顺手。如下图。前面设置好频率后,每步中的延时就不用在考虑了。
代码:(使用并口,只有写)
LCD12864.v
1 module LCD12864( 2 //input 3 sys_clk, 4 rst_n, 5 6 //output 7 lcd_rs, 8 lcd_rw, 9 lcd_en, 10 lcd_data, 11 lcd_psb 12 ); 13 input sys_clk;// 50MHZ 14 input rst_n; 15 16 output lcd_rs;//H:data L:command 17 output lcd_rw;//H:read module L:write module 18 output lcd_en;//H active 19 output [7:0] lcd_data; 20 output lcd_psb;//H:parallel module L:SPI module 21 22 /***************************************************/ 23 parameter T3MS = 18'd149_999; 24 parameter IDLE = 4'd0, 25 INIT_FUN_SET1 = 4'd1, 26 INIT_FUN_SET2 = 4'd2, 27 INIT_DISPLAY = 4'd3, 28 INIT_CLEAR = 4'd4, 29 INIT_DOT_SET = 4'd5, 30 SET_DDRAM = 4'd6, 31 WRITE_DATA1 = 4'd7, 32 INIT_FUN_SET3 = 4'd8, 33 SET_CGRAM = 4'd9, 34 WRITE_DATA2 = 4'd10, 35 SET_DDRAM2 = 4'd11, 36 SET_CUSTOM_L = 4'd12, 37 SET_CUSTOM_H = 4'd13, 38 STOP = 4'd14; 39 /***************************************************/ 40 //产生周期为6MS的lcd_clk给LCD 41 reg [17:0] cnt; 42 reg lcd_clk; 43 always @(posedge sys_clk or negedge rst_n) 44 if(!rst_n) begin 45 cnt <= 18'd0; 46 lcd_clk <= 1'b0; 47 end 48 else if(cnt == T3MS)begin 49 cnt <= 18'd0; 50 lcd_clk <= ~lcd_clk; 51 end 52 else 53 cnt <= cnt + 1'b1; 54 /***************************************************/ 55 reg lcd_rs; 56 always @(posedge lcd_clk or negedge rst_n) 57 if(!rst_n) 58 lcd_rs <= 1'b0; 59 else if((state == WRITE_DATA1) || (state == WRITE_DATA2)|| (state == SET_CUSTOM_H) || (state == SET_CUSTOM_L)) 60 lcd_rs <= 1'b1; //写数据模式 61 else 62 lcd_rs <= 1'b0; //写命令模式 63 /***************************************************/ 64 reg [3:0] state; 65 reg [7:0] lcd_data; 66 reg [6:0] num; 67 reg en; 68 always @(posedge lcd_clk or negedge rst_n) 69 if(!rst_n) begin 70 state <= IDLE; 71 lcd_data <= 8'hzz; 72 en <= 1'b1; 73 num <= 6'd0; 74 end 75 else 76 case(state) 77 IDLE: 78 begin 79 state <= INIT_FUN_SET1; 80 lcd_data <= 8'hzz; 81 en <= 1'b1; 82 end 83 84 INIT_FUN_SET1: 85 begin 86 lcd_data <= 8'h30; //功能设定 87 state <= INIT_FUN_SET2; 88 end 89 90 INIT_FUN_SET2: 91 begin 92 lcd_data <= 8'h30; //功能设定 93 state <= INIT_DISPLAY; 94 end 95 96 INIT_DISPLAY: 97 begin 98 lcd_data <= 8'h0c; //显示设定 99 state <= INIT_CLEAR; 100 end 101 102 INIT_CLEAR: 103 begin 104 lcd_data <= 8'h01; //清屏 105 state <= INIT_DOT_SET; 106 end 107 108 INIT_DOT_SET: 109 begin 110 lcd_data <= 8'h06; //进入点设定 111 state <= SET_DDRAM; 112 end 113 114 SET_DDRAM: 115 begin 116 if(num == 7'd0) 117 lcd_data <= 8'h81;//1 line 118 else if(num == 7'd12) 119 lcd_data <= 8'h92;//2 line 120 else if(num == 7'd18) 121 lcd_data <= 8'h8a;//3 line 122 else if(num == 7'd26) 123 lcd_data <= 8'h99;//4 line 124 125 state <= WRITE_DATA1; 126 end 127 128 WRITE_DATA1: 129 begin 130 if(num <= 7'd11) begin 131 num <= num + 1'b1; 132 lcd_data <= dis_data; 133 if(num == 7'd11) 134 state <= SET_DDRAM; 135 else 136 state <= WRITE_DATA1; 137 end 138 else if( num > 7'd11 && num <= 7'd17) begin 139 num <= num + 1'b1; 140 lcd_data <= dis_data; 141 if(num == 7'd17) 142 state <= SET_DDRAM; 143 else 144 state <= WRITE_DATA1; 145 end 146 else if(num > 7'd17 && num <= 7'd25) begin 147 num <= num + 1'b1; 148 lcd_data <= dis_data; 149 if(num == 7'd25) 150 state <= SET_DDRAM; 151 else 152 state <= WRITE_DATA1; 153 end 154 else if(num > 7'd25 && num <= 7'd33) begin 155 num <= num + 1'b1; 156 lcd_data <= dis_data; 157 if(num == 7'd33) 158 state <= INIT_FUN_SET3; 159 else 160 state <= WRITE_DATA1; 161 end 162 end 163 164 INIT_FUN_SET3: 165 begin 166 lcd_data <= 8'h30;//功能设定 167 state <= SET_CGRAM; 168 end 169 170 SET_CGRAM: 171 begin 172 lcd_data <= 8'h40;//设定CGRAM字符的位置 173 state <= WRITE_DATA2; 174 end 175 176 WRITE_DATA2: 177 begin 178 if(num >= 7'd34 && num <= 7'd65) begin 179 num <= num + 1'b1; 180 lcd_data <= dis_data; 181 state <= WRITE_DATA2; 182 end 183 else begin 184 num <= 7'd0; 185 state <= SET_DDRAM2; 186 end 187 end 188 189 SET_DDRAM2: 190 begin 191 lcd_data <= 8'h9e; //4line 192 state <= SET_CUSTOM_H;//设置自定义显示字符编码 193 end 194 195 SET_CUSTOM_H: 196 begin 197 lcd_data <= 8'h00;//高8bit 198 state <= SET_CUSTOM_L; 199 end 200 201 SET_CUSTOM_L: 202 begin 203 lcd_data <= 8'h06;//低8bit 00:正常 02:星星左上角多了一小点 04:显示的是乱码 06:显示也正常 204 state <= STOP; 205 end 206 207 STOP: 208 begin 209 en <= 1'b0;//显示完了,lcd_e就一直拉为低 210 state <= STOP; 211 end 212 213 default: state <= IDLE; 214 endcase 215 /***************************************************/ 216 reg [7:0] dis_data; 217 always @(posedge sys_clk or negedge rst_n) 218 if(!rst_n) 219 dis_data <= 8'hzz; 220 else 221 case(num) 222 //1 Line 81位置显示 欢迎访问博客 223 7'd0 : dis_data <= 8'hbb; 224 7'd1 : dis_data <= 8'hb6; 225 7'd2 : dis_data <= 8'hd3; 226 7'd3 : dis_data <= 8'had; 227 7'd4 : dis_data <= 8'hb7; 228 7'd5 : dis_data <= 8'hc3; 229 7'd6 : dis_data <= 8'hce; 230 7'd7 : dis_data <= 8'hca; 231 7'd8 : dis_data <= 8'hb2; 232 7'd9 : dis_data <= 8'ha9; 233 7'd10 : dis_data <= 8'hbf; 234 7'd11 : dis_data <= 8'hcd; 235 //2Line 92位置显示 文少清 236 7'd12 : dis_data <= 8'hce; 237 7'd13 : dis_data <= 8'hc4; 238 7'd14 : dis_data <= 8'hc9; 239 7'd15 : dis_data <= 8'hd9; 240 7'd16 : dis_data <= 8'hC7; 241 7'd17 : dis_data <= 8'he5; 242 //3Line 8a位置显示 LCD12864 243 7'd18 : dis_data <= "L"; 244 7'd19 : dis_data <= "C"; 245 7'd20 : dis_data <= "D"; 246 7'd21 : dis_data <= "1"; 247 7'd22 : dis_data <= "2"; 248 7'd23 : dis_data <= "8"; 249 7'd24 : dis_data <= "6"; 250 7'd25 : dis_data <= "4"; 251 //4Line 99位置显示 谢谢! 252 7'd26 : dis_data <= 8'hd0; 253 7'd27 : dis_data <= 8'hbb; 254 7'd28 : dis_data <= 8'hd0; 255 7'd29 : dis_data <= 8'hbb; 256 7'd30 : dis_data <= 8'ha3; 257 7'd31 : dis_data <= 8'ha1; 258 7'd32 : dis_data <= " "; //这两次空格可以不写的 259 7'd33 : dis_data <= " "; 260 //4line 9e位置显示星星月亮 261 7'd34 : dis_data <= 8'h08; 262 7'd35 : dis_data <= 8'h20; 263 7'd36 : dis_data <= 8'h1c; 264 7'd37 : dis_data <= 8'h10; 265 7'd38 : dis_data <= 8'h1c; 266 7'd39 : dis_data <= 8'h1c; 267 7'd40 : dis_data <= 8'hff; 268 7'd41 : dis_data <= 8'h9e; 269 7'd42 : dis_data <= 8'h7f; 270 7'd43 : dis_data <= 8'h1e; 271 7'd43 : dis_data <= 8'h1c; 272 7'd45 : dis_data <= 8'h1f; 273 7'd46 : dis_data <= 8'h3e; 274 7'd47 : dis_data <= 8'h1f; 275 7'd48 : dis_data <= 8'h3e; 276 7'd49 : dis_data <= 8'h1f; 277 7'd50 : dis_data <= 8'h77; 278 7'd51 : dis_data <= 8'h1f; 279 7'd52 : dis_data <= 8'h41; 280 7'd53 : dis_data <= 8'h3f; 281 7'd54 : dis_data <= 8'h00; 282 7'd55 : dis_data <= 8'h7e; 283 7'd56 : dis_data <= 8'h00; 284 7'd57 : dis_data <= 8'hfe; 285 7'd58 : dis_data <= 8'h83; 286 7'd59 : dis_data <= 8'hfc; 287 7'd60 : dis_data <= 8'h7f; 288 7'd61 : dis_data <= 8'hf8; 289 7'd62 : dis_data <= 8'h3f; 290 7'd63 : dis_data <= 8'hf0; 291 7'd64 : dis_data <= 8'h0f; 292 7'd65 : dis_data <= 8'hc0; 293 default: dis_data <= 8'h00; 294 endcase 295 /***************************************************/ 296 assign lcd_rw = 1'b0;//只有写模式 297 assign lcd_psb = 1'b1;//并口模式 298 assign lcd_en = en ? lcd_clk : 1'b0; 299 /***************************************************/ 300 endmodule
显示效果:
图片显示待续。