FPGA &&双按键控制&&LED呼吸灯实现

FPGA &&双按键控制&&LED呼吸灯实现


​ 首先本次设计要实现的目标: 一个按键控制led闪烁频率的增加,另一个按键控制led闪烁频率的减小

[工程链接:](https://pan.baidu.com/s/137NTleHZP8ss9jTRnAhMhQ
提取码:qb68)

1.按键脉冲设计

​ 众所周知,按键一般采取消抖程序作为按键开关控制使用,这一次我采用了,脉冲信号来作为开关信号使用,本次采取**寄存器打拍实现

1.1按键脉冲信号代码

/*
 * @Description: 按键脉冲信号产生
 * @Version: 1.0
 * @Author: Fangyeye
 * @Date: 2022-12-19 20:16:02
 * @LastEditors: Fangyeye
 * @LastEditTime: 2022-12-19 20:46:01
 */
module key_pulse#(
        parameter  integer  KEY_NUM = 2     //按键的数量
)
(
    input       wire                                clk             ,       //系统时钟频率50MHZ
    input       wire                                rst_n           ,
    input       wire  [KEY_NUM-1 :0]                key_in          ,       //按键输入信号
    output      wire  [KEY_NUM-1 :0]                key_pulse          
);

reg     key_r , key_rr  ;

// 寄存器打两拍的作用:1.同步时钟域 2.捕获按键按下的下降沿
always @(posedge clk , negedge rst_n) begin
    if(!rst_n)begin
        key_r <=  'b0;
        key_rr <= 'b0;
    end
    else begin
       key_r <= key_in;
       key_rr <= key_r; 
    end
end

assign key_pulse = (~key_r) & key_rr ;
    
endmodule

1.2.按键脉冲Testbench代码

// 按键脉冲测试tb
`timescale 1ns/1ns 
module tb_key_pulse();

reg clk;
reg rst_n;
wire pulse;
reg key;

key_pulse  u0(
    .clk(clk ),
    .rst_n(rst_n),
    .key_in(key),
    .key_pulse(pulse)
);

always #10 clk = ~ clk;

initial begin
    clk = 0;
    key = 0;
    rst_n = 1;
    #5 rst_n = 0;
    #5 rst_n = 1;
    #105 key = 0;
    #50 key = 1;
    #200 key = 0;
    #100 key = 1;
    #2000 $stop;
end

endmodule

1.3.仿真波形:

FPGA &&双按键控制&&LED呼吸灯实现

易知:当按键按下时,key为低电平时立马产生一个脉冲信号,实现开关作用

2. pwm脉宽调制

1.1PWM信号简介:

在这里插入图片描述

  • 什么是PWM:PWM简称脉冲宽度调制,即在一个周期内存在不同极性的电平状态。

  • PWM频率:是指一秒钟内从高电平时间在到低电平时间,再从低电平跳到高电平的瞬间次数,也就是一秒钟内有多少个PWM的周期。f = T / 1(HZ)。 基本单位为HZ(赫兹)

  • PWM周期:是指一秒钟内从高电平时间在到低电平时间,T = f / 1(s)。

  • PWM占空比:是指一个周期内高电平时间和总时间的比值。

1.2时间比例换算:

​ 1s(秒) =1000毫秒=1000 000 (微秒) =1000 000 000 (纳秒)

​ 上面图表表示:

​ T(周期) : 10ms/1s = 0.01s

​ f(频率) : 0.01/1 = 100HZ

​ 占空比 ;4/(4+6) *100% =40

1.3.设计一个周期10KHZ,占空比40%的信号:

按照上面的波形我们来设计个周期10KHZ,占空比40%的方波信号吧

1.3.1verilog代码

/*
 * @Description: 输出可调的PWM信号模块
    @function :    1.FPGA的可调PWM信号模块 
                    2.可调PWM信号的周期/占空比
                    3.默认占空比设置:DUTY
                    4.输出 10KHZ 40%占空比信号
 * @Version: 1.0
 * @Author: Fangyeye
 * @Date: 2022-12-19 21:39:47
 * @LastEditors: Fangyeye
 * @LastEditTime: 2022-12-20 13:35:50
 */
module led_gard#(
    parameter   integer         CLK_FREQ    =   50_000_000  ,   //输入的时钟频率 
    parameter   integer         PERIOD      =   1_000       ,   //PWM信号周期   Unit:HZ  
    parameter   integer         DUTY        =   40          
)
(
//系统接口
    input       wire                            clk     ,   //输入时钟50MHZ   
    input       wire                            rst_n   ,   //系统复位,低电平复位
//输出信号 
    output      reg                             out         //输出信号
);

//reg
reg     [31:0]               cnt    ;       //计数器 --用于时钟分频 到 1KHZ

localparam      integer     CNT_PERIOD      =  ( CLK_FREQ / PERIOD )  -1                ;   //周期计数值
localparam      integer     CNT_DUTY        =   CNT_PERIOD * (DUTY *1.0 / 100) - 1      ;   //占空比计数值 --高电平计数值

//计数器计数 
always @(posedge clk , negedge rst_n) begin
    if(!rst_n)begin
        cnt <= 32'b0;
    end
    else if(cnt == CNT_PERIOD ) begin
        cnt <= 32'b0;
    end
    else begin
        cnt <= cnt + 1'b1;
    end
end

// 根据占空比 动态调节进行电平翻转
always @(posedge clk  , negedge rst_n) begin
    if(!rst_n)begin
            out <= 1'b1;    //默认输出高电平
    end
    else if(cnt >= CNT_PERIOD) begin
            out <= 1'b1;
    end
    else begin
       if(cnt >=  CNT_DUTY)begin //开始低电平计数
            out <= 1'b0;
       end 
    end
end

endmodule



1.3.2Testbench代码

/测试实例
`timescale 1ns/1ns

