1.动态数码管显示
输入变量:时钟,复位,以及对应数码管的输入数据
输出变量:数码管显示数据,以及位选。
对于数码管动态显示胡整体思路如下:此模块作为可以调用的模块,外部输入数据对应着相应位置数码管的输出(也就是对应的位选),设定一个函数根据输入数据用来选择数码管显示的数字,其次设定一个计数器,将输入的数据通过状态机传输出去,并且根据计数器一些位数的变化对位选输出进行移位操作,保证对应位选与段选对应,显示正确的数据。
module nixie_tube(
input clk,
input rst,
input [4:0] in7,
input [4:0] in6,
input [4:0] in5,
input [4:0] in4,
input [4:0] in3,
input [4:0] in2,
input [4:0] in1,
input [4:0] in0,
output reg [7:0]sel_out,
output reg [7:0]sel_data
);
function [7:0]seg;
input[4:0] data;
begin
case(data)
0: seg = 8'b1100_0000;
1: seg = 8'b1111_1001;
2: seg = 8'b1010_0100;
3: seg = 8'b1011_0000;
4: seg = 8'b1001_1001;
5: seg = 8'b1001_0010;
6: seg = 8'b1000_0010;
7: seg = 8'b1111_1000;
8: seg = 8'b1000_0000;
9: seg = 8'b1001_0000;
10: seg = 8'b1000_1000;//A
11: seg = 8'b1000_0011;//B
12: seg = 8'b1010_0111;//C
13: seg = 8'b1010_0001;//D
14: seg = 8'b1000_0110;//E
15: seg = 8'b1000_1110;//F
16: seg = 8'b0111_1111;//.
17: seg = 8'b1011_1111;//-
default seg=0;
endcase
end
endfunction
reg [31:0] sel_cnt;
always@(posedge clk) sel_cnt<=sel_cnt+1;
wire [2:0]sel;
assign sel=sel_cnt[17:15];
always@(posedge clk)
case(sel)
0:sel_data<=seg(in0);
1:sel_data<=seg(in1);
2:sel_data<=seg(in2);
3:sel_data<=seg(in3);
4:sel_data<=seg(in4);
5:sel_data<=seg(in5);
6:sel_data<=seg(in6);
7:sel_data<=seg(in7);
endcase
always@(posedge clk)
sel_out<=~(1<<sel);
endmodule
此模块收获:可通过计数器来同时确定数据和位选的,对于位选信号是一个8位数据输出,哪一位输出1,表示哪个对应的数码管点亮。一般来说人视力所观察到数码管正常亮起的,数码管的刷新时间20ms即可。
2.24小时时钟
本模块输入变量:时钟,复位。
输出变量:数码管输出数据,数码管位选。
本模块思路:本模块用的开发板时钟为50MHz,将秒,分,时的个位和十位分开计算,这样节省资源,每次进位都需要求计数器计够,才能进位。
module clock24(
input clk,rst,
output [7:0]sel_data,
output[7:0]sel_out
);
reg [3:0]secend_time_c;
reg [3:0]secend_time_ten;
reg [3:0]minute_time_c;
reg [3:0]minute_time_ten;
reg [3:0]clock_time_c;
reg [1:0]clock_time_ten;
reg [25:0]secend_time_cnt;
wire secend_time_cnt_of=secend_time_cnt==50*1000*1000-1;
wire secend_time_of={secend_time_ten,secend_time_c}==8'b0101_1001;
wire minute_time_c_of=(secend_time_of && minute_time_c==4'd9);
wire minute_time_ten_of={minute_time_ten,minute_time_c}==8'b0101_1001;
wire clock_start=(minute_time_ten_of && secend_time_of);
wire clock_ten_start=(clock_start && clock_time_c==4'd9);
wire clock_time_of={clock_time_ten,clock_time_c}==5'b1_0100;
always@(posedge clk)
if(rst | (secend_time_cnt_of)) secend_time_cnt<=0;else secend_time_cnt<=secend_time_cnt+1;
always@(posedge clk)
if(rst|(secend_time_c==4'd9 && secend_time_cnt_of ))secend_time_c<=0;
else if(secend_time_cnt_of) secend_time_c<=secend_time_c+1;
always@(posedge clk) if(rst|(secend_time_cnt_of && secend_time_of)) secend_time_ten<=0;
else if(secend_time_c==4'd9 && secend_time_cnt_of && secend_time_cnt_of) secend_time_ten<=secend_time_ten+1;
always@(posedge clk ) if(rst | (minute_time_c_of && secend_time_cnt_of && secend_time_of)) minute_time_c<=0;
else if(secend_time_of && secend_time_cnt_of) minute_time_c<=minute_time_c+1;
always@(posedge clk) if(rst|(secend_time_cnt_of && clock_start )) minute_time_ten<=0;
else if(minute_time_c_of && secend_time_of && secend_time_cnt_of) minute_time_ten<=minute_time_ten+1;
always@(posedge clk ) if(rst | (clock_ten_start && minute_time_ten_of && secend_time_cnt_of)) clock_time_c<=0; else if(clock_start &&secend_time_cnt_of) clock_time_c<=clock_time_c+1;
always@(posedge clk) if(rst|(clock_time_of && clock_start && secend_time_cnt_of)) clock_time_ten<=0;
else if((clock_ten_start && minute_time_ten_of && secend_time_cnt_of)) clock_time_ten<=clock_time_ten+1;
nixie_tube nixie_tube(
. clk(clk),
. rst(rst),
.in7({3'd0,clock_time_ten}),
.in6({1'd0,clock_time_c}),
.in5(17),
.in4({1'd0,minute_time_ten}),
.in3({1'd0,minute_time_c}),
.in2(17),
.in1({1'd0,secend_time_ten}),
.in0({1'd0,secend_time_c}),
.sel_out(sel_out),
.sel_data(sel_data)
);
endmodule
2.1 24小时时钟第二种办法
此方法是直接计算秒,分,时。对于个位,用除法留余数(%),对于十位用除法(/)。但这种方法比较占用资源。
module nixie_tube(
input rst,clk,
output [7:0] seg7_sel,seg7_data
);
reg [31:0] cnt;
reg second_pulse;
wire cnt_of = cnt == 50*1000*10 - 1 ;
always@(posedge clk) if(rst) cnt <= 0; else cnt <= (cnt_of) ? 0 : cnt + 1;
always@(clk) if(cnt_of) second_pulse <= 1; else second_pulse <= 0;
reg [5:0] sec_c,min_c,hur_c;
// R T L
always@(posedge clk)if (rst) sec_c<=0; else if (second_pulse) sec_c <= (sec_c==59) ? 0 : (sec_c + 1 ) ;
always@(posedge clk)if (rst) min_c<=0; else if (second_pulse && sec_c==59) min_c<= (min_c==59) ? 0 : (min_c + 1 ) ;
always@(posedge clk)if (rst) hur_c<=0; else if (second_pulse && sec_c==59 && min_c==59 ) hur_c<= (hur_c==23) ? 0 : (hur_c + 1 ) ;
display_number_4 display_number(
.clk (clk) ,
.in7 (hur_c / 10),
.in6 (hur_c % 10),
.in5 (17) ,
.in4 (min_c / 10),
.in3 (min_c % 10),
.in2 (17) ,
.in1 (sec_c / 10),
.in0 (sec_c % 10),
.seg7_sel (seg7_sel) ,
.seg7_data (seg7_data)
);
endmodule
本模块收获:对于时钟显示,将数据传输给数码显示模块,对应位置显示对应数据。对于分,秒,时的进位要注意秒的计数器一定要计满50*1000*1000-1。对于代码编写,尽量避免乘除运算,因为单周期运算,占用资源太大。