经过前面几个步骤的分析与设计,目前对于各个模块的抽象,封装以及各个模块之间接口与功能的划分已经非常清晰,把修改后的功能框图以及顶层的源代码重新呈现给大家。根据这两部分内容并结合PRA006/010硬件原理图组织硬件实验与调试。

图1
1.模块组装
module complex_counter
(
input inclk,
input sw_in_l, sw_in_r, sw_in_p, sw_in_m,
output [ 5: 0 ] SEAT,
output DP,
output [ 6: 0 ] SEVEN_SEG
);
wire pll_locked;
wire sys_clk;
wire rst = !pll_locked;
wire ms_p;
wire s_p;
wire [ 3: 0 ] s_l;
wire [ 3: 0 ] s_h;
wire [ 3: 0 ] m_l;
wire [ 3: 0 ] m_h;
wire [ 3: 0 ] h_l;
wire [ 3: 0 ] h_h;
wire [ 3: 0 ] d_l;
wire [ 3: 0 ] d_h;
wire [ 3: 0 ] mh_l;
wire [ 3: 0 ] mh_h;
wire [ 5: 0 ] dp_tmp;
wire [ 3: 0 ] seg_a;
wire [ 3: 0 ] seg_b;
wire [ 3: 0 ] seg_c;
wire [ 3: 0 ] seg_d;
wire [ 3: 0 ] seg_e;
wire [ 3: 0 ] seg_f;
wire sw_l;
wire sw_r;
wire sw_p;
wire sw_m;
wire [ 9: 0 ] dp_pos;
f_div f_div_inst
(
.rst ( rst ),
.clk ( sys_clk ),
.ms_p ( ms_p ),
.s_p ( s_p )
);
sw_debounce sw_debounce_inst
(
.rst ( rst ),
.clk ( sys_clk ),
.ms_p ( ms_p ),
.sw_in_l ( sw_in_l ),
.sw_in_r ( sw_in_r ),
.sw_in_p ( sw_in_p ),
.sw_in_m ( sw_in_m ),
.sw_out_l ( sw_l ),
.sw_out_r ( sw_r ),
.sw_out_p ( sw_p ),
.sw_out_m ( sw_m )
);
count count_inst
(
.rst ( rst ),
.clk ( sys_clk ),
.s_p ( s_p ),
.sw_in_l ( sw_l ),
.sw_in_r ( sw_r ),
.sw_in_p ( sw_p ),
.sw_in_m ( sw_m ),
.s_out_l ( s_l ),
.s_out_h ( s_h ),
.m_out_l ( m_l ),
.m_out_h ( m_h ),
.h_out_l ( h_l ),
.h_out_h ( h_h ),
.d_out_l ( d_l ),
.d_out_h ( d_h ),
.mh_out_l ( mh_l ),
.mh_out_h ( mh_h ),
.dp_out_pos ( dp_pos )
);
schdl_adjust schdl_adjust_inst
(
.rst ( rst ),
.clk ( sys_clk ),
.s_p ( s_p ),
.dp_in_pos ( dp_pos ),
.s_in_l ( s_l ),
.s_in_h ( s_h ),
.m_in_l ( m_l ),
.m_in_h ( m_h ),
.h_in_l ( h_l ),
.h_in_h ( h_h ),
.d_in_l ( d_l ),
.d_in_h ( d_h ),
.mh_in_l ( mh_l ),
.mh_in_h ( mh_h ),
.dp_out ( dp_tmp ),
.seg_out_a ( seg_a ),
.seg_out_b ( seg_b ),
.seg_out_c ( seg_c ),
.seg_out_d ( seg_d ),
.seg_out_e ( seg_e ),
.seg_out_f ( seg_f )
);
scan_dis_7seg scan_dis_7seg_inst
(
.rst ( rst ),
.clk ( sys_clk ),
.ms_p ( ms_p ),
.seg_in_a ( seg_a ),
.seg_in_b ( seg_b ),
.seg_in_c ( seg_c ),
.seg_in_d ( seg_d ),
.seg_in_e ( seg_e ),
.seg_in_f ( seg_f ),
.dp_in ( dp_tmp ),
.SEAT ( SEAT ),
.DP ( DP ),
.seven_seg ( SEVEN_SEG )
);
pll1 pll1_inst
(
.areset ( 1'b0 ),
.inclk0 ( inclk ),
.c0 ( sys_clk ),
.locked ( pll_locked )
);
endmodule
2.开发板FII-PRA006/010资源的使用
-
- 数码管,如图2

图2
- 按键资源

图3
- 资源与FPGA管脚映射,如表1,
| 顶层module信号名 | 网络标号 | FPGA管脚 | 开发板上的标识 | FPGA管脚电平瞄准 | 端口说明 |
| inclk | C10_50MCLK | 91 | LVCMOS33 | 输入时钟 | |
| sw_in_p | KEY3 | 11 | PB0 | LVCMOS33 | 按键(+) |
| sw_in_m | KEY2 | 10 | PB3 | LVCMOS33 | 按键(-) |
| sw_in_l | KEY0 | 3 | PB1 | LVCMOS33 | 按键左移 |
| sw_in_r | KEY1 | 7 | PB2 | LVCMOS33 | 按键右移 |
| SEAT[5] | SEG_3V3_D5 | 124 | LVCMOS33 | 位选信号第5位 | |
| SEAT[4] | SEG_3V3_D4 | 127 | LVCMOS33 | 位选信号第4位 | |
| SEAT[3] | SEG_3V3_D3 | 129 | LVCMOS33 | 位选信号第3位 | |
| SEAT[2] | SEG_3V3_D2 | 141 | LVCMOS33 | 位选信号第2位 | |
| SEAT[1] | SEG_3V3_D1 | 142 | LVCMOS33 | 位选信号第1位 | |
| SEAT[0] | SEG_3V3_D0 | 136 | LVCMOS33 | 位选信号第0位 | |
| SEVEN_SEG[6] | SEG_PG | 135 | LVCMOS33 | 段选信号第7位 | |
| SEVEN_SEG[5] | SEG_PF | 138 | LVCMOS33 | 段选信号第6位 | |
| SEVEN_SEG[4] | SEG_PE | 126 | LVCMOS33 | 段选信号第5位 | |
| SEVEN_SEG[3] | SEG_PD | 125 | LVCMOS33 | 段选信号第4位 | |
| SEVEN_SEG[2] | SEG_PC | 133 | LVCMOS33 | 段选信号第3位 | |
| SEVEN_SEG[1] | SEG_PB | 137 | LVCMOS33 | 段选信号第2位 | |
| SEVEN_SEG[0] | SEG_PA | 132 | LVCMOS33 | 段选信号第1位 | |
| DP | SEG_DP | 128 | LVCMOS33 | 小数点 |
- 在工程中锁定管脚
单击Quartus II 菜单–> Assignments–>Pin Planner,打开Pin Planner 界面,按照表1进行管脚锁定,锁定后的管脚位置、所属BANK,电平标准如图4,

图4
2. 重新编译complex_counter 工程并下载,调试。
注意:先进行基础功能调试,再测试边界条件。在设置和调整时应注意边界问题,如秒,分的手动校准范围不能超过59;小时的手动校准范围不能超过23;天的手动校准范围不能超过当前月份的最大值;月的手动校准范围不能超过12。
- 调试步骤如下:
- 观察秒计数是否正常,分是否进位。
- 手动调节分到59,当秒进位时,观察分是否准确进位。
- 调节小时到23,观察是否正确进位。
- 调节月到1月,2月,3 月,4月;日分别调节到31,28,31,30观察是否日与月正确进位。
- 调节其它月份与日,观察进位情况。并观察日、月是否同步。
- 如发现设计缺陷,修复并重新测试。
- 较时到当前时间,并保持运行
3. 修改文档,设计模块划分框图,及完整代码。
模块框图最终版本如图5所示:

图5
代码的修改主要在计数器模块的count和counter文件。与之前的工程相比较,更新后的工程在计数器模块添加了月份计数的反馈(月份输出反馈到日)。在添加月份反馈之后,校准月份,日期的进制也会自动随之改变。比如由1月校准到4月,日期也由31进制变成30进制。
修改后的count代码如下:
module count
(
input rst,
input clk,
input s_p,
input sw_in_l,
input sw_in_r,
input sw_in_p,
input sw_in_m,
output [ 3: 0 ] s_out_l,
output [ 3: 0 ] s_out_h,
output [ 3: 0 ] m_out_l,
output [ 3: 0 ] m_out_h,
output [ 3: 0 ] h_out_l,
output [ 3: 0 ] h_out_h,
output [ 3: 0 ] d_out_l,
output [ 3: 0 ] d_out_h,
output [ 3: 0 ] mh_out_l,
output [ 3: 0 ] mh_out_h,
output reg [ 9: 0 ] dp_out_pos
);
wire m_p;
wire h_p;
wire d_p;
wire mh_p;
always@( posedge clk or posedge rst )
if ( rst )
begin
dp_out_pos <= 10'b1;
end
else
begin
if ( dp_out_pos == 0 )
dp_out_pos <= 10'b1;
if ( sw_in_l )
if ( !dp_out_pos[ 9 ] )
begin
dp_out_pos <= { dp_out_pos[ 8: 0 ], dp_out_pos[ 9] };
end
if ( sw_in_r )
if ( !dp_out_pos[ 0 ] )
begin
dp_out_pos <= { dp_out_pos[ 0 ], dp_out_pos[ 9: 1 ] };
end
end
counter
#(
.RADIX1( 9 ),
.RADIX2( 5 ),
.RADIX3( 0 )
)
counter_second
(
.rst ( rst ),
.clk ( clk ),
.dp_in_pos ( dp_out_pos[ 1: 0 ] ),
.sw_in_p ( sw_in_p ),
.sw_in_m ( sw_in_m ),
.x_in_p ( s_p ),
.x_out_l ( s_out_l ),
.x_out_h ( s_out_h ),
.x_out_p ( m_p )
);
counter
#(
.RADIX1( 9 ),
.RADIX2( 5 ),
.RADIX3( 0 )
)
counter_minute
(
.rst ( rst ),
.clk ( clk ),
.dp_in_pos ( dp_out_pos[ 3: 2 ] ),
.sw_in_p ( sw_in_p ),
.sw_in_m ( sw_in_m ),
.x_in_p ( m_p ),
.x_out_l ( m_out_l ),
.x_out_h ( m_out_h ),
.x_out_p ( h_p )
);
counter
#(
.RADIX1( 3 ),
.RADIX2( 2 ),
.RADIX3( 3 )
)
counter_hour
(
.rst ( rst ),
.clk ( clk ),
.dp_in_pos ( dp_out_pos[ 5: 4 ] ),
.sw_in_p ( sw_in_p ),
.sw_in_m ( sw_in_m ),
.x_in_p ( h_p ),
.x_out_l ( h_out_l ),
.x_out_h ( h_out_h ),
.x_out_p ( d_p )
);
wire [3:0] month_out;
counter
#(
.RADIX1( 1 ),
.RADIX2( 3 ),
.RADIX3( 2 )
)
counter_day
(
.rst ( rst ),
.clk ( clk ),
.dp_in_pos ( dp_out_pos[ 7: 6 ] ),
.sw_in_p ( sw_in_p ),
.sw_in_m ( sw_in_m ),
.x_in_p ( d_p ),
.x_out_l ( d_out_l ),
.x_out_h ( d_out_h ),
.month_in ( month_out ),
.x_out_p ( mh_p )
);
counter
#(
.RADIX1( 2 ),
.RADIX2( 1 ),
.RADIX3( 1 )
)
counter_month
(
.rst ( rst ),
.clk ( clk ),
.dp_in_pos ( dp_out_pos[ 9: 8 ] ),
.sw_in_p ( sw_in_p ),
.sw_in_m ( sw_in_m ),
.x_in_p ( mh_p ),
.x_out_l ( mh_out_l ),
.x_out_h ( mh_out_h ),
.month_out ( month_out ),
.x_out_p ()
);
endmodule
修改后的counter代码如下所示:
module counter
#(
parameter RADIX1 = 9,
parameter RADIX2 = 5,
parameter RADIX3 = 0 // 0 => second or minute; 1 => month; 2 => day ; 3 => hour.
)
(
input rst,
input clk,
input [ 1: 0 ] dp_in_pos, // position
input sw_in_p, // button ++
input sw_in_m, // button --
input x_in_p, // x input pulse enable carry_in
output reg[ 3: 0 ] x_out_l,
output reg[ 3: 0 ] x_out_h,
input [ 3: 0 ] month_in,
output [ 3: 0 ] month_out,
output reg x_out_p // carry out
);
assign month_out = x_out_h * 10 + x_out_l;
always@( posedge clk or posedge rst )
if ( rst )
begin
x_out_l <= (RADIX3 == 2 || RADIX3 == 1 ) ? 1 : 0;
x_out_h <= 0;
x_out_p <= 1'b0;
end
else
begin
x_out_p <= 1'b0;
if ( sw_in_p ) // button ++
begin
if ( dp_in_pos[ 0 ] )
begin
if ( x_out_l == 9 ) x_out_l <= 0;
else x_out_l <= x_out_l + 1;
end
else if ( dp_in_pos[ 1 ] )
begin
if ( x_out_h == 9 ) x_out_h <= 0;
else x_out_h <= x_out_h + 1;
end
end
if ( sw_in_m ) // button --
begin
if ( dp_in_pos[ 0 ] )
begin
if ( x_out_l == 0 ) x_out_l <= 9;
else x_out_l <= x_out_l - 1;
end
else if ( dp_in_pos[ 1 ] )
begin
if ( x_out_h == 0 ) x_out_h <= 9;
else x_out_h <= x_out_h - 1;
end
end
if ( x_in_p )
begin
if ( RADIX3 == 0 )
begin
if ( x_out_l == RADIX1 )
begin
x_out_l <= 0;
if ( x_out_h == RADIX2 )
begin
x_out_h <= 0;
x_out_p <= 1'b1;
end
else
x_out_h <= x_out_h + 1;
end
else
x_out_l <= x_out_l + 1;
end
else if (( RADIX3 == 1 )||( RADIX3 == 3 ))
begin
if ( ( x_out_l == RADIX1 ) && ( x_out_h == RADIX2 ) )
begin
x_out_l <= (RADIX3 == 1) ? 1'b1 : 1'b0;
x_out_h <= 0;
x_out_p <= 1'b1;
end
else if ( x_out_l == 9 )
begin
x_out_l <= 0;
x_out_h <= x_out_h + 1;
end
else
x_out_l <= x_out_l + 1;
end
else if ( RADIX3 == 2 )
begin
case ( month_in )
1, 3, 5, 7, 8, 10, 12:
begin
if ( ( x_out_l == 1 ) && ( x_out_h == 3 ) )
begin
x_out_l <= 1;
x_out_h <= 0;
x_out_p <= 1'b1;
end
else
begin
if ( x_out_l == 9 )
begin
x_out_l <= 0;
x_out_h <= x_out_h + 1;
end
else
x_out_l <= x_out_l + 1;
end
end
2:// possibly developed for leap year adjustment
begin
if ( ( x_out_l == 8 ) && ( x_out_h == 2 ) )
begin
x_out_l <= 1;
x_out_h <= 0;
x_out_p <= 1'b1;
end
else
begin
if ( x_out_l == 9 )
begin
x_out_l <= 0;
x_out_h <= x_out_h + 1;
end
else
x_out_l <= x_out_l + 1;
end
end
4, 6, 9, 11:
begin
if ( ( x_out_l == 0 ) && ( x_out_h == 3 ) )
begin
x_out_l <= 1;
x_out_h <= 0;
x_out_p <= 1'b1;
end
else
begin
if ( x_out_l == 9 )
begin
x_out_l <= 0;
x_out_h <= x_out_h + 1;
end
else
x_out_l <= x_out_l + 1;
end
end
default: ;
endcase
end
end
end
endmodule
在修改完代码之后,重新编译,下载,重复上述调试步骤,观察实验现象。
作业:将上述复杂数字中的设计在PRX100-D上实现。
扩展设计:
- 添加年份计数及显示。
- 添加闰年计算,调整2月的天数。
- 添加蜂鸣器,实现整点报时(PRX100-D),蜂鸣器的使用请参照蜂鸣器实验。