FPGA implements electronic clock through digital tube


foreword

Environment:
1. Quartus18.1
2. vscode
3. Board model: EP4CE6F17C8N


1. Principle

The principle of persistence of vision: when the human eye observes the scene, the light signal is transmitted to the brain nerve, and it takes a short period of time. After the effect of light is over, the visual image does not disappear immediately. This residual vision is called "after image". This phenomenon of vision is called "persistence of vision".
Here our nixie tube is actually switching all the time, but because the switching is too fast, there is a persistence of vision, which affects our eyes to think that the nixie tube has not changed.

1. Common cathode digital tube or common anode digital tube

Common cathode : The common terminal is the cathode, and the digital tube lights up when the anode is added. That is, when the true value is 1, the digital tube lights up; when the true value is 0, the digital tube does not light up.
Common anode : the common terminal is the anode, plus the cathode digital tube lights up. That is, when the true value is 0, the digital tube lights up; when the true value is 1, the digital tube does not light up.
So when using digital tubes, we need to judge whether the digital tubes on the board are common cathode or common anode.

insert image description here

2. The truth table of common cathode and common anode

Common Cathode Truth Table:
insert image description here
Common Anode Truth Table:
insert image description here

2. System design

1. Overall block diagram:

insert image description here

2. Module call

insert image description here

3. Module schematic diagram

insert image description here

3. Source code

1. Counting module

module counter(
    input     wire         clk      ,
    input     wire         rst_n    ,

    output    wire   [16:0] dout
);
localparam [25:0] CNTMAX_1s   = 26'd50_000_000;
localparam [16:0] CNTMAX_days = 17'd86400;
reg [25:0] cnt_1s;
reg [16:0] cnt_days;
wire   [4:0] hour;
wire   [5:0] min ;
wire   [5:0] sec;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt_1s<=26'd0;
    else if(cnt_1s==CNTMAX_1s-1)
        cnt_1s<=26'd0;
    else
        cnt_1s<=cnt_1s+1;
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt_days<=17'd0;
    else if(cnt_days==CNTMAX_days-1&&cnt_1s==CNTMAX_1s-1)
        cnt_days<=17'd0;
    else if(cnt_1s==CNTMAX_1s-1)
        cnt_days<=cnt_days+1;
    else
        cnt_days<=cnt_days;
end
assign hour=cnt_days/3600;
assign min =(cnt_days-(hour*3600))/60;
assign sec =cnt_days-(hour*3600+min*60);
assign dout= {
    
    hour,min,sec};
endmodule

2. Digital tube drive module

module seg_driver(  //数码管驱动
    input               clk     ,
    input               rst_n   ,
    input       [16:0]  din     ,

    output reg  [5:0]   sel     , //片选
    output reg  [7:0]   dig       //段选     
);

    // parameter TIME_SCAN = 50_000 ; // 1MS 让片选一直扫描的移动
parameter TIME_SCAN = 50_000;
    parameter   ZER = 7'b100_0000,  // 0亮 1灭
                ONE = 7'b111_1001,
                TWO = 7'b010_0100,
                THR = 7'b011_0000,
                FOR = 7'b001_1001,
                FIV = 7'b001_0010,
                SIX = 7'b000_0010,
                SEV = 7'b111_1000,
                EIG = 7'b000_0000,
                NIN = 7'b001_0000;

    reg    [15:0]   cnt_scan    ; //扫描计数器
    wire            add_cnt_scan;
    wire            end_cnt_scan;

    reg    [3:0]    data        ; //寄存器 缓存数据
    reg             dot         ; //小数点

    wire   [3:0]    sec_l       ;  //秒低位
    wire   [3:0]    sec_h       ;  //秒 高位
    wire   [3:0]    min_l       ;  // 分地位
    wire   [3:0]    min_h       ;  //分高位
    wire   [3:0]    hou_l       ; 
    wire   [3:0]    hou_h       ;

    assign  sec_l = din[5:0]   % 10 ;  // 59 % 10 = 9 
    assign  sec_h = din[5:0]   / 10 ;  // 59 / 10 = 5 
    assign  min_l = din[11:6]  % 10 ;
    assign  min_h = din[11:6]  / 10 ;
    assign  hou_l = din[16:12] % 10 ;
    assign  hou_h = din[16:12] / 10 ;

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_scan <= 16'b0;
        end
        else if(add_cnt_scan)begin
            if(end_cnt_scan)begin
                cnt_scan <= 16'b0;
            end
            else begin
                cnt_scan <= cnt_scan + 1'b1;
            end
        end
        else begin
            cnt_scan <= cnt_scan ;
        end
    end

    assign add_cnt_scan = 1'b1;
    assign end_cnt_scan = add_cnt_scan && cnt_scan == TIME_SCAN - 1;

    always @(posedge clk or negedge rst_n)begin   // 片选
        if(!rst_n)begin
            sel <= 6'b011_111;
        end
        else if(end_cnt_scan)begin
            sel <= {
    
    sel[0],sel[5:1]};//循环向右移动  
        end
        else begin
            sel <= sel;
        end
    end 

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            data <= 3'b0;
            dot  <= 1'b1;
        end
        else begin
            case(sel)
                6'b011_111 : begin data <= sec_l; dot <= 1'b1; end
                6'b101_111 : begin data <= sec_h; dot <= 1'b1; end
                6'b110_111 : begin data <= min_l; dot <= 1'b0; end
                6'b111_011 : begin data <= min_h; dot <= 1'b1; end
                6'b111_101 : begin data <= hou_l; dot <= 1'b0; end
                6'b111_110 : begin data <= hou_h; dot <= 1'b1; end
                default : begin data <= 3'b0; dot <= 1'b1;end
            endcase
        end
    end
    
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            dig <= 8'b0;
        end
        else begin
            case(data)
                0 : dig <= {
    
    dot,ZER};
                1 : dig <= {
    
    dot,ONE};
                2 : dig <= {
    
    dot,TWO};
                3 : dig <= {
    
    dot,THR};
                4 : dig <= {
    
    dot,FOR};
                5 : dig <= {
    
    dot,FIV};
                6 : dig <= {
    
    dot,SIX};
                7 : dig <= {
    
    dot,SEV};
                8 : dig <= {
    
    dot,EIG};
                9 : dig <= {
    
    dot,NIN};
                default : dig <= 8'b0;
            endcase
        end
    end
endmodule

3. Top-level module

module Clock_top(
    input       clk   ,
    input       rst_n ,

    output  [5:0]  sel ,
    output  [7:0]  dig 
);
wire [16:0] dout;
counter counter_inst(
    .clk      (clk),
    .rst_n    (rst_n),
    
    .dout(dout)
);
seg_driver seg_driver_inst(  //数码管驱动
    .clk     (clk),
    .rst_n   (rst_n),
    .din     (dout),

    .sel     (sel), //片选
    .dig     (dig)  //段选     
);
endmodule

4. Operation effect

Nixie tube realizes electronic clock


V. Summary

This project is not difficult, it just requires us to have a certain understanding of the basics. The first is the realization of the necessary timer, and the operation of chip selection and segment selection of the digital tube.

6. References

1. Detailed explanation of common cathode and common anode digital tubes
2. Digital clock with digital tubes

Guess you like

Origin blog.csdn.net/qq_52215423/article/details/130402854