介绍顺序:时序、设计思路、代码实现;
- 时序:
写入时序,12864与1602相同,不再重复,请看1602篇。
- 设计思路:
按照上述时序图,可以实现指令或数据的写入,具体写入指令或数据的顺序如下:
12864基本指令集与1602大致相同,除了这些12864还有7个扩展指令集,平时用不到,不介绍。11种基本指令的操作方法大致同1602:
下面只说平常用到的指令,按照执行顺序说明:
- 功能设置:0x30,延时72us
- 显示开关控制:0x0c,延时72us;
- 输入方式设置:0x06,延时72us;
- 清屏:0x01,延时4.6ms;
- DDRAM地址设置:0x80/0x90/0x88/0x98;
- 写数据:待显示数据;
有几点需要注意:
- 功能设置指令最少执行两次,否则可能导致第二行不能显示;
- 延时时间一定要保证,特别是清屏指令,否则不显示;
- 代码实现:
写入以及显示各用一个状态机实现:
- 初始化:
input clk;//系统时钟
input rst;//系统复位
output reg rs;//液晶--rs
output reg rw;//液晶--rw
output reg e;//液晶--e
output reg [7:0] db;//液晶--db
reg write_en;//写入--启动,1启动,0停止
reg write_rs;//写入--指令or数据,1数据,0指令
reg [3:0] write_state;//写入--状态机
reg [5:0] write_cnt;//写入--延时控制
reg [5:0] lcd_state;//lcd状态机
reg [7:0] lcd_db_r;//lcd待显示数据
reg [19:0] lcd_delay;//lcd操作间延时
reg [3:0] lcd_init_cnt;//lcd初始化次数
parameter tas = 10;//140ns-->200ns
parameter pweh = 25;//450ns-->500ns
parameter th = 1;//10ns-->20ns
parameter tcycle = 50;//1000ns-->1000ns
parameter delay_4600 = 250000;//4.6ms-->5ms
parameter delay_72 = 5000;//72us-->100us
- 写入:
always @ (posedge clk or negedge rst) begin//指令、数据写入
if(!rst) begin
write_state <= 4'd0;
write_cnt <= 8'd0;
rs <= 1'b0;
rw <= 1'b0;
e <= 1'b0;
db <= 8'd0;
end
else begin
case(write_state)
4'd0 : if(write_en == 1'b1) write_state <= 4'd1;//等待
4'd1 : begin//rs,rw置位,延时tas
rs <= write_rs;
rw <= 1'b0;
if(write_cnt == (tas - 1)) begin
write_state <= 4'd2;
write_cnt <= 8'd0;
end
else write_cnt <= write_cnt + 1;
end
4'd2 : begin//e,data置位,延时pweh
e <= 1'b1;
db <= lcd_db_r;
if(write_cnt == (pweh - 1)) begin
write_state <= 4'd3;
write_cnt <= 8'd0;
end
else write_cnt <= write_cnt + 1'b1;
end
4'd3 : begin//e复位,延时th
e <= 1'b0;
if(write_cnt == (th - 1)) begin
write_state <= 4'd4;
write_cnt <= 8'd0;
end
else write_cnt <= write_cnt + 1'b1;
end
4'd4 : begin//rs,rw复位,延时tcycle,写入完毕
rs <= 1'b0;
rw <= 1'b0;
if(write_cnt == (tcycle - 1)) begin
write_state <= 4'd0;
write_cnt <= 8'd0;
end
else write_cnt <= write_cnt + 1'b1;
end
default : ;
endcase
end
end
- 显示:
always @ (posedge clk or negedge rst) begin//显示
if(!rst) begin
lcd_state <= 6'd0;
lcd_db_r <= 8'd0;
lcd_delay <= 20'd0;
lcd_init_cnt <= 4'd0;
write_en <= 1'b0;
write_rs <= 1'b0;
end
else begin
case(lcd_state)
6'd0 : begin//功能设置(6)
lcd_db_r <= 8'h30;//基本指令集动作
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd1 : begin//功能设置--延时(72us)
if(lcd_delay == delay_72) begin
if(lcd_init_cnt == 4'd1) begin
lcd_state <= lcd_state + 1;
lcd_init_cnt <= 4'd0;
end
else begin
lcd_state <= 6'd0;
lcd_init_cnt <= lcd_init_cnt + 1;
end
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd2 : begin//显示开关控制(4)
lcd_db_r <= 8'h0c;//开显示,关光标,关闪烁
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd3 : begin//显示开关控制--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd4 : begin//输入方式设置(3)
lcd_db_r <= 8'h06;//AC++,画面不动
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd5 : begin//输入方式设置--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd6 : begin//清屏(1)
lcd_db_r <= 8'h01;//固定,注意延时4.6ms
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd7 : begin//清屏--延时(4.6ms)
if(lcd_delay == delay_4600) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd8 : begin//DDRAM地址设置(8)
lcd_db_r <= 8'h80;//地址:第一行第一个
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd9 : begin//DDRAM地址设置--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd10 : begin//写数据(10)
lcd_db_r <= "A";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd11 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd12 : begin//写数据(10)
lcd_db_r <= "D";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd13 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd14 : begin//写数据(10)
lcd_db_r <= "8";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd15 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd16 : begin//写数据(10)
lcd_db_r <= "3";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd17 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd18 : begin//写数据(10)
lcd_db_r <= "9";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd19 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd20 : begin//写数据(10)
lcd_db_r <= "7";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd21 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd22 : begin//DDRAM地址设置(8)
lcd_db_r <= 8'h90;//地址:第二行第一个
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd23 : begin//DDRAM地址设置--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd24 : begin//写数据(10)
lcd_db_r <= "A";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd25 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd26 : begin//写数据(10)
lcd_db_r <= "D";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd27 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd28 : begin//写数据(10)
lcd_db_r <= "6";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd29 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd30 : begin//写数据(10)
lcd_db_r <= "2";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd31 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd32 : begin//写数据(10)
lcd_db_r <= "3";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd33 : begin//写数据--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd34 : begin//DDRAM地址设置(8)
lcd_db_r <= 8'h88;//地址:第三行第一个
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd35 : begin//DDRAM地址设置--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd36 : begin//写数据(10)
lcd_db_r <= "A";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd37 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd38 : begin//写数据(10)
lcd_db_r <= "M";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd39 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd40 : begin//写数据(10)
lcd_db_r <= "C";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd41 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd42 : begin//写数据(10)
lcd_db_r <= "1";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd43 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd44 : begin//写数据(10)
lcd_db_r <= "2";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd45 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd46 : begin//写数据(10)
lcd_db_r <= "0";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd47 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd48 : begin//写数据(10)
lcd_db_r <= "0";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd49 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd50 : begin//DDRAM地址设置(8)
lcd_db_r <= 8'h98;//地址:第三行第一个
write_rs <= 1'b0;//指令
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd51 : begin//DDRAM地址设置--延时(72us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd52 : begin//写数据(10)
lcd_db_r <= "O";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd53 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd54 : begin//写数据(10)
lcd_db_r <= "P";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd55 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd56 : begin//写数据(10)
lcd_db_r <= "0";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd57 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
6'd58 : begin//写数据(10)
lcd_db_r <= "7";//待显示数据
write_rs <= 1'b1;//数据
write_en <= 1'b1;
if(write_cnt == (tcycle - 1)) begin
lcd_state <= lcd_state + 1;
write_en <= 1'b0;
end
end
6'd59 : begin//写数据--延时(40us)
if(lcd_delay == delay_72) begin
lcd_state <= lcd_state + 1;
lcd_delay <= 20'd0;
end
else lcd_delay <= lcd_delay + 1;
end
endcase
end
end