简单三段式状态机实验2-LCD12864
此实验是在“基于I2C EPPRPM(AT24C02B) + LCD12864实验”基础上,把LCD模块里的一段式状态机改成三段式,I2C EPPROM模块暂时未改出来,一步一步来吧,改完后代码下载到板子上验证是OK的。
三段式状态机里面要注意的是,抽出来reg 如计数器num、lcd_rs,在利用状态作为判断条件时,得注意是用n_state呢还是用c_state,对于我这样的初学者,一时半会弄不清是用哪个作为判断条件好,怎么办,每种情况都试一次吧。结果用n_state能正常显示,用c_state显示乱码。
用c_state作为判断条件的仿真波形如下:
好奇怪哦,左边框中num为什么没有清零呢?这是因为if else产生的优先权导致,一不小心就范这样的错误。
/***************************************************/
reg [:] c_state,n_state;
reg [:] num;
reg lcd_rs;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
lcd_rs <= 'b0;
else if((c_state == WRITE_DATA0)||(c_state == WRITE_DATA1)||(c_state == WRITE_DATA2)||(c_state == WRITE_DATA3))
lcd_rs <= 'b1; //data mode
else
lcd_rs <= 'b0; //cmd mode
/***************************************************/ /***********************************************************/
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
num <= 'd0;
else if((c_state == WRITE_DATA0) || (c_state == WRITE_DATA1))
num <= num + 'b1;
else if(num == 'd20) //不能放在状态判断后面,否则num不会归零
num <= 'd0;
/***********************************************************/
用n_state作为判断条件的仿真波形如下:
虽然把c_state改成n_state ,但是这个num能清零,好奇怪哦,有时间在好好研究吧,为了保险起见还是改成如下形式:
/***************************************************/
reg [:] c_state,n_state;
reg [:] num;
reg lcd_rs;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
lcd_rs <= 'b0;
else if((n_state == WRITE_DATA0)||(n_state == WRITE_DATA1)||(n_state == WRITE_DATA2)||(n_state == WRITE_DATA3))
lcd_rs <= 'b1; //data mode
else
lcd_rs <= 'b0; //cmd mode
/***************************************************/ /***********************************************************/
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
num <= 'd0;
else if(num == 'd20)
num <= 'd0;
else if((c_state == WRITE_DATA0) || (c_state == WRITE_DATA1))
num <= num + 'b1;
/***********************************************************/
注意看上面两种仿真波形,右边框的位置上是有区别的,c_state要比n_state慢一节拍,但对应输出数据值是c_state,比如当c_state=7时,是对LCD写数据,故lcd_rs=1,输出lcd_data="I",很明显,用c_state作为判断条件的是不对的,输出已经延长一拍。
三段式状态机里还要注意一个地方,在状态机里面既要作为输出,又要作为其他输出信号的判断条件,如下面的en,会产生警告,报出间接指出latch。
/***********************************************************/
reg en;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
en <= 'b1;
dis_data <= 'h00;
end
else case(num)
//I2C閫氫俊瀹為獙
'd0: dis_data <= "I";
'd1: dis_data <= "2";
.
.
.
/***********************************************************/ assign lcd_en = en ? lcd_clk : 'b0;
/***********************************************************/
“Warning (10240): Verilog HDL Always Construct warning at LCD12864.v(121): inferring latch(es) for variable "en", which holds its previous value in one or more paths through the always construct”
虽然有些警告无关紧要的,但还是应尽量避免这样写,办法也是要把en抽出来,我这里是简单的处理下。
/***************************************************/
wire en;
assign en = 'b1;//(n_state == STOP) ? 1'b0 : 'b1;
assign lcd_en = en ? lcd_clk : 'b0;
/***************************************************/
其实这里还有个问题,程序中在IDLE时,lcd_data <= 8'hzz;但仿真波形中没有看到,跟踪调试时,发现这语句永远不执行,自己屡了屡,确实执行不到,一时半会我也想不明白。比较简单的状态机,差不多先这样吧。
代码实现:
LCD12864.v
module LCD12864(
//input
sys_clk,
rst_n,
dis_data_low,
dis_data_hig, //output
lcd_rs,
lcd_rw,
lcd_en,
lcd_data,
lcd_psb
);
input sys_clk;// 50MHZ
input rst_n;
input [:] dis_data_low;
input [:] dis_data_hig; output lcd_rs;//H:data L:command
output lcd_rw;//H:read module L:write module
output lcd_en;//H active
output [:]lcd_data;
output lcd_psb;//H:parallel module L:SPI module /***************************************************/
parameter T3MS = 'd149_999;
parameter IDLE = 'd0,
INIT_FUN_SET1 = 'd1,
INIT_FUN_SET2 = 'd2,
INIT_DISPLAY = 'd3,
INIT_CLEAR = 'd4,
INIT_DOT_SET = 'd5,
SET_DDRAM = 'd6,
WRITE_DATA0 = 'd7,
SET_DDRAM2 = 'd8,
WRITE_DATA1 = 'd9,
WRITE_DATA2 = 'd10,
WRITE_DATA3 = 'd11;
/***************************************************/
//产生周期为6MS的lcd_clk给LCD
reg [:] cnt;
reg lcd_clk;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
cnt <= 'd0;
lcd_clk <= 'b0;
end
else if(cnt == T3MS)begin
cnt <= 'd0;
lcd_clk <= ~lcd_clk;
end
else
cnt <= cnt + 'b1;
/***************************************************/
reg lcd_rs;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
lcd_rs <= 'b0;
else if((n_state == WRITE_DATA0)||(n_state == WRITE_DATA1)||(n_state == WRITE_DATA2)||(n_state == WRITE_DATA3))
lcd_rs <= 'b1; //data mode
else
lcd_rs <= 'b0; //cmd mode
/***************************************************/
reg [:] c_state,n_state;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
c_state <= IDLE;
else
c_state <= n_state;
/***************************************************/
always @(*)
case(c_state)
IDLE: n_state = INIT_FUN_SET1;
INIT_FUN_SET1: n_state = INIT_FUN_SET2;
INIT_FUN_SET2: n_state = INIT_DISPLAY;
INIT_DISPLAY: n_state = INIT_CLEAR;
INIT_CLEAR: n_state = INIT_DOT_SET;
INIT_DOT_SET: n_state = SET_DDRAM;
SET_DDRAM: n_state = WRITE_DATA0;
WRITE_DATA0: if(num == 'd11) n_state = SET_DDRAM2;
else n_state = WRITE_DATA0;
SET_DDRAM2: n_state = WRITE_DATA1;
WRITE_DATA1: if(num == 'd20) n_state = WRITE_DATA2;
else n_state = WRITE_DATA1;
WRITE_DATA2: n_state = WRITE_DATA3;
WRITE_DATA3: n_state = SET_DDRAM;
default: n_state = IDLE;
endcase
/***************************************************/
reg [:] lcd_data;
reg [:] dis_data;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n) lcd_data <= 'h00;
else case(n_state)
IDLE: lcd_data <= 'hzz;
INIT_FUN_SET1: lcd_data <= 'h30; //function setting
INIT_FUN_SET2: lcd_data <= 'h30; //function setting
INIT_DISPLAY: lcd_data <= 'h0c; //display setting
INIT_CLEAR: lcd_data <= 'h01; //clear setting
INIT_DOT_SET: lcd_data <= 'h06; //dot setting
SET_DDRAM: lcd_data <= 'h91; //2 line
WRITE_DATA0: lcd_data <= dis_data;
SET_DDRAM2: lcd_data <= 'h89; //3 line
WRITE_DATA1: lcd_data <= dis_data;
WRITE_DATA2: lcd_data <= dis_data_hig; //high byte
WRITE_DATA3: lcd_data <= dis_data_low; //low byte
default: ;
endcase
/***********************************************************/
reg [:] num;
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n)
num <= 'd0;
else if(num == 'd20)
num <= 'd0;
else if((n_state == WRITE_DATA0) || (n_state == WRITE_DATA1))
num <= num + 'b1;
/***********************************************************/
always @(posedge sys_clk or negedge rst_n)
if(!rst_n)
dis_data <= 'h00;
else case(num)
'd0: dis_data <= "I";
'd1: dis_data <= "2";
'd2: dis_data <= "C";
'd3: dis_data <= " ";//8'hcd;
'd4: dis_data <= "E";//8'ha8;
'd5: dis_data <= "P";//8'hd0;
'd6: dis_data <= "P";//8'hc5;
'd7: dis_data <= "R";//8'hca;
'd8: dis_data <= "O";//8'hb5;
'd9: dis_data <= "M";//8'hd1;
'd10: dis_data <= " ";//8'he9;
'd11: dis_data <= "0";
'd12: dis_data <= "3";
'd13: dis_data <= 8'hb5;
'd14: dis_data <= 8'hd8;
'd15: dis_data <= 8'hd6;
'd16: dis_data <= 8'hb7;
'd17: dis_data <= 8'hd6;
'd18: dis_data <= 8'hb5;
'd19: dis_data <= " ";
default:dis_data <= 'h00;
endcase
/***************************************************/
assign lcd_rw = 'b0;//只有写模式
assign lcd_psb = 'b1;//并口模式
wire en;
assign en = 'b1;//(n_state == STOP) ? 1'b0 : 'b1;
assign lcd_en = en ? lcd_clk : 'b0;
/***************************************************/
endmodule
激励文件(只对LCD模块进行仿真):
lcd_top.v
`timescale 1ns/10ps
module lcd_top;
/*************************************************************/
reg sys_clk;
reg rst_n;
wire start_cnt;
/*************************************************************/
initial begin
sys_clk = 'b0;
rst_n = 'b0;
#;
rst_n = 'b1;
end
/*************************************************************/
always # sys_clk = ~sys_clk;
/*************************************************************/
wire lcd_rs;//H:data L:command
wire lcd_rw;//H:read module L:write module
wire lcd_en;//H active
wire [:] lcd_data;
wire lcd_psb;//H:parallel module L:SPI module
LCD12864 LCD12864_u1(
//input
.sys_clk(sys_clk),
.rst_n(rst_n),
.dis_data_low(""),
.dis_data_hig("c"), //output
.lcd_rs(lcd_rs),
.lcd_rw(lcd_rw),
.lcd_en(lcd_en),
.lcd_data(lcd_data),
.lcd_psb(lcd_psb)
);
endmodule
这里在把一段式状态机的仿真波形贴出来,可以好好的比较比较,这样做有什么不同,但要知道,三段式从输入到输出要比一段式要延时一个节拍。
简单三段式状态机实验2-LCD12864的更多相关文章
- 简单三段式状态机实验1-SOS
一直想从一段式状态机切换到三段式状态机,从书上和网上不断搜寻三段式案例及方法,感觉很简单,就想拿之前做过的实验把一段式改成三段式,可是写起来并非那么简单,很棘手,改完后也没有成功,尤其状态机里面的计数 ...
- 简单三段式状态机实验3-Sequence Detect(序列检测)
1.序列检测器的逻辑功能描述:序列检测指的就是将一个指定的序列从数字码流中识别出来.本例中,我们将设计一个"10010”序列的检测器.设x_in为数字码流输入,z_out为检出标记输出,高电 ...
- Verilog笔记.三段式状态机
之前都是用的一段式状态机,逻辑与输出混在一起,复杂点的就比较吃力了. 所以就开始着手三段式状态机. 组合逻辑与时序逻辑分开,这样就能简单许多了. 但是两者在思考方式上也有着很大的区别. 三段式,分作: ...
- FPGA三段式状态机的思维陷阱
用三段式描述状态机的好处,国内外各位大牛都已经说的很多了,大致可归为以下三点: 1.将组合逻辑和时序逻辑分开,利于综合器分析优化和程序维护; 2.更符合设计的思维习惯; 3.代码少,比一段式状态机更简 ...
- 10010序列检测器的三段式状态机实现(verilog)
序列检测器是时序数字电路设计中经典的教学范例,夏宇闻的<verilog数字系统设计教程>一书中有这个例子,用verilog设计一个“10010”序列的检测器.看完后我觉得F和G两个状态多余 ...
- 基于FPGA的三段式状态机
状态机分类: 通常, 状态机的状态数量有限, 称为有限状态机(FSM) .由于状态机所有触发器的时钟由同一脉冲边沿触发, 故也称之为同步状态机. 根据状态机的输出信号是否与电路的输入有关分为 Meal ...
- (原创)Verilog三段式状态机
下面以上图一个简单的FSM说明三段式Verilog状态机范式: `timescale 1ns / 1ps module FSM( clk,rst_n, in1,in2, out1,out2, CS,N ...
- Verilog三段式状态机描述
时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必需考虑的所有历史信息. 状态机采用VerilogHDL语言编码,建议分为三个always段完成. 三段式建模 ...
- verilog 三段式状态机的技巧
三段式代码多,但是有时钟同步,延时少,组合逻辑跟时序逻辑分开并行出错少. (1)同步状态转移 (2)当前状态判断接下来的状态 (3)动作输出 如果程序复杂可以不止三个always .always ...
随机推荐
- Java中的String[] args
在每个java程序中都有一个方法,public static void main(String[] args)方法,这个参数看了好久没看懂,但是细细看来,还是挺简单的,所有的方法的参数都是一个道理,而 ...
- hdu_5742_It's All In The Mind
题目链接:hdu_5742_It's All In The Mind 题意: 有一个部分的数列,让你找一个满足他给的三个条件的数列,使前两个数的和除这个数列的sum最大 题解: xjb贪心一下就行了. ...
- openwrt 包makefile
$() 表示要执行的一条语句 $(if 条件, 成立执行, 失败执行) if条件分支 $(foreach 变量, 成员列表, 执行体) 成员遍历语句 可以看出,语句是可以嵌套使用的. ...
- PAC全自动脚本代理
Proxy 极低成本绕过GFW的一个PAC代理 Download proxy.zip Proxy 轻量级的FQ工具,不需要安装客户端.可以设置系统代理,也可以设置浏览器代理或者配合SS等插件使用. 免 ...
- css:cdata
javascript <![CDATA[的web标准使用方法 根据W3C XHTML 1.0的规定:在XHTML中,因为<和&这两个符号有特殊意义(小于号用于标签的开始标记), ...
- 后台运行之BackgroundWorker
BackgroundWorker 类允许您在单独的专用线程上运行操作. 耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态. 如果您需要能进行响应的用户界 ...
- OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)
OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...
- Setting DPDK+OVS+QEMU on CentOS
Environment Build Step: these packages are needed for building dpdk+ovs: yum install -y make gcc gli ...
- 图像操作相关 With Quartz 2D
本文将为大家介绍常见的IOS图像处理操作包括以下四部分:旋转,缩放,裁剪以及像素和UIImage之间的转化,主要使用的知识是quartz2D.Quartz2D是CoreGraphics框架中的一个重要 ...
- 在Android studio中进行NDK开发
在Android studio中进行NDK开发 分类: Android平台 软硬件环境 ubuntu kylin 14.04 红米note增强版 Android studio 0.8.6 ndk ...