原创 【我要崛起】第五章 器件时序图的分析,状态机最重要。(1)(更新)

2014-3-15 11:06 3194 18 22 分类: FPGA/CPLD 文集: 基于SDRAM的图像处理

这一章出得有点慢,终于挤到时间出来好好地写,在总结之前要说明一点的是,这一章我分三个小节来叙说,第一小节是从基础的器件开始,咱们的字符型LCD1602的datasheet分析;到第二节的TFT-LCD800*480的datasheet讲解;最后到第三节终极版驱动SDRAM。通过这三个小节让大伙更加清楚理解当你拿到一个器件在手的时候,用FPGA来给他编写驱动代码,应该如何入手,他的关键点在哪里?接下来我都一一帮大伙理顺,和归纳。

我相信,玩过单片机(MCU)的人都基本接触过LCD1602,用它来显示字符的,相对于单片机控制LCD1602,FPGA来驱动就相对比较费力,都是万恶的时序图啊。奇怪,怎么没有LCD1602的英文版datasheet呢?这里只能用中文版来解说。

首先第一点定义好器件的接口,如图所示:

 

5717038251970356900.jpgqq图片20140309001208.jpg

这里我们只需要有用的接口,那些电源接口不需要定义的,可以忽视。

 

第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。

第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。

第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。

第7~14脚:D0~D7为8位双向数据线。

input clk

input rst_n
 
output lcd_en
 
output reg lcd_rs
 
output lcd_rw
 
output reg [7:0] lcd_data
定义好了输入输出口,接下来就看基本操作时序图:
qq图片20140309211553.jpg
只是显示字符,我们只需要写操作的时序图(其他操作可以参考写操作):
qq图片20140309211936.jpg
qq图片20140309212209.jpg
如上图所示,LCD_EN的频率应该控制在2.5M(因为最小值Tc为400ns)以内(不同的LCD1602参数会有所不同)。
我们姑且可以按着单片机的机器周期1us(12个X1/12M=1us 一个机器周期等于12个时钟周期)用计数器分频得:
reg [15:0] cnt;
 
always @ (posedge clk or negedge rst_n)
 
begin
 
if(!rst_n)
 
cnt <= 0;
 
else
 
cnt <= cnt + 1'b1;
 
end
 
assign lcd_en = cnt[15]; 
assign lcd_rw = 1'b0; //因为是写操作,直接拉低
1602液晶模块内部的控制器共有11条控制指令
qq图片20140309230936.jpg
控制命令表
 
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)
 
指令1:清显示,指令码01H,光标复位到地址00H位置。
 
指令2:光标复位,光标返回到地址00H。
 
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
 
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
 
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。
 
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
 
指令7:字符发生器RAM地址设置。
 
指令8:DDRAM地址设置。
 
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
 
指令10:写数据。
 
指令11:读数据。
 
通过上面的材料分析,大概我们应该了解到LCD1602的基本操作了
LCD1602的一般初始化(复位)过程
 
写指令38H:显示模式设置
 
写指令08H:显示关闭
 
写指令01H:显示清屏
 
写指令06H:显示光标移动设置
 
写指令0CH:显示开及光标设置
 
根据初始化的过程,我们开始写状态机,这里为了方便我只显示一行的写操作,就写一行“Hello World”(下面显示的参数都是已经定义好的,就是一个顺序上的问题,很简单,这个不作详细的说明了)
 
parameter [127:0] line_rom1 = "Hello World";
 
