欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

FPGA--1602

程序员文章站 2022-04-30 11:33:04
...

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

  1. 时序:

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

FPGA--1602

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

可以看到共有四种线,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

 

相关标签: FPGA

推荐阅读