FPGA--1602

介绍顺序:时序、设计思路、代码实现;

  1. 时序:

市面上大部分1602芯片为HD44780,1602时序也就是HD44780的时序,直接看图:

这是写入的时序图,读取的时序图用不上,不分析,与写入类似。

可以看到共有四种线,RS指令数据选择,0代表指令,1代表数据,R/W读取控制,0代表写入,1代表读取,E代表使能,下降沿写入,高电平读取,DB[7:0]为并行8位数据线。

Tas:RS,RW变化开始,到E变化开始的时间,最少140ns;

Pweh:E变化开始,到E复位,最少450ns;

Tdsw:数据变化开始,到E下降沿,最少195ns,实际操作中,数据和E可以同时变化,这样可以省略tdsw参数;

Th/tah:E复位开始,到RS,RW复位(数据可以不复位),最少10ns;

Tcycle:一次操作时间,最少1000ns;

  1. 设计思路:

按照上述时序图,可以实现指令或数据的写入,具体写入指令或数据的顺序如下:

HD44780共有11种指令,建议看看芯片手册;

下面只说平常用到的指令,按照执行顺序说明:

  1. 功能设置:0x38,延时40us
  2. 显示开关控制:0x0c,延时40us;
  3. 输入方式设置:0x06,延时40us;
  4. 清屏:0x01,延时1.64ms
  5. DDRAM地址设置:0x80或0xc0;
  6. 写数据:待显示数据;

有几点需要注意:

  1. 功能设置指令最少执行两次,否则可能导致第二行不能显示;
  2. 延时时间一定要保证,特别是清屏指令,否则不显示;
  1. 代码实现:

写入以及显示各用一个状态机实现:

  1. 初始化:
module lcd1602(clk,rst,rs,rw,e,db);

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 [16: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_1640 = 100000;//1.64ms-->2ms
parameter delay_40 = 5000;//40us-->100us
  1. 写入:
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
  1. 显示:
always @ (posedge clk or negedge rst) begin//显示
	if(!rst) begin
		lcd_state <= 6'd0;
		lcd_db_r <= 8'd0;
		lcd_delay <= 17'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'h38;//8为数据接口,两行显示,5*7点阵字符
					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//功能设置--延时(40us)
					if(lcd_delay == delay_40) 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 <= 17'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//显示开关控制--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'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//输入方式设置--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd6 : begin//清屏(1)
					lcd_db_r <= 8'h01;//固定,注意延时1.64ms
					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//清屏--延时(1.64ms)
					if(lcd_delay == delay_1640) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'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地址设置--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd10 : 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'd11 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd12 : 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'd13 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd14 : 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'd15 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd16 : 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'd17 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd18 : begin//写数据(10)
					lcd_db_r <= "/";//待显示数据
					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//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end	
			6'd20 : 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'd21 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd22 : 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'd23 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd24 : begin//写数据(10)
					lcd_db_r <= "/";//待显示数据
					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//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd26 : 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'd27 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd28 : 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'd29 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd30 : begin//DDRAM地址设置(8)
					lcd_db_r <= 8'hc0;//地址:第二行第一个
					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'd31 : begin//DDRAM地址设置--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end					
			6'd32 : 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'd33 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd34 : begin//写数据(10)
					lcd_db_r <= "5";//待显示数据
					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'd35 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd36 : begin//写数据(10)
					lcd_db_r <= ":";//待显示数据
					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_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd38 : 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'd39 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end
			6'd40 : 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'd41 : begin//写数据--延时(40us)
					if(lcd_delay == delay_40) begin
						lcd_state <= lcd_state + 1; 
						lcd_delay <= 17'd0;
					end
					else lcd_delay <= lcd_delay + 1;
				end			
		endcase
	end
end

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值