FPGA巩固基础:秒表的设计

设计要求:

6位8段数码管,低三位显示毫秒计数,最高位显示分钟,其余两位显示秒计数。

开始案件与暂停按键,复位按键直接全部归零。

扩展部分:每计满一次,led移位一次。

框图设计:

 

思路讲解:

首先按键信号经过消抖再用,然后把产生的标志信号传给控制模块,由于控制逻辑很简单就把这部分控制逻辑放进“数据产生模块中了”;

然后把数码管与led接口模块interface放进去。

按理来讲,应该重新定义个接口模块再把led与nixie放进去,比较规范。

模块讲解:

值得一提就是数据产生模块与数码管接口模块:

数据产生模块:

 其实输出端口是几个级联得计数器。

代码奉上:

`include "para.v"
module data_gen (
    input		wire				sys_clk         ,
    input		wire				sys_rst_n       ,
    input       wire                start_flag      ,
    input       wire                stop_flag       ,

    output      reg     [3:0]       po_data_one     ,
    output      reg     [3:0]       po_data_two     ,
    output      reg     [3:0]       po_data_thr     ,
    output      reg     [3:0]       po_data_fou     ,
    output      reg     [3:0]       po_data_fiv     ,
    output      reg     [3:0]       po_data_six     ,
    output      reg                 minute_flag     
);
    // localparam
    localparam      IDLE    = 3'b001 ,
                    WORKING = 3'b010 ,
                    STOP    = 3'b100 ;
    // reg signal 
    reg     [15:0]      cnt_1ms     ;
    reg     [2:0]       state_c     ;
    reg     [2:0]       state_n     ;

    // wire signal
    wire                add_cnt_1ms     ;
    wire                end_cnt_1ms     ;
    wire                IDLEtoWORKING   ;
    wire                WORKINGtoSTOP   ;
    wire                STOPtoWORKING   ;   
/******************************************************************************************
********************************************main code**************************************
*******************************************************************************************/
    // // reg signal 
    // reg     [2:0]       state_c     ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            state_c <= IDLE ;
        else 
            state_c <= state_n ;
    end
    // reg     [2:0]       state_n     ;
    always @(*) begin
        if(~sys_rst_n)
            state_n = IDLE ;
        else 
        case(state_c)
        IDLE   :    if(IDLEtoWORKING)
                        state_n = WORKING ;
                    else 
                        state_n = IDLE ;
        WORKING:    if(WORKINGtoSTOP)
                        state_n = STOP ;
                    else 
                        state_n = WORKING ;
        STOP   :    if(STOPtoWORKING)
                        state_n = WORKING ;
                    else 
                        state_n = STOP ;
        default:        state_n = IDLE ;
        endcase
    end

    assign  IDLEtoWORKING   = (state_c == IDLE      ) && (start_flag) ;
    assign  WORKINGtoSTOP   = (state_c == WORKING   ) && (stop_flag ) ;
    assign  STOPtoWORKING   = (state_c == STOP      ) && (start_flag) ;

    // reg     [15:0]      cnt_1ms     ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_1ms <= 16'd0 ;
        else if(add_cnt_1ms) begin
            if(end_cnt_1ms)
                cnt_1ms <= 16'd0 ;
            else 
                cnt_1ms <= cnt_1ms + 1'b1 ;
        end
        else if(state_c == IDLE) 
            cnt_1ms <= 16'd0 ; 
        else 
            cnt_1ms <= cnt_1ms ;// 注意这里,是保持还是归零。
    end
    // wire                add_cnt_1ms ;
    assign  add_cnt_1ms = (state_c == WORKING   ) ;
    // wire                end_cnt_1ms ;
    assign  end_cnt_1ms = add_cnt_1ms && (cnt_1ms == `MAX_CNT_1MS - 1) ;

    // output signal description
    // output		reg     [3:0]       po_data_one    ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_data_one <= 4'd0 ;
        else if(end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1)
            po_data_one <= 4'd0 ;
        else if(end_cnt_1ms)
            po_data_one <= po_data_one + 1'b1 ;
        else
            po_data_one <= po_data_one ;
    end
    // output      reg     [3:0]       po_data_two     ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_data_two <= 4'd0 ;
        else if((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)
            po_data_two <= 4'd0 ;
        else if(end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1)
            po_data_two <= po_data_two + 1'b1 ;
        else
            po_data_two <= po_data_two ;
    end
    // output      reg     [3:0]       po_data_thr     ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_data_thr <= 4'd0 ;
        else if((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1))
            po_data_thr <= 4'd0 ;
        else if(((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1))
            po_data_thr <= po_data_thr + 1'b1 ;
        else
            po_data_thr <= po_data_thr ;
    end
    // output      reg     [3:0]       po_data_fou     , 显示秒的个位 0 ~ 9
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_data_fou <= 4'd0 ;
        else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1))
            po_data_fou <= 4'd0 ;
        else if((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1))
            po_data_fou <= po_data_fou + 1'b1 ;
        else
            po_data_fou <= po_data_fou ;
    end
    // output      reg     [3:0]       po_data_fiv     , 显示秒的十位 0 ~ 5
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_data_fiv <= 4'd0 ;
        else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5))
            po_data_fiv <= 4'd0 ;
        else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1))
            po_data_fiv <= po_data_fiv + 1'b1 ;
        else
            po_data_fiv <= po_data_fiv ;
    end
    // output      reg     [3:0]       po_data_six     ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            po_data_six <= 4'd0 ;
        else if((((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5)) && (po_data_six == `MAX_CNT_NUM - 1))
            po_data_six <= 4'd0 ;
        else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5))
            po_data_six <= po_data_six + 1'b1 ;
        else
            po_data_six <= po_data_six ;
    end
    // reg minute_flag
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            minute_flag <= 1'b0 ;
        else if((((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5)) && (po_data_six == `MAX_CNT_NUM - 1))
            minute_flag <= 1'b1 ;
        else 
            minute_flag <= 1'b0 ;
    end
    
endmodule

状态机设计:

当复位按键按下,现态与次态都需要回到IDLE状态。
在代码层面,给state_n设置一个复位情况。

数码管模块: 

创新点,与以往不同的代码设计,这次用了“函数”,function。

代码奉上:

`include "para.v"
module nixie (
    input		wire				sys_clk         ,
    input		wire				sys_rst_n       ,
    input       wire     [3:0]      pi_data_one     ,
    input       wire     [3:0]      pi_data_two     ,
    input       wire     [3:0]      pi_data_thr     ,
    input       wire     [3:0]      pi_data_fou     ,
    input       wire     [3:0]      pi_data_fiv     ,
    input       wire     [3:0]      pi_data_six     ,

    output		reg     [5:0]       sel             , 
    output		reg     [7:0]       dig              
);
    // reg 
    reg                     dot             ; // 数码管上的小数点。
    reg     [31:0]          cnt_time        ; // 移位寄存器的移位时间,计数器。
    // wire
    wire                    add_cnt_time    ;      
    wire                    end_cnt_time    ;      
/******************************************************************************************
********************************************main code**************************************
*******************************************************************************************/   
    // reg signal description 
    // reg     [31:0]          cnt_time    ; // 移位寄存器的移位时间。
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_time <= 32'd0 ;
        else if(add_cnt_time) begin
            if(end_cnt_time)
                cnt_time <= 32'd0 ;
            else 
                cnt_time <= cnt_time + 1'b1 ;
        end
        else 
            cnt_time <= 32'd0 ; // 注意这里,是保持还是归零。
    end
    // reg         dot ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            dot <= 1'b1 ;
        else 
            dot <= 1'b1 ;
    end

    // wire signal description 
    assign  add_cnt_time = 1'b1 ;
    assign  end_cnt_time = add_cnt_time && (cnt_time == `MAX_CNT_TIES - 1) ;
    // task
    // task       nixie_dig ;
    //     input   [3:0]   data_num    ;
    //     output  [7:0]   po_dig      ;
    //     case (data_num)
    //     0      :    po_dig  = {dot, `ZERO  } ;
    //     1      :    po_dig  = {dot, `ONE   } ;
    //     2      :    po_dig  = {dot, `TWO   } ;
    //     3      :    po_dig  = {dot, `THREE } ;
    //     4      :    po_dig  = {dot, `FOUR  } ;
    //     5      :    po_dig  = {dot, `FIVE  } ;
    //     6      :    po_dig  = {dot, `SIX   } ;
    //     7      :    po_dig  = {dot, `SEVEN } ;
    //     8      :    po_dig  = {dot, `EIGHT } ;
    //     9      :    po_dig  = {dot, `NINE  } ;
    //     default:    po_dig  = 8'd0   ;
    //     endcase
    // endtask
    // function
