新闻  |   论坛  |   博客  |   在线研讨会
FPGA学习之——状态机实现流水灯(源码分析)
fwjie | 2012-02-24 12:41:18    阅读:8806   发布文章

Verilog HDL描述的电路大都是并行实现的,状态机就是通过不同的状态迁移来完成一些特定的顺序逻辑。

 

流水灯状态机 

用一个按键sel来控制流水灯的流向,而流水灯的流动是通过状态机来实现的,设计一个流水灯,由四个LED组成,流动间隔一秒,可以按键控制流向(向左还是右),代码如下:

/********************************文件信息**************************************

** 文件名称:state_machine

** 文件作者:樊文杰

** 创建日期:2012.02.16

** 软件平台:Quartus II 9.0

** 硬件平台:EP2C5T144C8

** 功能描述:状态机的行为级描述(顶层模块)

** 实验效果:按下复位键(P67)则四个LED全亮,松开则开始流水效果,按下SEL(P57)

**                 则在等待一次闪动后,开始向相反方向流水(原因是在下一个时钟周期内才检测按键)

**                 

**--------------------------------------修改文件的相关信息----------------------

** 修改人:

** 修改日期:           

** 版本号:

** 修改内容:

**

*******************************************************************************/

module state_machine(

       clk,                                                                 //时钟输入,20M               

       reset_n,                                                           //复位输入,低电平有效

       sel,                                                                 //流水灯方向控制端,0:按下,1:放开

       Q                                                                    //输出,1:点亮,0:熄灭

       );

       input       clk;                                                        //输入

       input       reset_n;

       input       sel;

       output   [3:0] Q;                                            //输出

       reg          [3:0] Q;                                           //寄存器定义

      

       wire        clk_out;                                           //计数的时钟,分频得到,周期:1S

       reg          [2:0] sts;                                          //状态机的状态

             

       parameter       st1 = 2'b00,                                        //状态机状态1参数定义

                            st2 = 2'b01,                                 //状态机状态2参数定义

                            st3 = 2'b10,                                 //状态机状态3参数定义

                            st4 = 2'b11;                                 //状态机状态4参数定义

                           

       //***********************************************************/

       //     模块名称:状态机描述

       //     模块功能:根据不同的状态实现流水灯的左移和右移

       //***********************************************************/

       always@(posedge clk_out or negedge reset_n)

       begin

              if(!reset_n)

                     begin

                            Q <= 4'b1111;                             //复位的时候值为灯全亮

                            sts <= st1;                                   //初始状态

                     end

              else

                     case(sts)                                            //通过不同的状态来实现流水灯的迁移

                            st1:                                            //状态1

                                   begin

                                          Q <= 4'b0001;               //第一状态的第一位输出1

                                          if(sel)

                                                 sts    <= st2;           //根据SEL判断流水灯方向

                                          else

                                                 sts <= st4;

                                   end

                            st2:

                                   begin

                                          Q <= 4'b0010;               //第二个状态第二位输出1

                                          if(sel)

                                                 sts <= st3;

                                          else

                                                 sts    <= st1;

                                   end

                            st3:

                                   begin

                                          Q <= 4'b0100;               //第三个状态第三位输出1

                                          if(sel)

                                                 sts <= st4;

                                          else

                                                 sts <= st2;

                                   end

                            st4:

                                   begin

                                          Q <= 4'b1000;               //第四个状态第四位输出1

                                          if(sel)

                                                 sts <= st1;

                                          else

                                                 sts <= st3;                                         

                                   end

                            default:

                                   sts <= st1;                                   //复位的时候为状态1

                     endcase                                     

       end

      

 

       //***********************************************************/

       //     分频模块例化

       //     从分频模块得到周期为1s 的方波

       //***********************************************************/

clk_div clk_div_0

              (

              .clk(clk),

              .reset_n(reset_n),

              .clk_out(clk_out)

              );           

Endmodule

以下是分频模块源码:

/********************************文件信息**************************************

** 文件名称:state_machine

** 文件作者:樊文杰

** 创建日期:2012.02.16

** 软件平台:Quartus II 9.0

** 硬件平台:EP2C5T144C8

** 功能描述:状态机的行为级描述(分频模块,产生周期为1S的方波)

** 实验效果:

**                 

**--------------------------------------修改文件的相关信息----------------------

** 修改人:

** 修改日期:           

** 版本号:

** 修改内容:

**

*******************************************************************************/

module clk_div(

       clk,                                                   //     时钟输入,20M

       reset_n,                                                    //     复位,高电平有效

       clk_out                                                     //     分频时钟输出

       );

      

       parameter       cnt_top = 26'd10000000;       //     分频系数

       input              clk;                              //     端口

       input              reset_n;

       output            clk_out;

       reg                 clk_out;

       reg                 [25:0]     clk_cnt;          //     时钟计数器

      

always@(posedge clk or negedge reset_n)

       begin

       if(!reset_n)                                               // 复位

              begin

                     clk_out <= 1'b0;                   //     清零

                     clk_cnt <= 0;

              end

       else

              begin

                     if(clk_cnt == cnt_top - 1)  //       0.5 S计数到

                            begin

                                   clk_out <= ~clk_out;//   分频输出(翻转电平)

                                   clk_cnt <= 0;         //     计数清零

                            end

                     else

                            clk_cnt <= clk_cnt + 1'b1;//   计数器加1                                              

              end

       end

endmodule

 

实验效果是,流水灯从LED1向LED4流动,按下sel键后在等待一次流动再向相反方向流动,按下复位键,灯全亮!

四个流水灯共四种状态来实现“流动”效果,而这四种状态是预先定义好的,通过时钟周期来向下一个状态迁移达到效果,所以就定义了st1-st4这四种状态,在每种状态中都已经定义好了LED的亮灭情况,那么为什么按下sel后再等待一次闪动才相反流动呢,因为,FPGA是按时钟周期工作的,在这个时钟周期开始时已经判断了进入哪种状态,然后执行这个状态中的已定义好的逻辑,所以这时在这种状态中并没有检测sel的状态,而是按这个时钟周期开始前的sel状态执行,然后切换状态(已经按下了sel键),在下一个时钟周期,从新检测sel并判断状态,然后才按sel的状态切换状态,从而改变流动方向,应该是这要的。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客