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个数码管对应的小数点都由外部输入,本程序仅简单执行以前介绍过扫描、译码、显示电路。