| **银杏科技有限公司旗下技术文档发布平台** ||||
|技术支持电话|**0379-69926675-801**|||
|技术支持邮件|Gingko@vip.163.com|||
^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^
| V1.0 | 2020-22-26 | gingko | 初次建立 |
===== 实验十三:有限状态机实验——二段式状态机描述 =====
==== 一、 实验目的与意义 ====
- 掌握二段式状态机的描述方法。
- 掌握宏定义、参数变量的使用方法。
==== 二、 实验设备及平台 ====
- iCore3L 双核心板。
- XiST USB CaBle(或相同功能)仿真器。
- Micro USB线缆。
- 装有HqFpga开发软件的电脑一台。
==== 三、 实验原理 ====
* 本实验讲两段式状态机在数字逻辑电路中的设计和实现。
* 二段式状态机的整个功能由两个always模块完成,一个always模块采用同步时序的方法描述状态转移,另一个模块采用组合逻辑的方式判断状态转移条件,描述状态转移规律,两者结合完成状态机功能。
* 二段式与一段式状态机相比,将同步时序和组合逻辑分别放在不同的always模块中,不仅便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线实现设计。在二段式描述中,常采用组合逻辑描述状态的输出,这种组合逻辑有产生毛刺的可能性,且不利于约束,这也是二段式描述的缺点。
==== 四、 代码讲解 ====
* 本实验状态机的主要功能是通过状态切换实现LED的颜色显示。
* 本实验的实验原理是通过计数器延时产生一个周期为1s的触发信号,以该信号作为状态转移的触发条件,在不同状态显示不同的色彩。实验代码中,一个always块采用同步时序逻辑的方式控制状态机从当前状态跳转到下一个状态。另一个always模块控制不同状态下的逻辑输出。
* 下面这段代码通过对系统时钟计数,产生1秒为周期的触发信号,具体代码如下:
//-----------------------------------------------------//
//循环计数1秒
reg [31:0] time_cnt;
reg state_sig;
always@(posedge fpga_clk or negedge rst_n)
if(!rst_n)
time_cnt <=32'd0;
else if(time_cnt == 32'd25_000_000)
time_cnt <= 32'd0;
else
time_cnt <= time_cnt + 1'd1;
//每计数满1秒拉高1个脉冲信号
always@(posedge fpga_clk or negedge rst_n)
if(!rst_n)
state_sig <= 1'b0;
else if(time_cnt == 32'd25_000_000)
state_sig <= 1'b1;
else
state_sig <= 1'b0;
* 本实验中状态机控制状态跳转的原理如下:
* 1、通过计数器计数,产生一个每1秒钟拉高一次的触发信号state_sig;
* 2、时序逻辑always模块控制状态机由当前状态寄存器切换到到下一个状态寄存器。
* 3、另一个always模块中,首先判断当前状态寄存器的值,根据寄存器值跳转到相应的状态,并根据触发信号State_sig判断是否更新状态寄存器的变量。也就是跳转的下一个状态是否和当前状态保持一样。
* 4、状态机跳转到相应状态时,根据当前状态控制LED的亮灭。
//时序逻辑,控制状态跳转
always@(posedge fpga_clk or negedge rst_n)
if(!rst_n)
led_current_state <= `state_idle;
else
led_current_state <= led_next_state;
//组合逻辑,控制状态跳转条件及状态输出
always@(led_current_state or state_sig or rst_n)
if(!rst_n)
begin
led_r <= LED_ON;
led_next_state <= `state_idle;
end
else
case(led_current_state)
`state_idle:begin//触发信号有效,则跳转到led_on状态,否则,保持当前状态
if(state_sig)
begin
led_next_state <= `state_led_on;
led_r <= LED_ON; //点亮LED
end
else
led_next_state <= `state_idle;
end
`state_led_on:begin
if(state_sig)//触发信号有效,则跳转到led_off状态,否则保持当前状态
begin
led_next_state <= `state_led_off;
led_r <= LED_OFF; //熄灭LED
end
else
led_next_state <= `state_led_on;
end
`state_led_off:begin
if(state_sig)//触发信号有效,则跳转到led_on状态,否则保持当前状态
begin
led_next_state <= `state_led_on;
led_r <= LED_ON; //点亮LED
end
else
led_next_state <= `state_led_off;
end
endcase
* 在这个两段式状态机中,注意状态更新的always模块是时序逻辑,和25MHz的系统时钟fpga_clk同步;而控制状态寄存器更新的always模块的触发信号则不同。
==== 五、 实验步骤及实验结果 ====
* 1、新建工程,参数设置如下图所示。
{{ :icore3l:icore3l_fpga_13_1.png?direct |图 13-1 新建工程及工程设置}}
* 2、将rst_n.v文件添加到工程中;点击“完成”按钮。
* 3、点击左侧栏“设计管理”按钮,然后点击“新建文件”按钮,建立状态机模块文件(fsm_ctrl.v)和顶层模块文件(two_fsm.v),并在顶层模块中例化复位控制模块和状态机模块。之后进行语法检查并保存源文件。
* 4、关闭“设计管理”界面,点击左侧栏的“工程属性”按钮,点击“源文件”栏目下的“+”号,将建立的顶层文件和状态机文件添加到工程,然后点击“确定”按钮。添加完成后再次点击“设计管理”按钮,查看“顶层模块设置”栏里是否为设计的顶层模块名;如果不是,需修改为源文件中的顶层模块名。
{{ :icore3l:icore3l_fpga_13_1.png?direct |图13-2 添加源文件及设置顶层文件}}
* 5、点击主界面的“RTL综合”按钮,运行结果无报错后点击左侧栏的“物理约束”按钮,进行引脚绑定。
* 6、选中“约束编辑器”,点击“确定”按钮,弹出的物理约束界面中绑定信号引脚,然后点击“保存”按钮并退出。
{{ :icore3l:icore3l_fpga_13_1.png?direct |图 13-3 添加物理约束,绑定引脚信息}}
* 7、点击左侧边栏的“全部运行”按钮,进行全编译;编译完成后生成bit文件,然后点击“下载/编程”按钮,将bit文件下载到FPGA中。
* 8、找到工程编译生成的bit文件,选中后点击“下载”按钮。注意检查bit文件的路径。
* 9、可以看到iCore3L 上LED灯每3秒切换一次亮灭状态。
==== 六、 拓展实验 ====
1、 通过HqInsight采样状态机跳转信号及状态寄存器的值,观察信号变化。
2、 对比一段式状态机和二段式状态机状态跳转的时序有何不同。