LCD1602驱动
新近写的,水平有限,欢迎拍砖。实验程序:
---------------------------------------------------
module lcd1602_drive(
input clk,
input rst_n,
// LCD1602 Interface
output reg lcd_data,
output lcd_e,
output reg lcd_rs,
output lcd_rw
);
// +++++++++++++++++++++++++++++++++++++
// 分频模块开始
// +++++++++++++++++++++++++++++++++++++
parameter CLK_DIV = 10_0000; // 分频参数
reg 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 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
---------------------------------------------------
实验现象:
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531559.png
(原文件名:抓图-1.png)
Quartus II 综合报告:
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531565.png
(原文件名:抓图-2.png) 改进版测试文件
module lcd1602_test(
input CLOCK_50, // 板载时钟50MHz
input Q_KEY, // 板载按键RST
// LCD1602 Interface
output LCD1602_DATA, // LCD1602数据总线
output LCD1602_E, // LCD1602使能
output LCD1602_RS, // LCD1602指令数据选择
output LCD1602_RW // LCD1602读写选择
);
// 0 ~ (8*16-1) = 128
// 16bits -> 0123456789ABCDEF <-
wire row1_val = "A Lcd Disp Test ";
wire 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) 好帖记号! 学习了 好贴 上图
http://cache.amobbs.com/bbs_upload782111/files_27/ourdev_538135.JPG
(原文件名:lcd1602液晶显示.JPG)
http://cache.amobbs.com/bbs_upload782111/files_27/ourdev_538136.JPG
(原文件名:lcd1602数字钟.JPG) 为什么我烧进去lcd1602上面什么都没有? 好贴,mark 这个要记好非常好 以为是HAL层驱动~~ 多谢lz的程序,我的一开始频率设的太高,总是不稳定,后来把频率降下来就好了 mark mark mark txt文档中的://在Quartus II中,使用Assignments-Import Assignment,导入该txt文件。
这个有什么作用?是不是输入管脚!!!! // 将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; 回复【15楼】suxilong 小苏
-----------------------------------------------------------------------
高电平锁存,下降沿有效
页:
[1]