FPGA实战学习笔记(二):按键控制LED

目录

一、KEY硬件原理

二、设计输入

1.端口设计

2.波形图绘制

3.按键控制led代码实现

三、RTL功能仿真

1.RTL原理图

2.仿真测试文件代码 

3.仿真结果

三、下载验证

总结


使用四个按键开关控制四个LED灯。(正点原子开发指南,记录自己学习过程,题目练习,这里程序是自己编写的与指南中不同,如果看到的小伙伴有什么好的建议可以一同分享交流)


一、KEY硬件原理

        开发板上的4个按键未按下时,输出高电平,按下后,输出低电平。图中的每个按键都 连接了一个10K电阻,起到限流的作用,以防止按键被按下时电源直接接地造成电路短路。

二、设计输入

1.端口设计

        本次实验使用4个按键来控制4颗LED灯,没有按键被按下时,4颗LED保持常灭;如果按键 KEY0被按下, LED灯从低位到高位流水;如果按键KEY1被按下,LED灯从高位到低位流水;如果按键 KEY2被按下,LED灯交替闪烁;KEY3被按下,LED灯常亮。
        模块的输入端口包含3个输入端口系统时钟sys_clk、复位信号sys_rst_n、4bit按键输入信号key[3:0],输出为包含4bit的LED端口led[3:0]。

2.波形图绘制

        如波形图所示,这里仅展示了当按键0按下时Led[3:0]的状态变化,初始状态给led端口赋值为4’b0000;当按键0按下,key[3:0]此时状态为1110,等待0.5s后,即计数器计数25000000次(板载晶振为50MHz,周期为20ns),给 led 端口赋初始值为4’b0001;等待0.5s后,给led端口赋值为4’b0010;等待0.5s,给led端口赋值为 4’b0100;再次等待0.5s后,给led端口赋值为4’b1000;再次等待0.5s后,给led端口赋值为4’b0001,后面依次类推,四个LED即可实现流水的效果。
        其他按键波形图此处没做绘制,详细实现逻辑参考代码,流水灯移位操作原理可看上一篇文章https://blog.csdn.net/qq_45910789/article/details/139297906?spm=1001.2014.3001.5501

3.按键控制led代码实现

根据波形图使用Verilog编写计数器(key_led.v)代码
代码如下:

//key控制led
module key_led(
    input sys_clk,       // 系统时钟输入
    input sys_rst_n,     // 系统复位信号输入
    input [3:0] key,     // 键盘输入
    
    output reg [3:0] led // LED输出
);

parameter MCNT = 25'd24999999; // 计数器最大计数值,对应0.5秒
reg [24:0] cnt;                 // 计数器

// 计数器逻辑,用于生成0.5秒的时间间隔
always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        cnt <= 25'd0;
    else if (cnt == MCNT)
        cnt <= 25'd0;
    else
        cnt <= cnt + 25'd1;
end

// LED控制逻辑,根据键盘输入控制LED状态
//这个思路有个缺陷,判断key状态时需要先判断cnt是否达到最大计数值
always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) // 如果系统复位信号为低电平
        led <= 4'b0000; // 将LED输出置零
    else if (cnt == MCNT) begin // 当计数器计满0.5秒时
        case (key) // 根据键盘输入进行不同的操作
            4'b1110: begin // 如果键盘输入为 "1110"
                if (led == 4'b000) // 如果LED状态为全灭
                    led <= 4'b0001; // 将LED状态置为最低位亮
                else
                    led <= {led[2:0], led[3]}; // 否则循环左移LED状态
            end
            4'b1101: begin // 如果键盘输入为 "1101"
                if (led == 4'b000) // 如果LED状态为全灭
                    led <= 4'b1000; // 将LED状态置为最高位亮
                else
                    led <= {led[0], led[3:1]}; // 否则循环右移LED状态
            end
            4'b1011: begin // 如果键盘输入为 "1011"
                led <= ~led; // 取反LED状态
            end
            4'b0111: begin // 如果键盘输入为 "0111"
                led <= 4'b1111; // 将LED状态全部置为亮
            end
            default: begin // 对于其他键盘输入
                led <= 4'b0000; // 将LED状态置为全灭
            end
        endcase 
    end   
end
//下面这个思路也可以,就是先选择key状态,然后判断计数最大值 
/*
always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) // 如果系统复位信号为低电平
        led <= 4'b0000; // 将LED输出置零
    else begin
            case(key)
            4'b1110:begin
            if(led ==4'b000)
            led <= 4'b0001;
            else if(cnt == MCNT)
            led <= {led[2:0],led[3]};
            end
            4'b1101:begin
            if(led ==4'b000)
            led <= 4'b1000;
            if(cnt == MCNT)
            led <= {led[0],led[3:1]};
            end
            4'b1011:begin 
            if(cnt == MCNT)
            led <= ~led;
            else
            led <= led;
            end
            4'b0111:begin led <= 4'b1111;end
            default:led <= 4'b0000;
        endcase
    end   
end
*/
endmodule

三、RTL功能仿真

1.RTL原理图

RTL视图如下:

2.仿真测试文件代码 

代码如下:

`timescale 1ns / 1ns


module tb_key_led();
reg     sys_clk  ;
reg     sys_rst_n;
reg     [3:0]key ;
                 
wire    [3:0]led      ;   

initial begin
    sys_clk = 1'b1;
    sys_rst_n = 1'b0;
    key <= 4'b1111;
    #201
    sys_rst_n = 1'b1;
    #24900
    key <= 4'b1110;
    #24900
    key <= 4'b1111;
    #24900
    key <= 4'b1101;
    #24900
    key <= 4'b1111;
    #24900
    key <= 4'b1011;
    #24900
    key <= 4'b1111;
    #24900
    key <= 4'b0111;
    #24900
    key <= 4'b1111;  
end
always #10 sys_clk = ~sys_clk;
    
    
key_led 
#(
    .MCNT(24)
)
key_led_inst(
.sys_clk  (sys_clk  ),
.sys_rst_n(sys_rst_n),
.key      (key      ),
           
.led      (led      )

);
endmodule

3.仿真结果

        仿真整体波形图如上图,仿真时,依次按下按键0后释放按键,按下按键1后释放按键,按下按键2后释放按键,按下按键3后释放按键。

        

        按键0按下的仿真波形与之前所绘制的按下按键0的波形图一致,这里为了减少仿真耗时在仿真文件里将间隔时间设置为500ns,计数器最大次数25。

三、下载验证

        在经过分析综合、管脚分配、时序约束后,生成bit流文件进行上板验证实现结果如下所示:

key_led

总结

        注意按键按下的状态选择程序编写,按键0和按键1的流水灯由于使用的移位操作进行,所以在判断按键按下后需要先把led初始状态设置为0001(向左流水)和1000(向右流水),还有闪烁操作前也要加上对计数器的判断。

  • 33
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值