Menu Close

复杂数字钟设计(4)–分频与显示译码

1.分频器

在数字钟设计中分频器是必不可少的,但由于比较简单,而且有专门章节介绍了分频器的设计方法,这里给出简单介绍,并把源程序列出。分频器的设计章节中提到两种方法:

  • 一种是直接输出方波信号,在其它模块使用该信号时可以直接作为时钟使用,这种方法在利用FPGA器件实现时有一些弊端。在将寄存器的输出在挂在到全局时钟总线上时,会带来时序上不收敛的问题,特别是频率较高时,对于Intel_altera FPGA 可以参照PLL生成章节。
  • 另一种是采用时钟脉冲的方式,即输出与系统时钟同步的单时钟周期的脉冲,在后续使用该信号时,作为使能信号出现的,因此整个设计归为同步时钟设计,时序收敛有保障。在复杂数字钟设计中,分频器采用单时钟脉冲的方式输出的,也就是第二种方案。

分频代码如下:

module f_div
(
   input rst,
   input clk,
   output reg ms_p,
   output reg s_p
);

reg [ 16: 0 ] div_count_ms;
reg [ 9: 0 ] div_count_s;


//=====

always@( posedge clk or posedge rst )
    if ( rst )
    begin
        div_count_ms <= 0;
        ms_p <= 0;
    end
    else
    begin
        ms_p <= 0;

        if ( div_count_ms == 99999 )
        begin
            div_count_ms <= 0;
            ms_p <= 1'b1;  //每毫秒有一个单脉冲输出,脉冲宽度是系统时钟的一个周期的宽度,该信号一般不做时钟使用,而是作为后级电路的使能,或选择端使用,见秒分频中该信号的使用
        end
        else
        begin
            div_count_ms <= div_count_ms + 1;
        end
    end

always@( posedge clk or posedge rst )
    if ( rst )
    begin
        div_count_s <= 0;
        s_p <= 0;
    end
    else
    begin
        s_p <= 0;

        if ( ms_p )
        begin
            if ( div_count_s == 999 )
            begin
                div_count_s <= 0;
                s_p <= 1'b1;  //原理与毫秒分频器的原理一致
            end
            else
            begin
                div_count_s <= div_count_s + 1;
            end
        end
    end

endmodule

 

 

2.显示译码

由于现实的内容有秒、分、时、天、月5个内容共10个BCD计数变量需要显示,而数码管只有6个,因此存在选择显示的问题,也就是如何把10BCD选择性的显示在6个数码管上。为简化程序设计,显示译码部分仅提供6个数码管的数据及扫描,把复杂的问题交给调度程序完成,这样的功能划分有利于简化程序设计。代码如下:

module scan_dis_7seg
(
    input            rst,
    input            clk,
    input            ms_p,
    input      [3:0] seg_in_a,
    input      [3:0] seg_in_b,
    input      [3:0] seg_in_c,
    input      [3:0] seg_in_d,
    input      [3:0] seg_in_e,
    input      [3:0] seg_in_f,
    input      [5:0] dp_in,
    output reg [5:0] SEAT,
    output reg       DP,
    output reg [6:0] seven_seg
);
 
reg [3:0] count_sel;
 
always@(posedge clk or posedge rst )
if(rst) 
begin
    SEAT <= 6'b01_1111;
    count_sel <= 0;
    DP <= 1'b1;
end
else 
begin
    if(ms_p) 
    begin
        case (SEAT)
        6'b01_1111:     
        begin
            SEAT <= 6'b11_1110;
            count_sel <= seg_in_a;
            DP <= dp_in[0];
        end
        6'b11_1110: 
        begin
            SEAT <= 6'b11_1101;
            count_sel <= seg_in_b;
            DP <= dp_in[1];
        end
        6'b11_1101: 
        begin
            SEAT <= 6'b11_1011;
            count_sel <= seg_in_c;
            DP <= dp_in[2];
        end
        6'b11_1011: 
        begin
            SEAT <= 6'b11_0111;
            count_sel <= seg_in_d;
            DP <= dp_in[3];
        end
        6'b11_0111: 
        begin
            SEAT <= 6'b10_1111;
            count_sel <= seg_in_e;
            DP <= dp_in[4];
        end
        6'b10_1111: 
        begin
            SEAT <= 6'b01_1111;
            count_sel <= seg_in_f;
            DP <= dp_in[5];
        end
        default: SEAT <= 6'b01_1111;
        endcase
    end
end
 
always@(*)
case(count_sel)
0:       seven_seg = 7'b100_0000;
1:       seven_seg = 7'b111_1001;
2:       seven_seg = 7'b010_0100;
3:       seven_seg = 7'b011_0000;
4:       seven_seg = 7'b001_1001;
5:       seven_seg = 7'b001_0010;
6:       seven_seg = 7'b000_0010;
7:       seven_seg = 7'b111_1000;
8:       seven_seg = 7'b000_0000;
9:       seven_seg = 7'b001_0000;
4'ha:    seven_seg = 7'b000_1000;
4'hb:    seven_seg = 7'b000_0011;
4'hC:    seven_seg = 7'b100_0110;
4'hd:    seven_seg = 7'b010_0001;
4'hE:    seven_seg = 7'b000_0110;
4'hF:    seven_seg = 7'b000_1110;
default: seven_seg = 7'b111_1111;
endcase
 
endmodule

 

 

在上面的代码中程序非常单一,10个BCD码和6个数码管对应的小数点都由外部输入,本程序仅简单执行以前介绍过扫描、译码、显示电路。

 

Posted in FPGA, FPGA, Quartus II, Verilog, Verilog, 教材与教案, 文章

发表评论

相关链接