经过前面几个步骤的分析与设计,目前对于各个模块的抽象,封装以及各个模块之间接口与功能的划分已经非常清晰,把修改后的功能框图以及顶层的源代码重新呈现给大家。根据这两部分内容并结合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),蜂鸣器的使用请参照蜂鸣器实验。