1.分频器
在数字钟设计中分频器是必不可少的,但由于比较简单,而且有专门章节介绍了分频器的设计方法,这里给出简单介绍,并把源程序列出。分频器的设计章节中提到两种方法:
- 一种是直接输出方波信号,在其它模块使用该信号时可以直接作为时钟使用,这种方法在利用FPGA器件实现时有一些弊端。在将寄存器的输出在挂在到全局时钟总线上时,会带来时序上不收敛的问题,特别是频率较高时,对于Intel_altera FPGA 可以参照PLL生成章节。
- 另一种是采用时钟脉冲的方式,即输出与系统时钟同步的单时钟周期的脉冲,在后续使用该信号时,作为使能信号出现的,因此整个设计归为同步时钟设计,时序收敛有保障。在复杂数字钟设计中,分频器采用单时钟脉冲的方式输出的,也就是第二种方案。
分频代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
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个数码管的数据及扫描,把复杂的问题交给调度程序完成,这样的功能划分有利于简化程序设计。代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
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个数码管对应的小数点都由外部输入,本程序仅简单执行以前介绍过扫描、译码、显示电路。