[FPGA] electronic clock for nixie tube dynamic display

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

Keywords: FPGA

Added by microbluechip on Mon, 29 Nov 2021 16:46:04 +0200