搜索
bottom↓
回复: 16

LCD1602驱动

[复制链接]

出0入0汤圆

发表于 2010-2-1 22:08:42 | 显示全部楼层 |阅读模式
新近写的,水平有限,欢迎拍砖。

实验程序:
---------------------------------------------------
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)

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2010-2-20 00:15:30 | 显示全部楼层
改进版测试文件

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)

出0入4汤圆

发表于 2010-2-20 00:27:24 | 显示全部楼层
好帖  记号!

出0入0汤圆

发表于 2010-3-10 20:50:34 | 显示全部楼层
学习了

出0入0汤圆

发表于 2010-3-11 22:25:12 | 显示全部楼层
好贴

出0入0汤圆

发表于 2010-3-13 11:59:41 | 显示全部楼层
上图



(原文件名:lcd1602液晶显示.JPG)


(原文件名:lcd1602数字钟.JPG)

出0入0汤圆

发表于 2010-4-10 21:38:04 | 显示全部楼层
为什么我烧进去lcd1602上面什么都没有?

出0入0汤圆

发表于 2010-4-11 09:17:49 | 显示全部楼层
好贴,mark

出0入4汤圆

发表于 2010-4-11 09:20:59 | 显示全部楼层
这个要记好  非常好

出0入0汤圆

发表于 2010-4-21 15:07:29 | 显示全部楼层
以为是HAL层驱动~~

出0入0汤圆

发表于 2010-6-22 11:49:15 | 显示全部楼层
多谢lz的程序,我的一开始频率设的太高,总是不稳定,后来把频率降下来就好了

出0入0汤圆

发表于 2010-11-18 19:25:41 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-28 15:57:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-1 00:21:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-1 09:29:54 | 显示全部楼层
txt文档中的://在Quartus II中,使用Assignments-Import Assignment,导入该txt文件。


这个有什么作用?是不是输入管脚!!!!

出0入0汤圆

发表于 2010-12-1 17:16:36 | 显示全部楼层
// 将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     
这一段分频到时有什么用》?????


尤其是这句话!!!!assign lcd_e  = lcd_clk;

出0入0汤圆

发表于 2011-11-17 18:01:56 | 显示全部楼层
回复【15楼】suxilong 小苏
-----------------------------------------------------------------------

高电平锁存,下降沿有效
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 11:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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