查看: 926|回复: 0
打印 上一主题 下一主题

LCD1602驱动

[复制链接]
跳转到指定楼层
沙发
发表于 2016-5-17 19:15:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
新近写的,水平有限,欢迎拍砖。

实验程序:
---------------------------------------------------
module lcd1602_drive(
  input            clk,
  input            rst_n,
  // LCD1602 Interface
  output reg [7:0] lcd_data,
  output           lcd_e,
  output reg       lcd_rs,
  output           lcd_rw
);  

// +++++++++++++++++++++++++++++++++++++
// 分频模块开始
// +++++++++++++++++++++++++++++++++++++
parameter CLK_DIV = 10_0000;            // 分频参数
reg [16:0] cnt;                         // 分频计数子
reg lcd_clk;                            // 500Hz

// 将50MHz板载时钟分频至500Hz
// 注:计数分频,非等占空比
always @(posedge clk, negedge rst_n)
begin
  if(!rst_n)
  begin cnt <= 1'b0; lcd_clk <= 0; end
  else
  begin
    if(cnt <= CLK_DIV)
    begin cnt <= cnt + 1'b1; lcd_clk <= 1; end
    else
    begin cnt <= 1'b0;       lcd_clk <= 0; end
  end   
end
// -------------------------------------
// 分频模块结束
// -------------------------------------


// +++++++++++++++++++++++++++++++++++++
// LCD1602驱动模块开始
// +++++++++++++++++++++++++++++++++++++
/*
* 格雷码编码
* 状态数:初始化5个;换行1个;数据32个;空闲1个;共39个。
*/
// 初始化
parameter INIT_0  = 8'h00;
parameter INIT_1  = 8'h01;
parameter INIT_2  = 8'h03;
parameter INIT_3  = 8'h02;
parameter INIT_4  = 8'h06;
// 显示第一行
parameter ROW1_0  = 8'h07;
parameter ROW1_1  = 8'h05;
parameter ROW1_2  = 8'h04;
parameter ROW1_3  = 8'h0C;
parameter ROW1_4  = 8'h0D;
parameter ROW1_5  = 8'h0F;
parameter ROW1_6  = 8'h0E;
parameter ROW1_7  = 8'h0A;
parameter ROW1_8  = 8'h0B;
parameter ROW1_9  = 8'h09;
parameter ROW1_A  = 8'h08;
parameter ROW1_B  = 8'h18;
parameter ROW1_C  = 8'h19;
parameter ROW1_D  = 8'h1B;
parameter ROW1_E  = 8'h1A;
parameter ROW1_F  = 8'h1E;
// 换行
parameter CH_ROW  = 8'h1F;
// 显示第二行
parameter ROW2_0  = 8'h1D;
parameter ROW2_1  = 8'h1C;
parameter ROW2_2  = 8'h14;
parameter ROW2_3  = 8'h15;
parameter ROW2_4  = 8'h17;
parameter ROW2_5  = 8'h16;
parameter ROW2_6  = 8'h12;
parameter ROW2_7  = 8'h13;
parameter ROW2_8  = 8'h11;
parameter ROW2_9  = 8'h10;
parameter ROW2_A  = 8'h30;
parameter ROW2_B  = 8'h31;
parameter ROW2_C  = 8'h33;
parameter ROW2_D  = 8'h32;
parameter ROW2_E  = 8'h36;
parameter ROW2_F  = 8'h37;
// 空闲
parameter IDLE    = 8'h35;

reg [5:0] current_state, next_state;    // 现态、次态

// FSM: always1
always @ (posedge lcd_clk, negedge rst_n)
if(!rst_n)  current_state <= INIT_0;
else        current_state <= next_state;

// FSM: always2
always
begin
  case(current_state)
    // 初始化
    INIT_0  : next_state = INIT_1;
    INIT_1  : next_state = INIT_2;
    INIT_2  : next_state = INIT_3;
    INIT_3  : next_state = INIT_4;
    INIT_4  : next_state = ROW1_0;
    // 显示第一行
    ROW1_0  : next_state = ROW1_1;
    ROW1_1  : next_state = ROW1_2;
    ROW1_2  : next_state = ROW1_3;
    ROW1_3  : next_state = ROW1_4;
    ROW1_4  : next_state = ROW1_5;
    ROW1_5  : next_state = ROW1_6;
    ROW1_6  : next_state = ROW1_7;
    ROW1_7  : next_state = ROW1_8;
    ROW1_8  : next_state = ROW1_9;
    ROW1_9  : next_state = ROW1_A;
    ROW1_A  : next_state = ROW1_B;
    ROW1_B  : next_state = ROW1_C;
    ROW1_C  : next_state = ROW1_D;
    ROW1_D  : next_state = ROW1_E;
    ROW1_E  : next_state = ROW1_F;
    ROW1_F  : next_state = CH_ROW;
    // 换行
    CH_ROW  : next_state = ROW2_0;
    // 显示第二行
    ROW2_0  : next_state = ROW2_1;
    ROW2_1  : next_state = ROW2_2;
    ROW2_2  : next_state = ROW2_3;
    ROW2_3  : next_state = ROW2_4;
    ROW2_4  : next_state = ROW2_5;
    ROW2_5  : next_state = ROW2_6;
    ROW2_6  : next_state = ROW2_7;
    ROW2_7  : next_state = ROW2_8;
    ROW2_8  : next_state = ROW2_9;
    ROW2_9  : next_state = ROW2_A;
    ROW2_A  : next_state = ROW2_B;
    ROW2_B  : next_state = ROW2_C;
    ROW2_C  : next_state = ROW2_D;
    ROW2_D  : next_state = ROW2_E;
    ROW2_E  : next_state = ROW2_F;
    ROW2_F  : next_state = IDLE;
    // 空闲
    IDLE    : next_state = IDLE;   
    default : next_state = INIT_0;
  endcase
