Menu Close

复杂数字钟设计(6)–模块组装及硬件调试(PRA006)

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

%title插图%num

图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

%title插图%num

图2

  • 按键资源

%title插图%num

图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,

%title插图%num

图4

2. 重新编译complex_counter 工程并下载,调试。

注意:先进行基础功能调试,再测试边界条件。在设置和调整时应注意边界问题,如秒,分的手动校准范围不能超过59;小时的手动校准范围不能超过23;天的手动校准范围不能超过当前月份的最大值;月的手动校准范围不能超过12。

  • 调试步骤如下:
    • 观察秒计数是否正常,分是否进位。
    • 手动调节分到59,当秒进位时,观察分是否准确进位。
    • 调节小时到23,观察是否正确进位。
    • 调节月到1月,2月,3 月,4月;日分别调节到31,28,31,30观察是否日与月正确进位。
    • 调节其它月份与日,观察进位情况。并观察日、月是否同步。
  • 如发现设计缺陷,修复并重新测试。
  • 较时到当前时间,并保持运行

3. 修改文档,设计模块划分框图,及完整代码。

模块框图最终版本如图5所示:

%title插图%num

图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上实现。

扩展设计:

  1.  添加年份计数及显示。
  2. 添加闰年计算,调整2月的天数。
  3. 添加蜂鸣器,实现整点报时(PRX100-D),蜂鸣器的使用请参照蜂鸣器实验
Posted in FPGA, FPGA, Verilog, Verilog, 教材与教案, 文章

发表评论

相关链接