wire cmd_flag = (cnt == 16'h7FFF) ? 1'b1 : 1'b0; //当lcd_en有效之前,就写一个命令
 
reg [5:0] current_state, next_state;
 
always @ (posedge clk or negedge rst_n)
 
begin
 
if(!rst_n)
 
current_state <= IDLE;
 
else if(cmd_flag)
 
current_state <= next_state;
 
end
 
//---------------------------------------
 
always@*
 
begin
 
case(current_state)
 
// lcd init
 
IDLE         : next_state = DISP_SET;
 
DISP_SET     : next_state = DISP_OFF;
 
DISP_OFF     : next_state = CLR_SCR;
 
CLR_SCR      : next_state = CURSOR_SET1;
 
CURSOR_SET1 : next_state = CURSOR_SET2;
 
CURSOR_SET2 : next_state = ROW1_ADDR;
 
// display 1th line
 
ROW1_ADDR    : 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 = ROW1_ADDR;
 
default : next_state = IDLE ;
 
endcase
 
end
always @ (posedge clk or negedge rst_n)
 
begin
 
if(!rst_n)
 
begin
 
lcd_rs <= 0;
 
lcd_data <= 8'hXX;
 
end
 
else if(cmd_flag)
 
begin
 
// write statement
 
case(next_state)
 
IDLE         : lcd_rs <= 0,lcd_data <= 8'hxx; //statement
 
//lcd init
 
DISP_SET     : lcd_rs <= 0,lcd_data <= 8'h38; //statement
 
DISP_OFF     : lcd_rs <= 0,lcd_data <= 8'h08; //statement
 
CLR_SCR      : lcd_rs <= 0,lcd_data <= 8'h01; //statement
 
CURSOR_SET1 : lcd_rs <= 0,lcd_data <= 8'h06; //statement
 
CURSOR_SET2 : lcd_rs <= 0,lcd_data <= 8'h0C; //statement
 
// display 1th line
 
ROW1_ADDR    : lcd_rs <= 0,lcd_data <= 8'h80; //statement
 
ROW1_0       : lcd_rs <= 1,lcd_data <= line_rom1[127:120]; //record
 
ROW1_1       : lcd_rs <= 1,lcd_data <= line_rom1[127:120]; //record
 
ROW1_2       : lcd_rs <= 1,lcd_data <= line_rom1[119:112]; //record
 
ROW1_3       : lcd_rs <= 1,lcd_data <= line_rom1[103:96]; //record
 
ROW1_4       : lcd_rs <= 1,lcd_data <= line_rom1[95:88]; //record
 
ROW1_5       : lcd_rs <= 1,lcd_data <= line_rom1[87:80]; //record
 
ROW1_6       : lcd_rs <= 1,lcd_data <= line_rom1[79:72]; //record
 
ROW1_7       : lcd_rs <= 1,lcd_data <= line_rom1[71:64]; //record
 
ROW1_8       : lcd_rs <= 1,lcd_data <= line_rom1[63:56]; //record
 
ROW1_9       : lcd_rs <= 1,lcd_data <= line_rom1[55:48]; //record
 
ROW1_A       : lcd_rs <= 1,lcd_data <= line_rom1[47:40]; //record
 
ROW1_B       : lcd_rs <= 1,lcd_data <= line_rom1[39:32]; //record
 
ROW1_C       : lcd_rs <= 1,lcd_data <= line_rom1[31:24]; //record
 
ROW1_D       : lcd_rs <= 1,lcd_data <= line_rom1[23:16]; //record
 
ROW1_E       : lcd_rs <= 1,lcd_data <= line_rom1[15:8]; //record
 
ROW1_F       : lcd_rs <= 1,lcd_data <= line_rom1[7:0]; //record
 
endcase
 
FPGA驱动LCD1602基本上就是这样的一个思想吧,关键都是要搞好时序图这一块,*****不是有首歌是这样唱的吗?“跟着感觉走,NoNoNo”写时序图也是这样,跟着节拍走,yeyeye。哈哈
更新点:(2014.03. 15   11:00)
应网友“飞言走笔”的提议,应该加上一个状态的转移图更能够让大伙了解时序图用状态机写的重要性。
qq图片20140315105843.jpg
状态图大致如下:
1:初始化开始
 
2:显示模式设置
 
3:显示关闭
 
4:显示清屏
 
5:显示光标移动设置
 
6:显示开及光标设置
 
7:第一行的地址
 
8:第一行的数据
 

文章评论4条评论)

登录后参与讨论

用户443437 2014-3-14 21:16

恩恩,状态图更能够明白

飞言走笔 2014-3-14 14:56

顶一个~~状态机各状态的跳转不妨画个图,更清晰

用户443437 2014-3-12 21:17

恩恩,是呀,现在不需要用FPGA驱动了,我只是用这个例子说说如何克服看时序图的困难

用户377235 2014-3-12 16:05

总感觉用FPGA控制1602之类的东东很费劲且麻烦
相关推荐阅读
用户443437 2015-04-17 08:57
(多图)结合FPGA与DSP的仿人假手控制系统设计
仿人假手作为肢残患者重获人手功能的主要对象,具有重大的社会需求。理想的假手应具有人手的仿生特征,主要体现在假手构造、控制方式与环境感知3 个方面,但由于其有限的体积和复杂的传感器系统,对控制系统提出了...
用户443437 2014-05-10 14:37
熬了几个通宵,答辩终于搞掂
当答辩的评分老师问我:你有FPGA开发板了,外设也是买的,你还需要做什么硬件部分?其实那时我真的想问一下:老师,你其实懂不懂FPGA设计的?外设是谁来驱动的?它不同于ARM,可以用软件来驱动,做一...
用户443437 2014-04-25 09:52
[博客大赛]我也开始玩起Qsys
好久没有发博客了,前一段时间是毕业前的阵痛期,十分的纠结,关于FPGA的东西都不想理了,可以说是力不从心吧,实现就是这样,社会不急切需求这方面的人才,我该何去何从?恋上简单,爱上很难,且行且珍惜。...
用户443437 2014-04-10 17:23
[博客大赛]关于SD卡的读取问题
  最近一直在调试SD卡的读取数据,用串口调试助手来对比数据的正确,但是一直都读不出数据来,代码是特权同学的SD控制模块,我只是做了一些定制,用串口来调试,代码是没有问题的,纠结了我很久...
用户443437 2014-03-21 09:27
口头承诺真的成为了空谈
这几天终于把该忙的工作的搞掂了,接下来的时间都属于我自己的,可以安心去规划一下自己的未来发展方向了,之前一份做彩屏接口研发的工作是最适合我,本人也是对图像的处理感兴趣,第一份工作找的就是自己喜欢的...
我要评论
4
18
关闭 站长推荐上一条 /2 下一条