Altera FPGA LCD1602液晶螢幕封裝

溪江月發表於2015-04-25
首先我們需要了解LCD1602液晶顯示器的驅動原理以及LCD1602指令。
以下借用百度文庫的LCD1602指令文件

瞭解完LCD1602的驅動和指令,我們就可以嘗試用verilog硬體描述語言編寫LCD1602液晶屏的封裝。

下面是用verilog硬體描述語言編寫的LCD1602液晶螢幕的封裝。本人能力有限,只能寫到這樣了,高手勿噴!

//lcd顯示模組
module lcd_IP_model(clk,rst,data_buf,lcd_e,lcd_rw,lcd_rs,lcd_data);
 input clk;
 input rst;
 input [255:0]data_buf;     //資料介面
 output lcd_e;
 output lcd_rw;
 output lcd_rs;
 output [7:0]lcd_data;
 //--------------------------------------------------------------- 
 //分頻得到clk_800Hz
 reg [16:0]cnt;
 reg clk_lcd;
 always @(posedge clk or negedge rst)
  if(!rst)
   cnt <= 1'b0;
  else
   begin
    cnt <= cnt + 1'b1;
    if( cnt == 17'd31249)
    begin
     cnt <= 1'b0;
     clk_lcd <= ~clk_lcd;
    end
   end
 //--------------------------------------------------------------- 
 reg [2:0]func;    //狀態機func
 reg [3:0]com_cnt;   //com_buf_bit的計數模組
 reg [5:0]data_cnt;  //data_buf_bit計數模組
 reg [87:0]com_buf_bit; //11條lcd螢幕指令 每條8bit,11條就需要 11x8=88bit
 reg [255:0]data_buf_bit;//lcd 每行16個字元,一共兩行,總共32個字元,一個字元需要8bit顯示,所以32x8=256bit 參考LCD1602液晶顯示控制部分
 parameter set0=4'd1,set1=4'd2,dat1=4'd3,set2=4'd4,dat2=4'd5,done=4'd6;
 parameter com_buf={8'h02,8'h06,8'h0C,8'h38,8'h80,8'h00,8'h00,8'h00,8'h00,8'h00,8'h00};//LCD1602指令,對螢幕初始化
 //--------------------------------------------------------------- 
 reg [7:0]lcd_data;
 reg lcd_rs;
 reg en;
 reg [255:0]data; //因為封裝成ip核所以採用一個暫存器把data_buf值存起來,
       //後面做對比用,如果data值變化,顯示內容也就變化
 always @(posedge clk_lcd or negedge rst)
 begin
  if(!rst)
   com_buf_bit <= 8'h01;  //清屏指令
  else
  begin
   en <= 0;  //寫指令
   case(func)
    //液晶屏初始化
    set0: begin
       com_buf_bit <= com_buf;
       data_buf_bit <= data_buf;
       data <= data_buf;   //data_buf存到暫存器data裡面
       com_cnt <= 1'b0;
       data_cnt <= 1'b0;
       func <= set1;
      end
 //---------------------------------------------------------------    
    set1: begin
       lcd_rs <= 0; //寫指令
       lcd_data <= com_buf_bit[87:80];
       com_buf_bit <= (com_buf_bit<<8);
       com_cnt <= com_cnt + 1'b1;
       if(com_cnt <= 10) //共11次,11條lcd指令
        func <= set1;
       else
       begin
        func <= dat1;
        com_cnt <= 1'b0;
       end
      end
 //---------------------------------------------------------------    
    dat1: begin
       lcd_rs <= 1; //寫資料
       lcd_data <= data_buf_bit[255:248];
       data_buf_bit <= (data_buf_bit<<8);
       data_cnt <= data_cnt + 1'b1;
       if(data_cnt < 15) //共16次 液晶屏第一行顯示的內容
        func <= dat1;
       else
        func <= set2;
      end
 //---------------------------------------------------------------    
    set2: begin
       lcd_rs <= 0; //寫指令
       lcd_data <= 8'hC0; //表示第二行第一位
       func <= dat2;
      end
 //---------------------------------------------------------------   
    dat2: begin
       lcd_rs <= 1;  //寫資料
       lcd_data <= data_buf_bit[255:248];
       data_buf_bit <= (data_buf_bit<<8);
       data_cnt <= data_cnt + 1'b1;
       if(data_cnt < 31)  //共32次 把第二行的內容顯示在螢幕上
        func <= dat2;  //不能把第一行字元顯示出來,所以採用分兩次寫資料
       else
       begin
        func <= done;
        data_cnt <= 1'b0;
       end
      end
 //---------------------------------------------------------------   
    done: begin
       if(data_buf!==data ) //判斷有沒有新送進來的資料,對比法
       func <= set0;  //有就回液晶屏初始化
       else
       begin
        func <= done;  //沒有就結束
        en <= 1;
       end
      end
      default:func <= set0;
    endcase
   end
  end
 //---------------------------------------------------------------  
  assign lcd_e = clk_lcd | en;
  assign lcd_rw = 0;
 
endmodule

下面是一小段測試模組
//測試模組
module test(clk,data);
	input clk;
	output [255:0]data;
//靜態測試,測試時,請去掉註釋	
//	assign data="I AM A GOOD BOY!YOU ARE BAD BOY!";

//動態測試	
	reg [255:0]disp;
	integer i;
	always @(posedge clk)
	begin
		i <= i + 1'b1;
		if(i==25'd24999999)
		begin
			i <= 1'b0;
			disp[7:0] <= disp[7:0] + 1; 
			if(disp[7:0]==4'd9)
				disp[7:0] <= 1'b0;
		end
	end
	
	assign data[255:8] = "I AM A GOOD BOY!YOU ARE BAD BOY";
	assign data[7:0]=disp[7:0] + 8'd48;//最後一位迴圈顯示0-9
	
endmodule


頂層模組,連線測試模組和LCD封裝模組
//測試模組頂層模組
module test_top(clk,rst,lcd_rw,lcd_e,lcd_rs,lcd_data);
	input clk;
	input rst;
	output lcd_e;
	output lcd_rw;
	output lcd_rs;
	output [7:0]lcd_data;
	
	wire [255:0]data;
	
	test U1
			(.clk(clk),
			.data(data));
	
	lcd_IP_model U2
			(.clk(clk),
			.rst(rst),
			.data_buf(data),
			.lcd_e(lcd_e),
			.lcd_rw(lcd_rw),
			.lcd_rs(lcd_rs),
			.lcd_data(lcd_data));

endmodule
RTL檢視



顯示效果



相關文章