欢迎光临
我们一直在努力

基于FPGA的按键点灯的项目设计-考试篇

目录

项目设计按键点灯。要求:(14分)

方法一(推荐)

绘制模块框图及波形图

编写模块代码

上板验证

方法二

绘制模块框图及波形图

编写模块代码

上板验证

总结


项目设计按键点灯。要求:(14分)

  • 按键在3s内发生有效的A、B按键按下小灯将保持被点亮;
  • 按键在3s内发生有效的A、C按键按下小灯将保持1s的流水灯效果(左右都行);
  • 按键在3s内发生有效的A、B、C按键按下小灯将保持1s的闪光灯效果(0.5s亮,0.5s灭);
  • 按键在3s内只有1个按键被按下小灯将保持熄灭(只1次按下同样熄灭);
  • (注小灯均为4个灯,共有A、B、C三个按键,有效按下不分先后。小灯效果可以达成条件立即执行也可3s后统一执行,不做强制要求。3s有效区间不会随着有按键按下重新计时。最终改卷以实际上板效果为主,需完成上板前的所有准备工作)。

    方法一(推荐)

    绘制模块框图及波形图

    按键消抖、关灯、开灯、流水灯、闪光灯与4选1的多路选择器,六个模块比较简单,这里波形图就不在绘制了,想看波形图的可以去看我之前的文章。下面绘制的是fsm模块的波形图。

    这里的flag_A、flag_B、flag_C代表在3s内,A、B、C按下时为高电平,3s到了均为低电平。

    在此基础上我加了一个静态数码管显示,循环显示1、2、3,每隔1s跳一次,为了方便按按键。

    编写模块代码

    顶层模块key_led

    module key_led(
    input wire clk ,
    input wire rst_n ,
    input wire A ,
    input wire B ,
    input wire C ,

    output wire [3:0] led ,
    output wire ds ,
    output wire shcp ,
    output wire stcp ,
    output wire oe
    );

    wire key_flag_A;
    wire key_flag_B;
    wire key_flag_C;

    wire [1:0] sel;

    wire [3:0] in1;
    wire [3:0] in2;
    wire [3:0] in3;
    wire [3:0] in4;

    key_XD
    #(
    .CNT_MAX ( 32'd999_999 )//20ms
    )
    key_XD_A
    (
    .clk (clk ),
    .rst_n (rst_n ),
    .key_in (A ),

    .key_flag(key_flag_A)
    );

    key_XD
    #(
    .CNT_MAX ( 32'd999_999 )//20ms
    )
    key_XD_B
    (
    .clk (clk ),
    .rst_n (rst_n ),
    .key_in (B ),

    .key_flag(key_flag_B)
    );

    key_XD
    #(
    .CNT_MAX ( 32'd999_999 )//20ms
    )
    key_XD_C
    (
    .clk (clk ),
    .rst_n (rst_n ),
    .key_in (C ),

    .key_flag(key_flag_C)
    );

    fsm
    #(
    .TIME_3S ( 32'd2 ),
    .TIME_1S ( 32'd1 ),
    .TIME_500MS ( 32'd24_999_999)
    )
    fsm_0
    (
    .clk (clk ) ,
    .rst_n (rst_n) ,
    .A (key_flag_A) ,
    .B (key_flag_B) ,
    .C (key_flag_C) ,

    .sel (sel)
    );

    SGD
    #(
    .CNT_MAX ( 32'd24_999_999 )
    )
    SGD_0
    (
    .clk (clk ) ,
    .rst_n (rst_n) ,

    .led (in4)
    );

    water_led
    #(
    .CNT_MAX_1S ( 32'd49_999_999)//1s
    )
    water_led_0
    (
    .clk (clk ) ,
    .rst_n (rst_n) ,

    .led (in3)
    );

    open_led open_led_0(
    .clk (clk ) ,
    .rst_n (rst_n) ,

    .led (in2)
    );

    close_led close_led_0(
    .clk (clk ) ,
    .rst_n (rst_n) ,

    .led (in1)
    );

    mux_4 mux_4_inst(
    .in_1 (in1) ,
    .in_2 (in2) ,
    .in_3 (in3) ,
    .in_4 (in4) ,
    .sel (sel) ,

    .led (led)
    );

    seg_595_static seg_595_static_inst(
    .clk (clk ) ,
    .rst_n (rst_n) ,

    .ds (ds ) ,
    .shcp (shcp ) ,
    .stcp (stcp ) ,
    .oe (oe )
    );
    endmodule

    功能模块key_XD

    module key_XD
    #(
    parameter CNT_MAX = 32'd999_999
    )
    (
    input wire clk ,
    input wire rst_n ,
    input wire key_in ,

    output reg key_flag
    );

    reg [31:0] cnt;
    //cnt:低电平计数器
    always @ (posedge clk or negedge rst_n)
    if(!rst_n)
    cnt <= 32'd0;
    else if(key_in)//高电平
    cnt <= 32'd0;
    else if(cnt == CNT_MAX)//低电平且计数满
    cnt <= cnt;
    else//低电平且计数未满
    cnt <= cnt + 1'b1;
    //key_flag:当计数满20ms后产生按键有效标志位
    //且key_flag在999_998时拉高,维持一个时钟的高电平
    always @ (posedge clk or negedge rst_n)
    if(!rst_n)
    key_flag <= 1'b0;
    else if(cnt == CNT_MAX – 1'b1)
    key_flag <= 1'b1;
    else
    key_flag <= 1'b0;
    endmodule

    功能模块fsm

    module fsm
    #(
    parameter TIME_3S = 32'd2 ,
    parameter TIME_1S = 32'd1 ,
    parameter TIME_500MS = 32'd24_999_999
    )
    (
    input wire clk ,
    input wire rst_n ,
    input wire A ,
    input wire B ,
    input wire C ,

    output reg [1:0] sel
    );

    reg [31:0] cnt_3s;
    reg [31:0] cnt_1s;
    reg [31:0] cnt_500ms;
    reg flag_A;
    reg flag_B;
    reg flag_C;

    //cnt_500ms
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_500ms <= 32'd0;
    else if(cnt_500ms == TIME_500MS)
    cnt_500ms <= 32'd0;
    else
    cnt_500ms <= cnt_500ms + 1'b1;
    end
    //cnt_1s
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_1s <= 32'd0;
    else if(cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    cnt_1s <= 32'd0;
    else if(cnt_500ms == TIME_500MS)
    cnt_1s <= cnt_1s + 1'b1;
    else
    cnt_1s <= cnt_1s;
    end
    //cnt_3s
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_3s <= 32'd0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    cnt_3s <= 32'd0;
    else if(cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    cnt_3s <= cnt_3s + 1'b1;
    else
    cnt_3s <= cnt_3s;
    end
    // flag_A:3s内,A按下为高,没按下或者3s到了均为低
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    flag_A <= 1'b0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    flag_A <= 1'b0;
    else if(A)
    flag_A <= 1'b1;
    else
    flag_A <= flag_A;
    end
    //flag_B
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    flag_B <= 1'b0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    flag_B <= 1'b0;
    else if(B)
    flag_B <= 1'b1;
    else
    flag_B <= flag_B;
    end
    //flag_C
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    flag_C <= 1'b0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    flag_C <= 1'b0;
    else if(C)
    flag_C <= 1'b1;
    else
    flag_C <= flag_C;
    end
    //sel
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    sel <= 2'b00;//熄灭
    else if(flag_A && flag_B && flag_C)//保持1s的闪光灯效果(0.5s亮,0.5s灭)
    sel <= 2'b11;
    else if(flag_A && flag_C)//保持1s的流水灯效果(左右都行)
    sel <= 2'b10;
    else if(flag_A && flag_B)//保持被点亮
    sel <= 2'b01;
    else if(flag_A || flag_B || flag_C)//保持熄灭
    sel <= 2'b00;
    else
    sel <= sel;
    end

    endmodule

    功能模块close_led

    module close_led(
    input wire clk ,
    input wire rst_n ,

    output wire [3:0] led
    );

    assign led = 4'hf;

    endmodule

    功能模块open_led

    module open_led(
    input wire clk ,
    input wire rst_n ,

    output wire [3:0] led
    );

    assign led = 4'b0000;

    endmodule

    功能模块water_led

    module water_led
    #(
    parameter CNT_MAX_1S = 32'd49_999_999//1s
    )
    (
    input wire clk ,
    input wire rst_n ,

    output reg [3:0] led
    );
    reg [31:0] cnt_1s;

    //cnt_1s
    always @ (posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_1s <= 32'd0;
    else if(cnt_1s == CNT_MAX_1S)
    cnt_1s <= 32'd0;
    else
    cnt_1s <= cnt_1s + 1'b1;
    end
    //led
    always @ (posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    led <= 4'b0111;
    else if(cnt_1s == CNT_MAX_1S)
    led <= {led[0],led[3:1]};
    else
    led <= led;
    end
    endmodule

    功能模块SGD

    module SGD
    #(
    parameter CNT_MAX = 32'd24_999_999
    )
    (
    input wire clk ,
    input wire rst_n ,

    output reg [3:0] led
    );

    reg [31:0] cnt;
    //cnt
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt <= 32'd0;
    else if(cnt == CNT_MAX)
    cnt <= 32'd0;
    else
    cnt <= cnt + 1'b1;
    end
    //led
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    led <= 4'h0;
    else if(cnt == CNT_MAX)
    led <= ~led;
    else
    led <= led;
    end
    endmodule

    功能模块mux_4

    module mux_4(
    input wire [3:0] in_1 ,
    input wire [3:0] in_2 ,
    input wire [3:0] in_3 ,
    input wire [3:0] in_4 ,
    input wire [1:0] sel ,

    output reg [3:0] led
    );

    always@(*)
    begin
    case(sel)
    2'b00 : led = in_1;
    2'b01 : led = in_2;
    2'b10 : led = in_3;
    2'b11 : led = in_4;
    default:led = in_1;
    endcase
    end

    endmodule

    功能模块seg_595_static

    module seg_595_static(
    input wire clk ,
    input wire rst_n ,

    output wire ds ,
    output wire shcp ,
    output wire stcp ,
    output wire oe
    );

    wire [7:0] seg;
    wire [5:0] sel;

    seg_static seg_static_1
    (
    .clk (clk ) ,
    .rst_n (rst_n) ,

    .seg (seg ) ,
    .sel (sel )
    );

    hc595_ctrl hc595_ctrl_1
    (
    .clk (clk ) ,
    .rst_n(rst_n) ,
    .seg (seg ) ,
    .sel (sel ) ,

    .ds (ds ) ,
    .shcp (shcp ) ,
    .stcp (stcp ) ,
    .oe (oe )
    );
    endmodule

    功能模块seg_static

    module seg_static
    #(
    parameter CNT_MAX_1S = 32'd49_999_999//1s
    )
    (
    input wire clk ,
    input wire rst_n ,

    output reg [7:0] seg ,
    output reg [5:0] sel
    );

    reg [31:0] cnt_1s;
    reg [3:0] cnt_data ;
    //cnt_1s
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_1s <= 32'd0;
    else if(cnt_1s == CNT_MAX_1S)
    cnt_1s <= 32'd0;
    else
    cnt_1s <= cnt_1s + 1'b1;
    end
    //cnt_data
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_data <= 4'h1;
    else if(cnt_data == 4'h3 && cnt_1s == CNT_MAX_1S)
    cnt_data <= 4'h1;
    else if(cnt_1s == CNT_MAX_1S)
    cnt_data <= cnt_data + 1'b1;
    else
    cnt_data <= cnt_data;
    end
    //seg
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    seg <= 8'hff;//数码管8段全灭
    else case(cnt_data)
    4'h0 : seg <= 8'hc0;
    4'h1 : seg <= 8'hf9;
    4'h2 : seg <= 8'ha4;
    4'h3 : seg <= 8'hb0;
    4'h4 : seg <= 8'h99;
    4'h5 : seg <= 8'h92;
    4'h6 : seg <= 8'h82;
    4'h7 : seg <= 8'hf8;
    4'h8 : seg <= 8'h80;
    4'h9 : seg <= 8'h90;
    4'ha : seg <= 8'h88;
    4'hb : seg <= 8'h83;
    4'hc : seg <= 8'hc6;
    4'hd : seg <= 8'ha1;
    4'he : seg <= 8'h86;
    4'hf : seg <= 8'h8e;
    default:seg <= 8'hff;//数码管8段全灭
    endcase
    end
    //sel
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    sel <= 6'd0;
    else
    sel <= 6'b111_111;
    end
    endmodule

    功能模块hc595_ctrl

    module hc595_ctrl
    #(
    parameter CNT_MAX_DIV4 = 2'd3 ,
    parameter CNT_MAX_BIT = 4'd13
    )
    (
    input wire clk ,
    input wire rst_n ,
    input wire [7:0] seg ,
    input wire [5:0] sel ,

    output reg ds ,
    output reg shcp ,
    output reg stcp ,
    output reg oe
    );

    reg [13:0] data ;
    reg [1:0] cnt_div4;
    reg [3:0] cnt_bit ;
    //data
    always@(*)
    begin
    if(!rst_n)
    data = 14'd0;
    else
    data = {seg[0],seg[1],seg[2],seg[3],seg[4],seg[5],seg[6],seg[7],sel[5:0]};
    end
    //cnt_div4
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_div4 <= 2'd0;
    else if(cnt_div4 == CNT_MAX_DIV4)
    cnt_div4 <= 2'd0;
    else
    cnt_div4 <= cnt_div4 + 1'b1;
    end
    //cnt_bit
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_bit <= 4'd0;
    else if(cnt_bit == CNT_MAX_BIT && cnt_div4 == CNT_MAX_DIV4)
    cnt_bit <= 4'd0;
    else if(cnt_div4 == CNT_MAX_DIV4)
    cnt_bit <= cnt_bit + 1'b1;
    else
    cnt_bit <= cnt_bit;
    end
    // ds
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    ds <= 1'd0;
    else
    ds <= data[cnt_bit];
    end
    // shcp
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    shcp <= 1'b0;
    else if(cnt_div4 == CNT_MAX_DIV4 – 1'b1 || cnt_div4 == CNT_MAX_DIV4)
    shcp <= 1'b1;
    else
    shcp <= 1'b0;
    end
    // stcp
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    stcp <= 1'b0;
    else if(cnt_bit == CNT_MAX_BIT && cnt_div4 == CNT_MAX_DIV4)
    stcp <= 1'b1;
    else
    stcp <= 1'b0;
    end
    // oe
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    oe <= 1'b1;
    else
    oe <= 1'b0;
    end
    endmodule

    上板验证

    绑定引脚

    使用signaltap查看波形并验证功能

    方法二

    绘制模块框图及波形图

    下面只需要绘制fsm模块的波形图即可

    这里的flag_A、flag_B、flag_C代表在3s内,A、B、C按下时为高电平,3s到了均为低电平。

    state_flag:用于提前知晓是切换到流水灯还是闪光灯,方便更新led初值

    编写模块代码

    顶层模块key_fsm_led

    module key_fsm_led(
    input wire clk ,
    input wire rst_n ,
    input wire A ,
    input wire B ,
    input wire C ,

    output wire [3:0] led ,
    output wire ds ,
    output wire shcp ,
    output wire stcp ,
    output wire oe
    );

    wire key_flag_A;
    wire key_flag_B;
    wire key_flag_C;

    key_XD
    #(
    .CNT_MAX ( 32'd999_999 )//20ms
    )
    key_XD_A
    (
    .clk (clk ),
    .rst_n (rst_n ),
    .key_in (A ),

    .key_flag(key_flag_A)
    );

    key_XD
    #(
    .CNT_MAX ( 32'd999_999 )//20ms
    )
    key_XD_B
    (
    .clk (clk ),
    .rst_n (rst_n ),
    .key_in (B ),

    .key_flag(key_flag_B)
    );

    key_XD
    #(
    .CNT_MAX ( 32'd999_999 )//20ms
    )
    key_XD_C
    (
    .clk (clk ),
    .rst_n (rst_n ),
    .key_in (C ),

    .key_flag(key_flag_C)
    );

    fsm
    #(
    .TIME_3S ( 32'd2 ),
    .TIME_1S ( 32'd1 ),
    .TIME_500MS ( 32'd24_999_999)
    )
    fsm_0
    (
    .clk (clk ) ,
    .rst_n (rst_n) ,
    .A (key_flag_A) ,
    .B (key_flag_B) ,
    .C (key_flag_C) ,

    .led (led)
    );

    seg_595_static seg_595_static_inst(
    .clk (clk ) ,
    .rst_n (rst_n) ,

    .ds (ds ) ,
    .shcp (shcp ) ,
    .stcp (stcp ) ,
    .oe (oe )
    );

    endmodule

    功能模块key_XD和方法一的一样

    功能模块fsm

    module fsm
    #(
    parameter TIME_3S = 32'd2 ,
    parameter TIME_1S = 32'd1 ,
    parameter TIME_500MS = 32'd24_999_999 ,

    parameter s0 = 2'd0,//熄灭
    parameter s1 = 2'd1,//常亮
    parameter s2 = 2'd2,//1s流水灯
    parameter s3 = 2'd3 //1s闪光灯(0.5s亮,0.5s灭)
    )
    (
    input wire clk ,
    input wire rst_n ,
    input wire A ,
    input wire B ,
    input wire C ,

    output reg [3:0] led
    );

    reg [31:0] cnt_3s;
    reg [31:0] cnt_1s;
    reg [31:0] cnt_500ms;
    reg flag_A;
    reg flag_B;
    reg flag_C;

    reg [2:0] state;
    reg state_flag;

    //cnt_500ms
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_500ms <= 32'd0;
    else if(cnt_500ms == TIME_500MS)
    cnt_500ms <= 32'd0;
    else
    cnt_500ms <= cnt_500ms + 1'b1;
    end
    //cnt_1s
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_1s <= 32'd0;
    else if(cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    cnt_1s <= 32'd0;
    else if(cnt_500ms == TIME_500MS)
    cnt_1s <= cnt_1s + 1'b1;
    else
    cnt_1s <= cnt_1s;
    end
    //cnt_3s
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    cnt_3s <= 32'd0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    cnt_3s <= 32'd0;
    else if(cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    cnt_3s <= cnt_3s + 1'b1;
    else
    cnt_3s <= cnt_3s;
    end
    // flag_A:3s内,A按下为高,没按下或者3s到了均为低
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    flag_A <= 1'b0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    flag_A <= 1'b0;
    else if(A)
    flag_A <= 1'b1;
    else
    flag_A <= flag_A;
    end
    //flag_B
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    flag_B <= 1'b0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    flag_B <= 1'b0;
    else if(B)
    flag_B <= 1'b1;
    else
    flag_B <= flag_B;
    end
    //flag_C
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    flag_C <= 1'b0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    flag_C <= 1'b0;
    else if(C)
    flag_C <= 1'b1;
    else
    flag_C <= flag_C;
    end
    //state
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    state <= s0;
    else if(cnt_3s == TIME_3S && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)//3s后判断按键状态
    if(flag_A && flag_B && flag_C)//保持1s的闪光灯效果(0.5s亮,0.5s灭)
    state <= s3;
    else if(flag_A && flag_C)//保持1s的流水灯效果(左右都行)
    state <= s2;
    else if(flag_A && flag_B)//保持被点亮
    state <= s1;
    else if(flag_A || flag_B || flag_C)//保持熄灭
    state <= s0;
    else
    state <= state;
    else
    state <= state;
    end
    //state_flag
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    state_flag <= 1'b0;
    else if(cnt_3s == TIME_3S – 1'b1 && cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)
    state_flag <= 1'b1;
    else
    state_flag <= 1'b0;
    end
    //led
    always@(posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    led <= 4'hf;
    else if(state_flag && flag_A && flag_B && flag_C)//赋初始值
    led <= 4'h0;
    else if(state_flag && flag_A && flag_C)
    led <= 4'b0111;
    else case(state)
    s0 : led <= 4'hf;//熄灭
    s1 : led <= 4'h0;//常亮
    s2 : //1s流水灯
    if(cnt_1s == TIME_1S && cnt_500ms == TIME_500MS)//1s流水
    led <= {led[0],led[3:1]};
    else
    led <= led;
    s3 : //1s闪光灯(0.5s亮,0.5s灭)
    if(cnt_500ms == TIME_500MS)
    led <= ~led;
    else
    led <= led;
    default:led <= 4'hf;
    endcase
    end

    endmodule

    功能模块静态数码管的代码都和方法一的一样

    上板验证

    绑定引脚和方法一绑定的引脚一致,下载代码验证功能即可,这里不再编写仿真代码,进行仿真验证。

    总结

    设计思路:首先需要进行按键消抖,那麽如何在3s内去记录按键A/B/C有没有按下呢?我们需要先设计一个3s的循环计数器,那用什么去记录按键有没有按下呢?假如使用三个计数器,cnt_AB,cnt_AC,cnt_ABC。先分析cnt_AB,A按下时,cnt_AB=1;B按下时,cnt_AB=2;3s到了清零,这样确实可以记录AB顺序按下,然后执行led常量,但按照BA按下就不行了,所以使用计数器记录按键有木有按下是不行的。假如使用序列检测,按键的排列组合太多,此方案不行。假如使用flag信号,当A按下过,让flag_A一直为高电平,3s到了才拉低,B和C一样这样设计。每当clk的上升沿到来时,去判断一次flag_A、flag_B、flag_C三个信号,当前处于什么状态,然后去执行相应的led效果,所以又想到了使用状态机,但是这里需要注意优先级,感觉这个方案可行。然后写代码写到给led赋值时,我发现如果当前led是常亮状态,然后跳转到下一个流水灯状态(使用位拼接的方法),那么在实现流水时,需要让led=4'b0111才行;我寻思着,是否可以在状态跳转时,去更新led的值。如果是一段式的话,我感觉应该可行;二段式和三段式不太行,因为不可以在两个always语句去给同一个信号赋值。这里卡住之后,我就把close_led,open_led,water_led,SGD模块框图画了出来,发现输出都是led[3:0],而顶层也是led[3:0],而这四路信号不可以同时接到输出信号,那如何选取一路输出呢?这时就想到了4选1多路选择器,选通信号就相当于是当前需要执行的状态。这样就不会出现前面在状态跳转时,无法更新led的值。所以方法一是最稳妥的,最直接的方案。

    接下来,我介绍一下方法二的想法吧。前面不是在状态跳转时,无法更新led的值,那我就想去解决这个问题,不就可以了嘛。出现这个问题主要是无法提前判断下一时刻的状态是什么,所以我就让其在cnt_3s计数到最大值时,再去判断led改执行什么功能。这样的话,就是每3s就去判断下一个3s的状态。然后设置一个state_flag信号,当cnt_3s=MAX-1时拉高一个时钟周期;当这个信号有效时,再根据flag_A、flag_B、flag_C信号,我们可以提前一个时钟周期知晓下一个led状态是什么,那么在这个时钟周期内,我们就可以去更新led的值,解决了这个问题,那么方案二就有了。

    赞(0)
    未经允许不得转载:171主机测评 » 基于FPGA的按键点灯的项目设计-考试篇
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址