1, Principle of nixie tube dynamic display
In fact, the dynamic display of nixie tube is an upgraded version of the static display of nixie tube. The segment selection signal given is the same, that is, which word is displayed, but the difference depends on which bit selection signal is given, that is, which nixie tube is displayed. Give a counter, and change the next bit selection at the end of the counter, so as to achieve the effect that the naked eye can not see the flicker, and feel that all nixie tubes are on, In fact, there is a dynamic scanning process.
2, Design ideas
Task requirements
Design a clock
The task here is a little higher than that of the previous nixie tube static display, but it is not so difficult to learn the principle of dynamic display
The idea is as follows: designing a clock is nothing more than solving a counting problem. The clock is divided into hour, minute and second. Here are three methods,
The first is the largest counter with 246060. When it reaches 60, xxx is very troublesome at first sight. I won't.
The second is divided into three counters: hour, minute and second. When the second is recorded to 60, minute starts counting, minute is recorded to 60, hour starts counting and hour is recorded to 24. This is OK, but I won't.
The third is divided into six counters, which are divided into time bits and ten bits, minute bits and ten bits, second bits and ten bits, minute and second bits are recorded as 10, minute and second ten bits are recorded as 6, hour bit, when the hour bit is 2, it can only be recorded as 4, and hour ten bits are recorded as 2.
With the above counting idea, write code. Of course, don't forget to write a 1s counter. After 1s, make the bits of seconds + 1
// Clock module clock( input clk, input rst_n, output [23:0] digital_clock ); parameter CNT_TIME = 50_000_000, TIME = 24'h235955; // 1s counter reg [25:0] cnt; wire add_cnt; wire end_cnt; // Bit counter for seconds reg [3:0] cnt_s_g; wire add_cnt_s_g; wire end_cnt_s_g; // Ten bit counter for seconds reg [3:0] cnt_s_s; wire add_cnt_s_s; wire end_cnt_s_s; // Fractional bit counter reg [3:0] cnt_m_g; wire add_cnt_m_g; wire end_cnt_m_g; // Ten digit counter reg [3:0] cnt_m_s; wire add_cnt_m_s; wire end_cnt_m_s; // Bit counter at reg [3:0] cnt_h_g; wire add_cnt_h_g; wire end_cnt_h_g; // Ten bit counter at reg [3:0] cnt_h_s; wire add_cnt_h_s; wire end_cnt_h_s; // 1s counter always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt)begin cnt <= 0; end else begin cnt <= cnt + 1; end end else begin cnt <= cnt; end end assign add_cnt = 1'b1; assign end_cnt = add_cnt && cnt == CNT_TIME - 1; // Bit counter for seconds always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_s_g <= TIME[3:0]; end else if(add_cnt_s_g)begin if(end_cnt_s_g)begin cnt_s_g <= 0; end else begin cnt_s_g <= cnt_s_g + 1; end end else begin cnt_s_g <= cnt_s_g; end end assign add_cnt_s_g = end_cnt; assign end_cnt_s_g = add_cnt_s_g && cnt_s_g == 10 - 1; // Ten bit counter for seconds always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_s_s <= TIME[7:4]; end else if(add_cnt_s_s)begin if(end_cnt_s_s)begin cnt_s_s <= 0; end else begin cnt_s_s <= cnt_s_s + 1; end end else begin cnt_s_s <= cnt_s_s; end end assign add_cnt_s_s = end_cnt_s_g; assign end_cnt_s_s = add_cnt_s_s && cnt_s_s == 6 - 1; // Fractional bit counter always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_m_g <= TIME[11:8]; end else if(add_cnt_m_g)begin if(end_cnt_m_g)begin cnt_m_g <= 0; end else begin cnt_m_g <= cnt_m_g + 1; end end else begin cnt_m_g <= cnt_m_g; end end assign add_cnt_m_g = end_cnt_s_s; assign end_cnt_m_g = add_cnt_m_g && cnt_m_g == 10 - 1; // Ten digit counter always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_m_s <= TIME[15:12]; end else if(add_cnt_m_s)begin if(end_cnt_m_s)begin cnt_m_s <= 0; end else begin cnt_m_s <= cnt_m_s + 1; end end else begin cnt_m_s <= cnt_m_s; end end assign add_cnt_m_s = end_cnt_m_g; assign end_cnt_m_s = add_cnt_m_s && cnt_m_s == 6 - 1; // Bit counter at always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_h_g <= TIME[19:16]; end else if(add_cnt_h_g)begin if(end_cnt_h_g)begin cnt_h_g <= 0; end else begin cnt_h_g <= cnt_h_g + 1; end end else begin cnt_h_g <= cnt_h_g; end end assign add_cnt_h_g = end_cnt_m_s; assign end_cnt_h_g = add_cnt_h_g && (cnt_h_g == (cnt_h_s == 2) ? (4 - 1) : (10 - 1)); // Ten bit counter at always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_h_s <= TIME[23:20]; end else if(add_cnt_h_s)begin if(end_cnt_h_s)begin cnt_h_s <= 0; end else begin cnt_h_s <= cnt_h_s + 1; end end else begin cnt_h_s <= cnt_h_s; end end assign add_cnt_h_s = end_cnt_h_g; assign end_cnt_h_s = add_cnt_h_s && cnt_h_s == 3 - 1; assign digital_clock = {cnt_h_s,cnt_h_g,cnt_m_s,cnt_m_g,cnt_s_s,cnt_s_g}; endmodule
The next step is to write the nixie tube driver module
The value passed in here is hexadecimal, which exactly corresponds to 6 nixie tubes. A number is represented by 4 binary numbers
// Nixie tube drive module seg_driver( input clk, input rst_n, input [23:0] data, output reg [7:0] seg_dig, output reg [5:0] seg_sel ); localparam ZERO = 7'b100_0000, ONE = 7'b111_1001, TWO = 7'b010_0100, THREE = 7'b011_0000, FOUR = 7'b001_1001, FIVE = 7'b001_0010, SIX = 7'b000_0010, SEVEN = 7'b111_1000, EIGHT = 7'b000_0000, NINE = 7'b001_0000; parameter SCAN_TIME = 50_000; // Scan counter 1ms reg [17:0] scan_cnt; wire add_scan_cnt; wire end_scan_cnt; reg [3:0] num; // decimal point reg point; // Scan counter 1ms always @(posedge clk or negedge rst_n)begin if(!rst_n)begin scan_cnt <= 0; end else if(add_scan_cnt)begin if(end_scan_cnt)begin scan_cnt <= 0; end else begin scan_cnt <= scan_cnt + 1; end end else begin scan_cnt <= scan_cnt; end end assign add_scan_cnt = 1'b1; assign end_scan_cnt = add_scan_cnt && scan_cnt == SCAN_TIME - 1; // Counter scan bit selection always @(posedge clk or negedge rst_n)begin if(!rst_n)begin seg_sel <= 6'b111110; end else if(end_scan_cnt)begin seg_sel <= {seg_sel[4:0],seg_sel[5]}; end else begin seg_sel <= seg_sel; end end // Give data according to bit selection always @(posedge clk or negedge rst_n)begin if(!rst_n)begin num <= 4'b0; point <= 1'b0; end else begin case (seg_sel) 6'b111110 : begin num <= data[3:0]; point <= 1'b1; end 6'b111101 : begin num <= data[7:4]; point <= 1'b1; end 6'b111011 : begin num <= data[11:8]; point <= 1'b0; end 6'b110111 : begin num <= data[15:12]; point <= 1'b1; end 6'b101111 : begin num <= data[19:16]; point <= 1'b0; end 6'b011111 : begin num <= data[23:20]; point <= 1'b1; end default: ; endcase end end // Assign value to segment selection according to num always @(posedge clk or negedge rst_n)begin if(!rst_n)begin seg_dig <= 8'hff; end else begin case (num) 0 : seg_dig <={point,ZERO}; 1 : seg_dig <={point,ONE}; 2 : seg_dig <={point,TWO}; 3 : seg_dig <={point,THREE}; 4 : seg_dig <={point,FOUR}; 5 : seg_dig <={point,FIVE}; 6 : seg_dig <={point,SIX}; 7 : seg_dig <={point,SEVEN}; 8 : seg_dig <={point,EIGHT}; 9 : seg_dig <={point,NINE}; default: ; endcase end end endmodule
3, Code part
clock.v
// Clock module clock( input clk, input rst_n, output [23:0] digital_clock ); parameter CNT_TIME = 50_000_000, TIME = 24'h235955; // 1s counter reg [25:0] cnt; wire add_cnt; wire end_cnt; // Bit counter for seconds reg [3:0] cnt_s_g; wire add_cnt_s_g; wire end_cnt_s_g; // Ten bit counter for seconds reg [3:0] cnt_s_s; wire add_cnt_s_s; wire end_cnt_s_s; // Fractional bit counter reg [3:0] cnt_m_g; wire add_cnt_m_g; wire end_cnt_m_g; // Ten digit counter reg [3:0] cnt_m_s; wire add_cnt_m_s; wire end_cnt_m_s; // Bit counter at reg [3:0] cnt_h_g; wire add_cnt_h_g; wire end_cnt_h_g; // Ten bit counter at reg [3:0] cnt_h_s; wire add_cnt_h_s; wire end_cnt_h_s; // 1s counter always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt)begin cnt <= 0; end else begin cnt <= cnt + 1; end end else begin cnt <= cnt; end end assign add_cnt = 1'b1; assign end_cnt = add_cnt && cnt == CNT_TIME - 1; // Bit counter for seconds always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_s_g <= TIME[3:0]; end else if(add_cnt_s_g)begin if(end_cnt_s_g)begin cnt_s_g <= 0; end else begin cnt_s_g <= cnt_s_g + 1; end end else begin cnt_s_g <= cnt_s_g; end end assign add_cnt_s_g = end_cnt; assign end_cnt_s_g = add_cnt_s_g && cnt_s_g == 10 - 1; // Ten bit counter for seconds always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_s_s <= TIME[7:4]; end else if(add_cnt_s_s)begin if(end_cnt_s_s)begin cnt_s_s <= 0; end else begin cnt_s_s <= cnt_s_s + 1; end end else begin cnt_s_s <= cnt_s_s; end end assign add_cnt_s_s = end_cnt_s_g; assign end_cnt_s_s = add_cnt_s_s && cnt_s_s == 6 - 1; // Fractional bit counter always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_m_g <= TIME[11:8]; end else if(add_cnt_m_g)begin if(end_cnt_m_g)begin cnt_m_g <= 0; end else begin cnt_m_g <= cnt_m_g + 1; end end else begin cnt_m_g <= cnt_m_g; end end assign add_cnt_m_g = end_cnt_s_s; assign end_cnt_m_g = add_cnt_m_g && cnt_m_g == 10 - 1; // Ten digit counter always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_m_s <= TIME[15:12]; end else if(add_cnt_m_s)begin if(end_cnt_m_s)begin cnt_m_s <= 0; end else begin cnt_m_s <= cnt_m_s + 1; end end else begin cnt_m_s <= cnt_m_s; end end assign add_cnt_m_s = end_cnt_m_g; assign end_cnt_m_s = add_cnt_m_s && cnt_m_s == 6 - 1; // Bit counter at always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_h_g <= TIME[19:16]; end else if(add_cnt_h_g)begin if(end_cnt_h_g)begin cnt_h_g <= 0; end else begin cnt_h_g <= cnt_h_g + 1; end end else begin cnt_h_g <= cnt_h_g; end end assign add_cnt_h_g = end_cnt_m_s; assign end_cnt_h_g = add_cnt_h_g && (cnt_h_g == (cnt_h_s == 2) ? (4 - 1) : (10 - 1)); // Ten bit counter at always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_h_s <= TIME[23:20]; end else if(add_cnt_h_s)begin if(end_cnt_h_s)begin cnt_h_s <= 0; end else begin cnt_h_s <= cnt_h_s + 1; end end else begin cnt_h_s <= cnt_h_s; end end assign add_cnt_h_s = end_cnt_h_g; assign end_cnt_h_s = add_cnt_h_s && cnt_h_s == 3 - 1; assign digital_clock = {cnt_h_s,cnt_h_g,cnt_m_s,cnt_m_g,cnt_s_s,cnt_s_g}; endmodule
Nixie tube drive module
seg_driver.v
// Nixie tube drive module seg_driver( input clk, input rst_n, input [23:0] data, output reg [7:0] seg_dig, output reg [5:0] seg_sel ); localparam ZERO = 7'b100_0000, ONE = 7'b111_1001, TWO = 7'b010_0100, THREE = 7'b011_0000, FOUR = 7'b001_1001, FIVE = 7'b001_0010, SIX = 7'b000_0010, SEVEN = 7'b111_1000, EIGHT = 7'b000_0000, NINE = 7'b001_0000; parameter SCAN_TIME = 50_000; // Scan counter 1ms reg [17:0] scan_cnt; wire add_scan_cnt; wire end_scan_cnt; reg [3:0] num; // decimal point reg point; // Scan counter 1ms always @(posedge clk or negedge rst_n)begin if(!rst_n)begin scan_cnt <= 0; end else if(add_scan_cnt)begin if(end_scan_cnt)begin scan_cnt <= 0; end else begin scan_cnt <= scan_cnt + 1; end end else begin scan_cnt <= scan_cnt; end end assign add_scan_cnt = 1'b1; assign end_scan_cnt = add_scan_cnt && scan_cnt == SCAN_TIME - 1; // Counter scan bit selection always @(posedge clk or negedge rst_n)begin if(!rst_n)begin seg_sel <= 6'b111110; end else if(end_scan_cnt)begin seg_sel <= {seg_sel[4:0],seg_sel[5]}; end else begin seg_sel <= seg_sel; end end // Give data according to bit selection always @(posedge clk or negedge rst_n)begin if(!rst_n)begin num <= 4'b0; point <= 1'b0; end else begin case (seg_sel) 6'b111110 : begin num <= data[3:0]; point <= 1'b1; end 6'b111101 : begin num <= data[7:4]; point <= 1'b1; end 6'b111011 : begin num <= data[11:8]; point <= 1'b0; end 6'b110111 : begin num <= data[15:12]; point <= 1'b1; end 6'b101111 : begin num <= data[19:16]; point <= 1'b0; end 6'b011111 : begin num <= data[23:20]; point <= 1'b1; end default: ; endcase end end // Assign value to segment selection according to num always @(posedge clk or negedge rst_n)begin if(!rst_n)begin seg_dig <= 8'hff; end else begin case (num) 0 : seg_dig <={point,ZERO}; 1 : seg_dig <={point,ONE}; 2 : seg_dig <={point,TWO}; 3 : seg_dig <={point,THREE}; 4 : seg_dig <={point,FOUR}; 5 : seg_dig <={point,FIVE}; 6 : seg_dig <={point,SIX}; 7 : seg_dig <={point,SEVEN}; 8 : seg_dig <={point,EIGHT}; 9 : seg_dig <={point,NINE}; default: ; endcase end end endmodule
top floor
module top( input clk, input rst_n, output [7:0] seg_dig, output [5:0] seg_sel ); // Intermediate signal wire [23:0] digital_clock; // Clock module clock u_clock( /*input */.clk (clk), /*input */.rst_n (rst_n), /*output */.digital_clock (digital_clock) ); // Nixie tube drive module seg_driver u_seg_driver( /*input */.clk (clk), /*input */.rst_n (rst_n), /*input [23:0] */.data (digital_clock), /*output [7:0] */.seg_dig (seg_dig), /*output [5:0] */.seg_sel (seg_sel) ); endmodule