设计要求:
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
函数或者任务的使用,是使得代码写起来更方便,设计起来更节省时间。
减少重复劳动。
要灵活使用。多观察,多分析,多获取信息。找到相关性,相似性。