Xilinx FPGA:vivado用状态机写4位流水灯,含按键消抖 zynq7000

一、项目要求

(1)要求用状态机实现4位流水灯设计,流水间隔1s。

(2)触发流水灯的条件是按下按键且按键消抖后。

二、设计思路

整体思路:状态机流水灯的模块设计调用按键按下的代码,即FMS.v调用例化的key.v文件

(1)信号需求:

        a.输入信号:输入系统时钟;

                             输入系统复位;

                             按下按键后有一个key信号;

                             按键消抖后有一个key_flag信号;

        b.输出信号:4个led灯,即led[4:0];

(2)计数器需求:

        a.状态机的计数器:流水灯变换间隔是1s,由于zynq7000是50MHz,因此一个周期是20ns,一秒内一共有50000000个20ns,因此状态机计数器需要计数50000000次;

        b.按键消抖的计数器:按下按键后抖动时间大约为20ms,同理按键消抖计数器需要计数500000次;

(3)存储:

        a.两个计数器分别需要存储;

        b.状态机的现态和次态需要存储。

(4)管脚绑定

根据原理图,电平标准3.3V,led分别绑定T12/U12/V12/W13管脚

根据原理图绑定时钟信号和按键信号,复位信号随便绑一个可以用的IO口。

三、key.v代码
`timescale 1ns / 1ps
module key(
input     sys_clk   ,    //系统时钟
input     sys_rst_n ,    //系统复位
input     key,           //输入信号key,即按键按下
output    key_flag       //输出信号key_flag,即按键消消抖成功

    );
parameter delay=50_000_0;   //计数器最大值为500000次(20ms)
reg   [18:0]   cnt       ;   //计数器需要的存储空间换算成二进制需要19位
always@(posedge sys_clk)
if(!sys_rst_n)                //复位信号有效的话计数器清零
   cnt<=0;
   else if(key==0)begin       //当按键按下时(key是低电平)
        if(cnt==delay-1)      //计数器计到最大值的时候 
        cnt<=cnt;             //保持
        else                
        cnt<=cnt+1;           //计数器不断增加 
   end
   else
        cnt<=0;
   assign key_flag=(cnt==delay-2)?1:0;     //当cnt计数到最大值-2时,key_flag输出高电平
endmodule
四、FMS.v代码
`timescale 1ns / 1ps
module FMS_0(
input         sys_clk       ,    //系统时钟
input         sys_rst_n     ,    //系统复位
input          key          ,    //输入信号key
output   reg  [3:0] led         // 输出信号led,,位宽为4,一共4个灯
    );
    wire         key_flag           ;        //key_flag作为中间信号可以不用输出
    parameter   IDLE  =5'b0000_1    ,       //空闲状态下的状态机
                 S0    =5'b0001_0    ,       //第1个led亮时状态机的值
                 S1    =5'b0010_0    ,       //第2个led亮时状态机的值
                 S2    =5'b0100_0    ,       //第3个led亮时状态机的值
                 S3    =5'b1000_0    ;       //第4个led亮时状态机的值
    parameter   delay=50_000_000    ;       //一秒钟计数器计数的次数
     reg [25:0]  count               ;       //给计数次数一个存储空间
     reg [4:0]   cur_state           ;       //当前状态(共5种) 
     reg [4:0]   next_state          ;       //下一个状态(共5种)
  
 //控制状态机计数器计数
 always@(posedge sys_clk)
 if(!sys_rst_n)
    count<=0;
    else if(count==delay-1)
    count<=0;
  else
    count<=count+1;  
  
     
 //描述状态机现态和次态的关系
 
 always@(posedge sys_clk)
 if(!sys_rst_n)
    cur_state<=IDLE;
    else
    cur_state<=next_state;
  
 //描述状态转移  用组合逻辑
 
 always@(*)
 if(!sys_rst_n)
    next_state=IDLE;
    else
    case(cur_state)
    IDLE  :  begin
             if(key_flag)       //当按键消抖结束时,进入S0状态
             next_state=S0;
             else
             next_state=IDLE;
             end 
     S0   :  begin
             if(count==delay-1)
             next_state=S1;
             else
             next_state=cur_state;
             end
     S1   :  begin                
             if(count==delay-1)     
             next_state=S2;       
             else                 
             next_state=cur_state;
             end                  
     S2   :  begin                
             if(count==delay-1)     
             next_state=S3;       
             else                 
             next_state=cur_state;
             end                  
     S3   :  begin                 
             if(count==delay-1)      
             next_state=S0;        
             else                  
             next_state=cur_state; 
             end    
     default next_state=IDLE;
     endcase     
 //用时序逻辑去赋值
 
 //将状态机和led联系起来
always@(posedge sys_clk)
if(!sys_rst_n)
   led<=4'b1111                  ;    //复位状态给让灯全亮
   else
   case(cur_state)
    IDLE   :   led<=4'b1111      ;
     S0    :   led<=4'b0001      ;
     S1    :   led<=4'b0010      ;
     S2    :   led<=4'b0100      ;          
     S3    :   led<=4'b1000      ;
    default:   led<=4'b0000      ;
   endcase

//例化后,可调用key.v中的程序
key    u1(
        .    sys_clk   (sys_clk  )  ,
        .    sys_rst_n (sys_rst_n)  ,
        .    key       (key      )  ,
        .    key_flag  (key_flag )

    );




endmodule
  五、仿真波形
`timescale 1ns / 1ps
module FMS_0_tb();
  reg     sys_clk       ;
  reg     sys_rst_n     ;
  reg      key          ;
  wire    [3:0] led     ;

    
 initial begin
 sys_clk=0;                       //给时钟初值为低电平
 sys_rst_n=0;                     //给复位信号初值为低电平
 key=1;                           //key信号给高电平
 #20
 sys_rst_n=1;                     //过20ns将复位信号拉高
 #500000
 key=0;                           //过500000ns拉低key信号,模拟人按按键
 #50000000                        //过1s后松开按键
 key=1;
 end

 always #10 sys_clk=~sys_clk;     //每10ns时钟信号电平翻转一次,即20ns/50MHz为一个周期
 
 //例化  
    FMS_0    u2(
      . sys_clk     (sys_clk  )   ,
      . sys_rst_n   (sys_rst_n)   ,
      .  key        ( key     )   ,
      .  led        (led      )   
     
    );

endmodule

  调整了下状态机的变换时间,不然波形不太容易看,以下是仿真结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值