【FPGA】数码管动态显示之电子时钟

一、数码管动态显示的原理

在这里插入图片描述
数码管动态显示其实就是数码管静态显示的升级版,给的段选信号是一样的,就是显示哪个字,但是不一样的是取决于给哪个位选信号,就是显示哪个数码管,给一个计数器,计数器结束就换下一个位选,以达到肉眼看不到闪烁的效果,就觉得数码管全部都在亮,其实就有个动态扫描的过程的。

二、设计思路

任务要求
设计一个时钟

这里的任务就比之前的数码管静态显示的任务要求高一点了,但学会了动态显示的原理,就不那么难了
思路如下:设计一个时钟无非就是解决一个计数的问题,时钟分为时,分,秒,这里有三种方法,
第一种是一个最大的,记246060的计数器,当记到60的时候,xxx,这种一看就很麻烦,还得算,我不会。
第二种是分为三个计数器,分为时,分,秒,当秒记到60,分开始计数,分记到60,时开始计数,时记到24,这种还行,但我也不会。
第三种是分为六个计数器,分为时的个位和十位,分的个位和十位,秒的个位和十位,分和秒的个位都记到10,分和秒的十位记到6,时的个位当时的时位为2的时候,只能记到4,时的十位记到2。
有了上面的计数思路,就写代码,当然别忘了还得写一个1s的计数器,过1s让秒的个位+1

// 时钟
module clock(
    input                  clk,
    input                  rst_n,
    output      [23:0]     digital_clock
);

parameter CNT_TIME = 50_000_000,
          TIME = 24'h235955;  

// 1s计数器
reg     [25:0]      cnt;
wire                add_cnt;
wire                end_cnt;

// 秒的个位计数器
reg     [3:0]       cnt_s_g;
wire                add_cnt_s_g;
wire                end_cnt_s_g;

// 秒的十位计数器
reg     [3:0]       cnt_s_s;
wire                add_cnt_s_s;
wire                end_cnt_s_s;

// 分的个位计数器
reg     [3:0]       cnt_m_g;
wire                add_cnt_m_g;
wire                end_cnt_m_g;

// 分的十位计数器
reg     [3:0]       cnt_m_s;
wire                add_cnt_m_s;
wire                end_cnt_m_s;

// 时的个位计数器
reg     [3:0]       cnt_h_g;
wire                add_cnt_h_g;
wire                end_cnt_h_g;

// 时的十位计数器
reg     [3:0]       cnt_h_s;
wire                add_cnt_h_s;
wire                end_cnt_h_s;

// 1s计数器
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;

// 秒的个位计数器
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;

// 秒的十位计数器
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;

// 分的个位计数器
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;

// 分的十位计数器
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;

// 时的个位计数器
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));

// 时的十位计数器
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

接下来是写数码管驱动模块
这里传进来的值是16进制的,正好对应6个数码管,一个数是用4个2进制数来表示

// 数码管驱动
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;

// 扫描计数器1ms
reg     [17:0]      scan_cnt;
wire                add_scan_cnt;
wire                end_scan_cnt;

reg     [3:0]      num;

// 小数点
reg                 point;

// 扫描计数器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;

// 计数器扫描位选
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

// 根据位选来给数据
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


// 根据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

三、代码部分

clock.v

// 时钟
module clock(
    input                  clk,
    input                  rst_n,
    output      [23:0]     digital_clock
);

parameter CNT_TIME = 50_000_000,
          TIME = 24'h235955;  

// 1s计数器
reg     [25:0]      cnt;
wire                add_cnt;
wire                end_cnt;

// 秒的个位计数器
reg     [3:0]       cnt_s_g;
wire                add_cnt_s_g;
wire                end_cnt_s_g;

// 秒的十位计数器
reg     [3:0]       cnt_s_s;
wire                add_cnt_s_s;
wire                end_cnt_s_s;

// 分的个位计数器
reg     [3:0]       cnt_m_g;
wire                add_cnt_m_g;
wire                end_cnt_m_g;

// 分的十位计数器
reg     [3:0]       cnt_m_s;
wire                add_cnt_m_s;
wire                end_cnt_m_s;

// 时的个位计数器
reg     [3:0]       cnt_h_g;
wire                add_cnt_h_g;
wire                end_cnt_h_g;

// 时的十位计数器
reg     [3:0]       cnt_h_s;
wire                add_cnt_h_s;
wire                end_cnt_h_s;

// 1s计数器
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;

// 秒的个位计数器
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;

// 秒的十位计数器
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;

// 分的个位计数器
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;

// 分的十位计数器
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;

// 时的个位计数器
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));

// 时的十位计数器
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

数码管驱动模块
seg_driver.v

// 数码管驱动
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;

// 扫描计数器1ms
reg     [17:0]      scan_cnt;
wire                add_scan_cnt;
wire                end_scan_cnt;

reg     [3:0]      num;

// 小数点
reg                 point;

// 扫描计数器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;

// 计数器扫描位选
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

// 根据位选来给数据
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


// 根据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

顶层

module top(
    input                   clk,
    input                   rst_n,
    output      [7:0]       seg_dig,
    output      [5:0]       seg_sel
);

// 中间信号
wire    [23:0]      digital_clock;

// 时钟模块
clock u_clock(
/*input       */.clk            (clk),
/*input       */.rst_n          (rst_n),
/*output      */.digital_clock  (digital_clock)
);

// 数码管驱动模块
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

猜你喜欢

转载自blog.csdn.net/weixin_45888898/article/details/121601868