设计要求:
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     
);// localparamlocalparam      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 signalwire                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) beginif(~sys_rst_n) state_c <= IDLE ;else state_c <= state_n ;end// reg     [2:0]       state_n     ;always @(*) beginif(~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 ;endcaseendassign  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) beginif(~sys_rst_n) cnt_1ms <= 16'd0 ;else if(add_cnt_1ms) beginif(end_cnt_1ms)cnt_1ms <= 16'd0 ;else cnt_1ms <= cnt_1ms + 1'b1 ;endelse 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) beginif(~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 ;elsepo_data_one <= po_data_one ;end// output      reg     [3:0]       po_data_two     ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;elsepo_data_two <= po_data_two ;end// output      reg     [3:0]       po_data_thr     ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;elsepo_data_thr <= po_data_thr ;end// output      reg     [3:0]       po_data_fou     , 显示秒的个位 0 ~ 9always @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;elsepo_data_fou <= po_data_fou ;end// output      reg     [3:0]       po_data_fiv     , 显示秒的十位 0 ~ 5always @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;elsepo_data_fiv <= po_data_fiv ;end// output      reg     [3:0]       po_data_six     ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;elsepo_data_six <= po_data_six ;end// reg minute_flagalways @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;endendmodule状态机设计:

当复位按键按下,现态与次态都需要回到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        ; // 移位寄存器的移位时间,计数器。// wirewire                    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) beginif(~sys_rst_n) cnt_time <= 32'd0 ;else if(add_cnt_time) beginif(end_cnt_time)cnt_time <= 32'd0 ;else cnt_time <= cnt_time + 1'b1 ;endelse cnt_time <= 32'd0 ; // 注意这里,是保持还是归零。end// reg         dot ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~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) beginif(~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) beginif(~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  }        ;endcaseendendmodule函数或者任务的使用,是使得代码写起来更方便,设计起来更节省时间。
减少重复劳动。
要灵活使用。多观察,多分析,多获取信息。找到相关性,相似性。