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

图1
1.模块组装
|
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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
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代码如下:
|
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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
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代码如下所示:
|
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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
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),蜂鸣器的使用请参照蜂鸣器实验。