function [6:0]  dig_num;
    input   [3:0]   data_in ;
    case (data_in)
    0      :    dig_num  = `ZERO  ;
    1      :    dig_num  = `ONE   ;
    2      :    dig_num  = `TWO   ;
    3      :    dig_num  = `THREE ;
    4      :    dig_num  = `FOUR  ;
    5      :    dig_num  = `FIVE  ;
    6      :    dig_num  = `SIX   ;
    7      :    dig_num  = `SEVEN ;
    8      :    dig_num  = `EIGHT ;
    9      :    dig_num  = `NINE  ;
    default:    dig_num  = 7'd0   ;
    endcase
endfunction
    // Output signal description
    // output		reg     [5:0]       sel             , 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            sel <= 6'b111_110 ;
        else if(end_cnt_time)
            sel <= {sel[4:0],sel[5]} ;
        else 
            sel <= sel ;
    end
    // output		reg     [7:0]       dig  
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            dig <= 8'd0 ;
        else 
        case (sel)
        6'b111_110: dig <= {dot, dig_num(pi_data_one)} ;
        6'b111_101: dig <= {dot, dig_num(pi_data_two)} ;
        6'b111_011: dig <= {dot, dig_num(pi_data_thr)} ;
        6'b110_111: dig <= {1'b0, dig_num(pi_data_fou)} ;
        6'b101_111: dig <= {dot, dig_num(pi_data_fiv)} ;
        6'b011_111: dig <= {1'b0, dig_num(pi_data_six)} ;
        default   : dig <= {dot, `SIX  }        ;
        endcase
    end

endmodule

函数或者任务的使用,是使得代码写起来更方便,设计起来更节省时间。

减少重复劳动。

要灵活使用。多观察,多分析,多获取信息。找到相关性,相似性。

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值