module tb_led_gard();

//reg
    reg         clk     ;
    reg         rst_n   ;


//wire 
    wire         out     ;

    parameter   integer         CLK_FREQ    =   50_000_000  ;   //输入的时钟频率 
    parameter   integer         PERIOD      =   1_000       ;   //PWM信号周期   Unit:HZ
    parameter   integer         DUTY        =   40          ;    //PWM的占空比  

    //实例化输出可调的PWM信号模块
    led_gard #(
        .CLK_FREQ(CLK_FREQ) ,
        .PERIOD(PERIOD)     ,
        .DUTY(DUTY)   
    )
    led_gard_init(
        .clk(clk),
        .rst_n(rst_n),
        .out(out)
    );

    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        #20 //系统开始工作
        rst_n = 1'b1;

    end

    always #10 clk = ~clk;

endmodule

1.3.3仿真波形:

在这里插入图片描述

易知 输出信号周期10KHZ,占空比40%,与预期设计相符合

3.双按键控制 LED灯亮度的实现

​ 接下来让我们修改代码来达到预期的设计,实现本次设计吧!

1.3.1双按键控制 LED灯verilog代码

/*
 * @Description: 一个按键控制led亮度的增加,另一个按键控制led亮度的减小
 * @Version: 1.0
 * @Author: Fangyeye
 * @Date: 2022-12-20 11:59:10
 * @LastEditors: Fangyeye
 * @LastEditTime: 2022-12-20 14:13:12
 */
 module fpga_top#(
    parameter   integer         CLK_FREQ    =   50_000_000  ,   //输入的时钟频率 
    parameter   integer         PERIOD      =   1_000       ,   //PWM信号周期   Unit:HZ  
    parameter   integer         DUTY        =   40              //默认40%占空比
)
(
//系统接口
    input       wire                            clk     ,   //输入时钟50MHZ   
    input       wire                            rst_n   ,   //系统复位,低电平复位
//用户接口
    input       wire                            key_up  ,   //亮度增加按键 
    input       wire                            key_down,   //亮度减小按键
//输出信号 
    output      reg                             out         //输出信号
 );

//reg
reg     [31:0]              cnt             ;       //计数器 --用于将时钟分频 到 1KHZ
reg     [9:0]               pulse           ;       //电平翻转计数器

//wire
wire                        key_up_pluse        ;     //亮度增加按键按下脉冲信号
wire                        key_down_pluse        ;   //亮度减小按键按下脉冲信号

localparam      integer     CNT_PERIOD      =  ( CLK_FREQ / PERIOD )  -1                ;   //周期计数值
localparam      integer     CNT_DUTY        =   CNT_PERIOD * (DUTY *1.0 / 100) - 1      ;   //占空比计数值 --高电平计数值


//计数器计数 
always @(posedge clk , negedge rst_n) begin
    if(!rst_n)begin
        cnt <= 32'b0;
    end
    else if(cnt == CNT_PERIOD ) begin
        cnt <= 32'b0;
    end
    else begin
        cnt <= cnt + 1'b1;
    end
end

// 根据占空比 动态调节进行电平翻转
always @(posedge clk  , negedge rst_n) begin
    if(!rst_n)begin
            out <= 1'b1;    //默认输出高电平
    end
    else if(cnt >= CNT_PERIOD) begin
            out <= 1'b1;
    end
    else begin
       if(cnt >=  pulse )begin //开始低电平计数
            out <= 1'b0;
       end 
    end
