说明书摘要
指令集
目前顶层开发到一半,只开发了写功能,读功能还未开发。另:目前指令逻辑直接在顶层中开发,代码写的比较草,状态机代码没有优化,因此顶层文件代码量超过了300行。。。。。后面可以将指令逻辑做个封装
顶层Verilog代码
//Name:Lcd_1602
//Author:Yang_Cheng_Yu
//Date:2020/4/18
//==================defines=====================
`define SIM
module lcd1602(
//================System Signal================
input clk,
input rst_n,
//================Interface====================
output RS,
output RW,
output E,
inout[7:0] DB,
input clr_req,
input cur_back_req,
input set_input_req,
input disp_onoff_req,
input shift_req,
input set_function_req,
input set_char_gen_addr_req,
input set_data_save_addr_req,
input set_rd_busy_req,
input wr_ddram_req,
input rd_ddram_req,
input[7:0] data_wr
);
//================parameters===================
`ifndef SIM
`else
`endif
//addr
parameter ADDR_CHAR_GEN_REG = 6'b01_0011;
parameter ADDR_DISP_DATA_REG = 7'b011_0011;
parameter ADDR_CNT = 7'b010_0101;
//state machine
localparam S_IDLE = 12'b000_0000_00001;
localparam S_CLR = 12'b000_0000_00010;
localparam S_CURSOR_BACK = 12'b000_0000_00100;
localparam S_SET_INPUT = 12'b000_0000_01000;
localparam S_DISPLAY_ONOFF = 12'b000_0000_10000;
localparam S_SHIFT = 12'b000_0001_00000;
localparam S_SET_FUNCTION = 12'b000_0010_00000;
localparam S_SET_CHAR_GEN_ADDR = 12'b000_0100_00000;
localparam S_SET_DATA_SAVE_ADDR = 12'b000_1000_00000;
localparam S_RD_BUSY = 12'b001_0000_00000;
localparam S_WR_DDRAM = 12'b010_0000_00000;
localparam S_RD_DDRAM = 12'b100_0000_00000;
//command
localparam CMD_CLR = 10'b00_0000_0001;
localparam CMD_CURSOR_BACK = 10'b00_0000_0010;
localparam CMD_SET_INPUT = 10'b00_0000_0110;//默认光标右移
localparam CMD_DISPLAY_ONOFF = 10'b00_0000_1110;//默认开启整体显示,有光标,光标不闪烁
localparam CMD_SHIFT = 10'b00_0001_1100;//默认移动显示文字,向右移动
localparam CMD_SET_FUNCTION = 10'b00_0010_1100;//默认8位总线,双行显示,5*10点阵字符
localparam CMD_SET_CHAR_GEN_ADDR = {4'b0001,ADDR_CHAR_GEN_REG};//前6位是字符发生贮存器地址
localparam CMD_SET_DATA_SAVE_ADDR = {3'b001,ADDR_DISP_DATA_REG};//前7位是数据贮存器地址
localparam CMD_RD_BUSY = {3'b010,ADDR_CNT};//默认不忙
//================System regs==================
reg[9:0] state;
reg[1:0] delay;
wire rs;
wire rw;
reg wr_req;
wire wr_req_wire;
assign wr_req_wire = wr_req;
wire flag_wr_end;
reg[9:0] cmd;
wire[7:0] out_db;
assign out_db = (state==S_RD_BUSY||state==S_RD_DDRAM)?8'hz:cmd[7:0];
assign DB=(state==S_RD_DDRAM||state==S_RD_BUSY)?8'hz:out_db;
// assign {rs,rw,out_db} = (state!=S_RD_DDRAM)?cmd:10'bz;
assign rs = (state==S_WR_DDRAM||state==S_RD_DDRAM)?1'b1:1'b0;
assign rw = (state==S_RD_BUSY||state==S_RD_DDRAM)?1'b1:1'b0;
wire[9:0] CMD_WR_DDRAM;
wire[9:0] CMD_RD_DDRAM;
assign CMD_WR_DDRAM = {2'b10,data_wr};
assign CMD_RD_DDRAM = {2'b11,8'hz};
//================Main Codes===================
lcd_write lcd_write_inst(
//================System Signal================
.clk (clk),
.rst_n (rst_n),
//================Interface====================
.rs_in (rs),
.RS (RS),//指令数据选择
.RW (RW),
.E (E),
.DB (DB),
.wr_req (wr_req_wire),
.data (out_db),
.flag_wr_end (flag_wr_end)
);
//state machine
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
state <= S_IDLE;
else case(state)
S_IDLE:begin
if(clr_req==1'b1)
state <= S_CLR;
else
state <= S_IDLE;
end
S_CLR:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_CLR;
end
S_CURSOR_BACK:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_CURSOR_BACK;
end
S_SET_INPUT:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_SET_INPUT;
end
S_DISPLAY_ONOFF:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_DISPLAY_ONOFF;
end
S_SHIFT:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_SHIFT;
end
S_SET_FUNCTION:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_SET_FUNCTION;
end
S_SET_CHAR_GEN_ADDR:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_SET_CHAR_GEN_ADDR;
end
S_SET_DATA_SAVE_ADDR:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_SET_DATA_SAVE_ADDR;
end
// S_RD_BUSY:begin
// if(flag_wr_end==1'b1)
// state <= S_IDLE;
// else
// state <= S_RD_BUSY;
// end
S_WR_DDRAM:begin
if(flag_wr_end==1'b1)
state <= S_IDLE;
else
state <= S_WR_DDRAM;
end
// S_RD_DDRAM:begin
// end
default:state <= S_IDLE;
endcase
end
//cmd
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
state <= S_IDLE;
else case(state)
S_IDLE:begin
cmd <= 10'b00_0000_0000;
end
S_CLR:begin
cmd <= CMD_CLR;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_CURSOR_BACK:begin
cmd <= CMD_CURSOR_BACK;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_SET_INPUT:begin
cmd <= CMD_SET_INPUT;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_DISPLAY_ONOFF:begin
cmd <= CMD_DISPLAY_ONOFF;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_SHIFT:begin
cmd <= CMD_SHIFT;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_SET_FUNCTION:begin
cmd <= CMD_SET_FUNCTION;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_SET_CHAR_GEN_ADDR:begin
cmd <= CMD_SET_CHAR_GEN_ADDR;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_SET_DATA_SAVE_ADDR:begin
cmd <= CMD_SET_DATA_SAVE_ADDR;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_RD_BUSY:begin
cmd <= CMD_RD_BUSY;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
S_WR_DDRAM:begin
cmd <= CMD_WR_DDRAM;
if(delay==2'd2)
delay <= 'd0;
else
delay <= delay + 1'b1;
if(delay==2'd1)
wr_req <= 1'b1;
else if(delay==2'd2)
wr_req <= 1'b0;
end
// S_RD_DDRAM:begin
// end
default:begin
cmd <= 10'b00_0000_0000;
delay <= 'd0;
end
endcase
end
endmodule