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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值