end

// 2个按键实例化
    key_pulse #(
        .KEY_NUM(1)
    )
    key_down_pulse_init (
        .clk(clk),
        .rst_n(rst_n),
        .key_in(key_down),
        .key_pulse(key_down_pluse)
    );

     key_pulse #(
        .KEY_NUM(1)
    )
    key_up_pulse_init (
        .clk(clk),
        .rst_n(rst_n),
        .key_in(key_up),
        .key_pulse(key_up_pluse)
    );

// 按键功能实现 
always @(posedge clk , negedge rst_n ) begin
    if(!rst_n)begin
        pulse <= CNT_DUTY;
    end
    else begin
        if(key_down_pluse)begin
           if(cnt <= CNT_PERIOD)begin
                pulse <= pulse + 4'd10;
           end 
        end
        else if (key_up_pluse) begin
           if(cnt >= 'd10)begin
                pulse <= pulse - 4'd10;
           end 
        end
    end
end


 endmodule
### 1.3.2上板验证

​ 两个按键触发方式为下降沿触发

在这里插入图片描述

由硬件原理图确定 (本人硬件是按下IO读取低电平)

在这里插入图片描述

FPGA读到数据
在这里插入图片描述

亮度增加按键按下:+10 ,亮度减小按键按下:-10
在这里插入图片描述

在这里插入图片描述

发现实物上板子LED亮度也有相应的变化,说明设计正确✔

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验目的: 通过 FPGA 实现按键控制 LED 的亮灭,加深对 FPGA 的理解和应用。 实验器材: - FPGA 开发板(例如 DE10-Lite) - USB 线 - 按键模块 - LED 模块 实验步骤: 1. 搭建硬件电路 将按键模块和 LED 模块插入 FPGA 开发板的相应引脚上,并将 FPGA 开发板与电脑连接。 按键模块连接方式: - K1 和 K2 分别连接到 FPGA 引脚的 PIN_23 和 PIN_25 上。 - GND 连接到 FPGA 引脚的 PIN_19 上。 LED 模块连接方式: - VCC 连接到 FPGA 引脚的 PIN_3 上。 - GND 连接到 FPGA 引脚的 PIN_1 上。 - LED1 和 LED2 分别连接到 FPGA 引脚的 PIN_10 和 PIN_12 上。 2. 新建 Quartus 工程 打开 Quartus 软件,选择 File -> New Project Wizard,新建一个工程。 3. 添加 Verilog 文件 在工程目录下新建一个 Verilog 文件,将以下代码复制进去: ```verilog module key_led( input clk, input k1, input k2, output led1, output led2 ); reg [1:0] state; always @(posedge clk) begin case(state) 2'b00: begin led1 <= 1'b0; led2 <= 1'b0; if(k1) state <= 2'b01; if(k2) state <= 2'b10; end 2'b01: begin led1 <= 1'b1; led2 <= 1'b0; if(!k1) state <= 2'b00; end 2'b10: begin led1 <= 1'b0; led2 <= 1'b1; if(!k2) state <= 2'b00; end default: state <= 2'b00; endcase end endmodule ``` 这段 Verilog 代码实现按键控制 LED 的功能,在上升沿时检测按键的状态,根据按键的状态控制 LED 的亮灭。 4. 设计约束文件 在工程目录下新建一个 SDC 文件,将以下代码复制进去: ```tcl create_clock -name clk -period 10.0 -waveform {0 5.0} [get_ports clk] set_input_delay -clock clk -max 2.0 [get_ports k1] set_input_delay -clock clk -max 2.0 [get_ports k2] set_output_delay -clock clk -max 2.0 [get_ports led1] set_output_delay -clock clk -max 2.0 [get_ports led2] ``` 这段 SDC 代码定义了时钟和输入输出的时序约束。 5. 编译工程 在 Quartus 软件中,选择 Processing -> Start Compilation,编译工程。 6. 下载到 FPGA 开发板 编译成功后,在 Quartus 软件中选择 Tools -> Programmer,将编译好的文件下载到 FPGA 开发板。 7. 运行实验 将 FPGA 开发板接通电源,按下 K1 按键LED1 亮起;按下 K2 按键LED2 亮起。松开按键后,LED 熄灭。 实验效果: 通过按键控制 LED 的亮灭,实现了简单的数字逻辑电路的设计和实现。 实验总结: 本实验通过 FPGA 实现按键控制 LED 的亮灭,加深了对 FPGA 的理解和应用。在设计数字逻辑电路时,需要注意时序约束的设置,确保电路能够正常工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值