end

// FSM: always3
always @ (posedge lcd_clk, negedge rst_n)
begin
  if(!rst_n)
  begin lcd_rs <= 0; lcd_data <= 8'h00; end
  else
  begin
    case(current_state)      
      INIT_0, CH_ROW, IDLE: lcd_rs <= 0;// 开始写指令      
      ROW1_0, ROW2_0      : lcd_rs <= 1;// 开始写数据
    endcase   
   
    case(current_state)
      // 写指令,初始化
      INIT_0  : lcd_data <= 8'h38;
      INIT_1  : lcd_data <= 8'h0C;
      INIT_2  : lcd_data <= 8'h01;
      INIT_3  : lcd_data <= 8'h06;
      INIT_4  : lcd_data <= 8'H80;
      // 写数据,显示第一行
      ROW1_0  : lcd_data <= "a";
      ROW1_1  : lcd_data <= "b";
      ROW1_2  : lcd_data <= "c";
      ROW1_3  : lcd_data <= "d";
      ROW1_4  : lcd_data <= "e";
      ROW1_5  : lcd_data <= "f";
      ROW1_6  : lcd_data <= "g";
      ROW1_7  : lcd_data <= "h";
      ROW1_8  : lcd_data <= "i";
      ROW1_9  : lcd_data <= "j";
      ROW1_A  : lcd_data <= "k";
      ROW1_B  : lcd_data <= "l";
      ROW1_C  : lcd_data <= "m";
      ROW1_D  : lcd_data <= "n";
      ROW1_E  : lcd_data <= "o";
      ROW1_F  : lcd_data <= "p";
      // 写指令,换行
      CH_ROW  : lcd_data <= 8'hC0;
      // 写数据,显示第二行
      ROW2_0  : lcd_data <= "A";
      ROW2_1  : lcd_data <= "B";
      ROW2_2  : lcd_data <= "C";
      ROW2_3  : lcd_data <= "D";
      ROW2_4  : lcd_data <= "E";
      ROW2_5  : lcd_data <= "F";
      ROW2_6  : lcd_data <= "G";
      ROW2_7  : lcd_data <= "H";
      ROW2_8  : lcd_data <= "I";
      ROW2_9  : lcd_data <= "J";
      ROW2_A  : lcd_data <= "K";
      ROW2_B  : lcd_data <= "L";
      ROW2_C  : lcd_data <= "M";
      ROW2_D  : lcd_data <= "N";
      ROW2_E  : lcd_data <= "O";
      ROW2_F  : lcd_data <= "P";
      // 写指令,空闲
      IDLE    : lcd_data <= 8'h00;
    endcase  
  end
end

// 在时钟高电平有效,低电平失效
// 数据方可被锁存
assign lcd_e  = lcd_clk;               
assign lcd_rw = 1'b0;                   // 只写

// -------------------------------------
// LCD1602驱动模块结束
// -------------------------------------

endmodule
---------------------------------------------------

实验现象:

(原文件名:抓图-1.png)

Quartus II 综合报告:

(原文件名:抓图-2.png)





改进版测试文件

module lcd1602_test(
  input        CLOCK_50,                // 板载时钟50MHz  
  input        Q_KEY,                   // 板载按键RST  
  // LCD1602 Interface
  output [7:0] LCD1602_DATA,            // LCD1602数据总线               
  output       LCD1602_E,               // LCD1602使能
  output       LCD1602_RS,              // LCD1602指令数据选择
  output       LCD1602_RW               // LCD1602读写选择
);

// 0 ~ (8*16-1) = 128
// 16bits             -> 0123456789ABCDEF <-
wire [127:0] row1_val = "A Lcd Disp Test ";
wire [127:0] row2_val = "Amy-studio Pub  ";


// 例化LCD1602驱动
lcd1602_drive u0(
  .clk(CLOCK_50),
  .rst_n(Q_KEY),
  // LCD1602 Input Value
  .row1_val(row1_val),
  .row2_val(row2_val),
  // LCD1602 Interface
  .lcd_data(LCD1602_DATA),
  .lcd_e(LCD1602_E),
  .lcd_rs(LCD1602_RS),
  .lcd_rw(LCD1602_RW)
);

endmodule

完整代码(不晓得什么意思,ourdev一次能贴的代码太短)点击此处下载 ourdev_534318.zip(文件大小:125K) (原文件名:_10_lcd1602_test.zip)


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表