FPGA驱动LCD1602(IIC) Verilog代码(三)------ LCD初始化

一、概述:

        前面已经完成了lcd写数据/命令,那么lcd的初始化就比较简单了,就是先发送命令复位设置lcd,然后发送数据过去交给lcd显示就好了。

        lcd的显示比较简单一点,只需要传输要显示字符的ascll码,lcd就会显示出该字符,而且支持自动的移位,即显示完一个字符后接着自动确定下一个字符的显示位置,不过需要指定方向好像,这个我没有研究(毕竟指令都是嫖来的)


二、Verilog代码

module lcd_init(
	input clk,						//时钟信号 1m
	input rst_n,					//复位信号
	input ena,						//模块使能信号
	input done_write,				//一个字节写完成
	output reg [7:0] data,		//需要写的数据
	output cmd_data,				//写数据还是写指令 0:指令 1:数据
	output reg ena_write			//使能写信号
);

parameter DELAY = 50;			//写完一个字节等待的时间 50us
reg [20:0] us_cnt;				//us计数器
reg us_cnt_clr;					//计数器清零信号

reg [7:0]init_cmd_data[16:0];	//初始化的命令和数据 //默认显示HelloWorld
reg [4:0]initcd_cnt;				//命令或数据计数器

initial begin
	init_cmd_data[0] = 8'h02;	//光标复位
	init_cmd_data[1] = 8'h28;	//四线操作模式
	init_cmd_data[2] = 8'h0C;	//开显示
	init_cmd_data[3] = 8'h01;	//清屏
	init_cmd_data[4] = 8'h80;	//设置显示初始位置
	init_cmd_data[5] = 8'h06;	//设置输入方式,增量
	
	//HelloWorld
	init_cmd_data[6] = 8'h48;init_cmd_data[7] = 8'h65;init_cmd_data[8] = 8'h6C;
	init_cmd_data[9] = 8'h6C;init_cmd_data[10] = 8'h6F;init_cmd_data[11] = 8'h57;
	init_cmd_data[12] = 8'h6F;init_cmd_data[13] = 8'h72;init_cmd_data[14] = 8'h6C;
	init_cmd_data[15] = 8'h64;
end

//状态说明:
//等待模块使能
//写一个字节
//等待写完成
//延时
//完成
parameter WaitEn=0,Write=1,WaitWrite=3,WaitDelay=4,Done=5;
reg[2:0] state,next_state;		//当前状态和下一个状态

//前6个为命令,后面都是数据,但是init_cnt每次都是提前加1的,所以需要等于6
assign cmd_data = (initcd_cnt<=3'd6) ? 1'b0 : 1'b1;

//1微秒计数器
always @ (posedge clk,negedge rst_n) begin
    if (!rst_n)
        us_cnt <= 21'd0;
    else if (us_cnt_clr)
        us_cnt <= 21'd0;
    else 
        us_cnt <= us_cnt + 1'b1;
end

//下一个状态确定
always @(*) begin
	if(!rst_n)
		next_state = WaitEn;//复位到初始状态
	else begin
		case(state)
			//等待模块使能
			WaitEn: next_state = ena ? Write : WaitEn;
			
			//写一个字节
			Write: next_state = WaitWrite;
			
			//等待写完成
			WaitWrite: next_state = done_write ? WaitDelay : WaitWrite;
			
			//延时
			//是否已经全部写完成,写完成进入下一个状态,否则等待延时完成继续写下一个字节
			WaitDelay: next_state = initcd_cnt==5'd16 ? Done : ((us_cnt==DELAY) ? Write : WaitDelay);
			
			//完成初始化
			Done:next_state = Done;
		endcase
	end
end

always @(posedge clk,negedge rst_n) begin
	if(!rst_n)begin
		us_cnt_clr = 1'b1;//计数器复位
		ena_write <= 1'b0;//不使能写
	end
	else begin
		case(state)
		
			//等待模块使能
			WaitEn:begin
				us_cnt_clr = 1'b1;
				ena_write <= 1'b0;
			end
			
			//写一个字节
			Write:begin
				us_cnt_clr = 1'b1;
				data <= init_cmd_data[initcd_cnt];
				ena_write <= 1'b1;//使能写模块
			end
			
			//等待写完成
			WaitWrite:begin
				ena_write <= 1'b0;
			end
			
			//延时
			WaitDelay:begin
				us_cnt_clr = 1'b0;//取消计数器复位,让计数器计数
			end
		endcase
	end
end

//状态流转
always @(posedge clk,negedge rst_n) begin
	if(!rst_n)
		state <= WaitEn;
	else
		state <= next_state;
end

//计数器计数
always @(posedge clk,negedge rst_n) begin
	if(!rst_n)begin
		initcd_cnt <= 4'd0;
	end
	else begin
		if(state ==  Write)//在写一个字节状态时计数器加1,然后立即进入下一个状态,所以这个值总会多1在使用时
			initcd_cnt <= initcd_cnt + 1'b1;
		else
			initcd_cnt <= initcd_cnt;
	end
end

endmodule

三、模块仿真代码(testbench)

`timescale 1ns/1ns //仿真单位为1ns,精度为1ns
module lcd_init_tb();
	
	reg clk;
	reg rst_n;
	wire done_write;
	wire [7:0] data;
	wire cmd_data;
	wire ena_write;
	wire sda;
	wire scl;
	
	wire sda_dir;
	
	reg sda_in;
	
	assign sda = sda_dir ? 1'bz : sda_in;
	
	
	lcd_init lcd_init_inst(
		.clk(clk),
		.rst_n(rst_n),
		.ena(1'b1),
		.done_write(done_write),
		.ena_write(ena_write),
		.data(data),
		.cmd_data(cmd_data)
	);
	
	lcd_write_cmd_data lcd_write_cmd_data_inst(
		.clk(clk),
		.rst_n(rst_n),
		.ena(ena_write),
		.data(data),
		.cmd_data(cmd_data),
		.sda(sda),
		.scl(scl),
		.sda_dir(sda_dir),
		.done(done_write)
	);
	
	initial begin
		#0 	clk = 0;
				rst_n = 0;
				sda_in = 0;
			
		#20	rst_n = 1;
		
	end
	
	always #5 clk = ~clk;
	
endmodule

四、仿真结果

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值