0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于FPGA按键控制LED-ISE操作工具

电子发烧友论坛 来源:FPGA技术江湖 2023-08-16 09:28 次阅读

本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子信息通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。

系统性的掌握技术开发以及相关要求,对个人就业以及职业发展都有着潜在的帮助,希望对大家有所帮助。后续会陆续更新 Xilinx 的 Vivado、ISE 及相关操作软件的开发的相关内容,学习FPGA设计方法及设计思想的同时,实操结合各类操作软件,会让你在技术学习道路上无比的顺畅,告别技术学习小BUG卡破脑壳,告别目前忽悠性的培训诱导,真正的去学习去实战应用。话不多说,上货。

按键控制LED-ISE操作工具

利用按键控制LED的要求为:按一下按键,改变一下LED的状态。按键按一次,LED由熄灭变为点亮,按键再按一次,LED由点亮变为熄灭。

硬件介绍

开发板上面有四个按键,当按键按下时,将对应的网络置成低电平;当按键释放时,将对应的网络置成高电平。

开发板上面有四个LED发光二极管,FPGA输出高电平时,LED点亮;FPGA输出低电平时,LED熄灭。

设计原理

通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。

按键抖动会引起一次按键被误读多次。为确保CPU对键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。

抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。这是一个很重要的时间参数,在很多场合都要用到。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。

我们可以在按键和主控设备之间加入消抖电路(消抖芯片电容等),此种方法会增大PCB面积和花费一定的物料费用。大多数的板子直接将按键和主控设备相连接,将带有抖动的波形输入到主控设备内部,由内部进行消抖处理。

单片机一般采用延迟重采样的方式进行消抖。当检测信号为低时,延迟一段时间(一般为20ms),再次检测信号是否为低,如果为低,则证明按键按下,否则认为按键没有按下,继续下一次检查。

在FPGA设计时,笔者推荐另外一种方式:持续采样。当检测到信号持续为低10ms,认为按键按下;当检测到信号持续为高10ms,认为按键释放。

在设计时,需要考虑到外部的按键信号为异步信号,需要进行同步处理。具体请参考附录2 FPGA中的同步信号、异步信号和亚稳态。

每次按键按下的时间的长短不一,经过消抖后,低电平的持续长度长短也不一样。此长度远远大于一个时钟周期的长度。要求每次按下只能够切换一次LED的状态,所以不能够直接用此电平当做输出翻转的使能。

经过消抖的波形,每次按下只有一个下降沿(按键按下时)、只有一个上升沿(按键释放时)。所以通过检测下降沿(上升沿)的变化,产生一个新的信号------脉冲(一个时钟周期的脉冲),利用此脉冲作为翻转的使能即可。利用检测到下降沿的脉冲翻转时,LED的状态会在按下时就会改变;利用检测到上升沿的脉冲翻转时,LED的状态会在释放时发生改变。本设计中采用检测到下降沿的脉冲进行翻转。

设计架构和信号说明

本设计模块命名为key_led。

a1f9a89a-3bc8-11ee-9e74-dac502259ad0.png

在设计中,共分为三个模块。

key_filter(按键消抖模块):将外部输入的带有抖动的波形进行消抖。

edge_check(边沿检测模块):将消抖后的波形进行下降沿检测,并产生对应的脉冲。

led_ctrl(led控制模块):利用脉冲,翻转led的输出状态。

a20f2512-3bc8-11ee-9e74-dac502259ad0.png

key_filter设计实现

本设计采用状态机实现,状态机的具体原理请参看相关文章。

对key_n信号为异步信号,需要进行同步两拍,命名为key_n_r和key_n_rr。状态机的判断信号为key_n_rr信号。

本设计共分为四个状态,KEY_OFF(按键释放状态),SHAKE_ON(按键按下时抖动判断状态),KEY_ON(按键按下状态),SHAKE_OFF(按键释放时抖动判断状态)。

按键没有按下时,一直KEY_OFF状态,当按键信号变为低电平时,就转入SHAKE_ON状态,检测低电平的持续时间。如果持续时间没有达到T_10ms就变为高电平,则清零计数器并返回KEY_OFF状态;如果持续时间没有达到T_10ms并且也一直为低电平,则继续在SHAKE_ON状态计数;如果持续时间达到T_10ms并且为低电平,则清零计数器并进入KEY_ON状态。在KEY_ON状态,外部输入为低电平时,则继续在KEY_ON状态;如果外部输出为高电平,则转入SHAKE_OFF状态。在SHAKE_OFF状态,如果持续时间没有到达T_10ms就变为低电平,则清零计数器并返回KEY_ON状态;如果持续时间没有达到T_10ms并且一直为高电平,则继续在SHAKE_OFF状态计数;如果持续时间达到T_10ms并且一直为高电平,则清零计数器并转入KEY_OFF状态。

在KEY_OFF和SHAKE_ON状态,认为按键没有按下;在KEY_ON和SHAKE_OFF状态,认为按键为按下;

状态转移图如下:

a2291e7c-3bc8-11ee-9e74-dac502259ad0.png

a24e2938-3bc8-11ee-9e74-dac502259ad0.png

设计代码为:

module key_filter (
 
 input   wire   clk,
 input   wire   rst_n,
 
 input   wire   key_n,
 
 output  reg   okey_n
);


 parameter T_10ms  = 500_000;


 localparam  KEY_OFF = 4'b0001;
 localparam  SHAKE_ON = 4'b0010;
 localparam  KEY_ON = 4'b0100;
 localparam  SHAKE_OFF = 4'b1000;
 
 reg     [3:0]   c_state;
 reg     [3:0]   n_state;
 reg          key_n_r;
 reg          key_n_rr;
 reg     [18:0]  cnt;
 
 always @ (posedge clk) key_n_r <= key_n;
  always @ (posedge clk) key_n_rr <= key_n_r;
  
  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      c_state <= KEY_OFF;
    else
      c_state <= n_state;
  end
  
  always @ * begin
    case (c_state)
      KEY_OFF    :    begin
        if (key_n_rr == 1'b1)
          n_state = KEY_OFF;
        else
          n_state = SHAKE_ON;
      end  
    
      SHAKE_ON    :    begin
        if (key_n_rr == 1'b1)
          n_state = KEY_OFF;
        else
          if (cnt < T_10ms - 1'b1)
            n_state = SHAKE_ON;
          else
            n_state = KEY_ON;
      end
    
      KEY_ON    :    begin
        if (key_n_rr == 1'b0)
          n_state = KEY_ON;
        else
          n_state = SHAKE_OFF;
      end
      
      SHAKE_OFF  :    begin
        if (key_n_rr == 1'b0)
          n_state = KEY_ON;
        else
          if (cnt < T_10ms - 1'b1)
            n_state = SHAKE_OFF;
          else
            n_state = KEY_OFF;
      end
      
      default  :    n_state = KEY_OFF;
    endcase
  end
  
  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      cnt <= 19'd0;
    else
      case (c_state)
        KEY_OFF    :    begin
          cnt <= 19'd0;
        end
      
        SHAKE_ON  :    begin
          if (key_n_rr == 1'b0 && cnt < T_10ms - 1'b1)
        cnt <= cnt + 1'b1;
      else
        cnt <= 19'd0;
        end
        
        KEY_ON    :    begin
          cnt <= 19'd0;
        end
        
        SHAKE_OFF  :    begin
          if (key_n_rr == 1'b1 && cnt < T_10ms - 1'b1)
        cnt <= cnt + 1'b1;
      else
        cnt <= 19'd0;
        end
        
        default    :    cnt <= 19'd0;
      endcase
  end  
  
  always @ (posedge clk, negedge rst_n) begin
    if (rst_n == 1'b0)
      okey_n <= 1'b1;
    else
      if (c_state == KEY_ON || c_state == SHAKE_OFF)
        okey_n <= 1'b0;
      else
        okey_n <= 1'b1;
  end


endmodule

(左右移动查看全部内容)

localparam可以定义参数,与parameter的区别在于,parameter定义的参数可以在例化时进行参数修改,而localparam定义的参数在例化时则不能够修改。定义状态机状态时,一般采用localparam的定义方式。在不希望别人修改参数时,也可以定义为localparam。

edge_check设计实现

在一个波形中,如果当前时刻为低电平,上一个时刻为高电平,则认为波形中有一个下降沿;如果当前时刻为高电平,上一个时刻为低电平,则认为波形中有一个上升沿。

在数字电路设计时,可以采用寄存器来存储上一个时刻的值。

a269ca12-3bc8-11ee-9e74-dac502259ad0.png

在寄存器电路中,Q的值,永远是上一个CLK的有效边沿所采样的D值。因此Q为上一时刻值,而D为当前时刻的值。

设计代码为:

module edge_check (


 input   wire      clk,  // 50MHz 
 input   wire      wave, // wave in
 
 output  wire      flag_pos, // flag - posedge
 output  wire      flag_neg // flag - negedge
);


 reg            wave_r;
 
 always @ (posedge clk) wave_r <= wave;
  
//  assign flag_pos = (wave == 1'b1 && wave_r == 1'b0) ? 1'b1 : 1'b0;
  assign flag_pos = wave & (~wave_r);
  
//  assign flag_neg = (wave == 1'b0 && wave_r == 1'b1) ? 1'b1 : 1'b0;
  assign flag_neg = (~wave) & wave_r;


endmodule

(左右移动查看全部内容)

在设计中,注释掉的两行代码和其下方的一行代码的功能是相同的。例:对于上升沿脉冲来说,现在为1,过去为0即为上升沿。由于寄存器每个时钟周期都刷新,满足这个要求的只会存在一个时钟周期,所以flag_pos为一个时钟周期的脉冲。

led_ctrl设计实现

本模块中,利用脉冲进行led状态的翻转即可。

设计代码为:

module led_ctrl (


 input   wire     clk,
 input   wire     rst_n,
 
 input   wire     flag,
 
 output  reg      led
);


 always @ (posedge clk, negedge rst_n) begin
  if (rst_n == 1'b0)
   led <= 1'b0;
    else
      if (flag == 1'b1)
        led <= ~led;
      else  
        led <= led;
  end


endmodule

(左右移动查看全部内容)

key_led设计实现

本模块只是负责将上述的三个模块按照架构图的方式进行连接,形成最终的设计。

设计代码为:

module key_led (


 input  wire      clk,
 input  wire      rst_n,
 input  wire      key_n,
 
 output wire      led
);


 wire          okey_n;
   wire                      flag;


key_filter key_filter_inst(
 
.clk  (clk),
.rst_n  (rst_n),
  
.key_n  (key_n),
  
.okey_n  (okey_n)
);
 
 edge_check edge_check_inst(


  .clk     (clk),  // 50MHz 
  .wave     (okey_n), // wave in
  
  .flag_pos   (), // flag - posedge
  .flag_neg   (flag) // flag - negedge
 );


 led_ctrl led_ctrl_inst(


  .clk     (clk),
  .rst_n    (rst_n),
  
  .flag     (flag),
  
  .led     (led)
 ); 
 
endmodule

(左右移动查看全部内容)

在设计中,采用了按键按下时的脉冲(检测到下降沿的脉冲),按键按下时led的状态即可进行翻转。

a27dcc88-3bc8-11ee-9e74-dac502259ad0.png

功能仿真

在仿真时,将按键消抖中的T_10ms的参数修改为20,即持续时间不超过400ns都不认为是有效按下或者抬起。

仿真代码如下:

将okey_n、flag信号添加出来。

`timescale 1ns/1ps


module key_led_tb;


 reg       clk;
 reg       rst_n;
 reg       key_n;
 
 wire      led;
 
 key_led key_led_inst(


   .clk    (clk),
   .rst_n   (rst_n),
   .key_n   (key_n),
   
   .led    (led)
  );


 initial clk = 1'b0;
 always # 10 clk = ~clk;
 
 initial begin
  rst_n = 1'b0;
  key_n = 1'b1;
  # 201
  rst_n = 1'b1;
  # 200
//-------------- on shake-------------  
  @ (posedge clk);
  # 2;
  key_n = 1'b0;
  # 320
  @ (posedge clk);
  # 2;
  key_n = 1'b1;
  # 159
  @ (posedge clk);
  # 2;
  key_n = 1'b0;
  # 320
  @ (posedge clk);
  # 2;
  key_n = 1'b1;
  # 159
//--------------------------------------
//---------key on ---------------------  
  @ (posedge clk);
  # 2;
  key_n = 1'b0;
  # 5000
//------------------------------------  
//---------off shake ----------------
  @ (posedge clk);
  # 2;
  key_n = 1'b0;
  # 320
  @ (posedge clk);
  # 2;
  key_n = 1'b1;
  # 159
  @ (posedge clk);
  # 2;
  key_n = 1'b0;
  # 320
//-------------------------------------
//-----------key off----------------  
  @ (posedge clk);
  # 2;
  key_n = 1'b1;
  # 10000
  $stop;
 end


endmodule

(左右移动查看全部内容)

a2997410-3bc8-11ee-9e74-dac502259ad0.png

通过RTL仿真图,可以清晰的看到okey_n信号将key_n的抖动滤除掉;flag信号为okey_n信号的下降沿时所产生的脉冲;led在flag信号为高时,反正翻转。

分配管脚、下板测试之前,应该将按键消抖里面的T_10ms参数重新改为500_000,否则下板后可能会达不到消抖的效果。

下板观察现象:

a2adc186-3bc8-11ee-9e74-dac502259ad0.png

下板成功后,可以修改在设计中使用上升沿的脉冲,得到的现象应该是按键释放时,LED的状态发生反转。

切记:每次修改代码,一定要进行重新编译,否则更改将不会生效。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1602

    文章

    21320

    浏览量

    593199
  • led
    led
    +关注

    关注

    237

    文章

    22449

    浏览量

    645878
  • Xilinx
    +关注

    关注

    70

    文章

    2121

    浏览量

    119373
  • 发光二极管
    +关注

    关注

    13

    文章

    1138

    浏览量

    65680
  • 开发板
    +关注

    关注

    25

    文章

    4429

    浏览量

    93995

原文标题:【教程分享】FPGA零基础学习:按键控制LED-ISE操作工具

文章出处:【微信号:gh_9b9470648b3c,微信公众号:电子发烧友论坛】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    STM32按键控制LED的亮灭

    使用一个按键控制LED的亮灭,按键按下时LED亮起,按键松开时LED熄灭。通过
    的头像 发表于 12-11 14:19 2024次阅读
    STM32<b class='flag-5'>按键控制</b><b class='flag-5'>LED</b>的亮灭

    FPGA导航按键控制LED的方法

    FPGA按键控制LED软件芯片功能代码代码解释软件软件使用的是ISE14.6(因为穷没买7系列,劝大家买个7系列的板子,这个软件装着还挺费事,不如Vivado好用,且6和7软件不通用)
    发表于 01-18 10:31

    LED流水灯设计-ISE操作工具

    灯设计-ISE操作工具在软件设计时,第一个例程总是“hello world!”,那么学习硬件时,也会有硬件的“hello world”------流水灯。在FPGA开发板上有四个LED
    发表于 03-31 18:44

    按键控制LED-ISE操作工具

    LED-ISE操作工具利用按键控制LED的要求为:按一下按键,改变一下LED的状态。
    发表于 04-03 19:36

    数码管驱动设计-ISE操作工具

    设计-ISE操作工具Xilinx ISE 系列实操所使用的开发设备为叁芯智能科技研发的SANXIN B02 FPGA开发板,如果有想入手的大侠,可登陆叁芯智能科技官方淘宝店咨询以及购买
    发表于 04-04 21:23

    音乐蜂鸣器设计-ISE操作工具

    设计-ISE操作工具Xilinx ISE 系列实操所使用的开发设备为叁芯智能科技研发的SANXIN B02 FPGA开发板,如果有想入手的大侠,可登陆叁芯智能科技官方淘宝店咨询以及购买
    发表于 04-04 21:46

    IP CORE 之 PLL- ISE 操作工具

    不多说,上货。IP CORE 之 PLL- ISE 操作工具本篇实现基于叁芯智能科技的SANXIN -B02 FPGA开发板,如有入手开发板,可以登录官方淘宝店购买,还有配套的学习视频。Xilinx
    发表于 04-06 16:04

    IP CORE 之 ROM 设计- ISE 操作工具

    不多说,上货。IP CORE 之 ROM 设计- ISE 操作工具本篇实现基于叁芯智能科技的SANXIN -B02 FPGA开发板,如有入手开发板,可以登录官方淘宝店购买,还有配套的学习视频
    发表于 04-07 20:09

    IP CORE 之 RAM 设计- ISE 操作工具

    不多说,上货。IP CORE 之 RAM 设计- ISE 操作工具本篇实现基于叁芯智能科技的SANXIN -B02 FPGA开发板,如有入手开发板,可以登录官方淘宝店购买,还有配套的学习视频
    发表于 04-10 16:43

    IP CORE 之 FIFO 设计- ISE 操作工具

    不多说,上货。IP CORE 之 FIFO 设计- ISE 操作工具本篇实现基于叁芯智能科技的SANXIN -B02 FPGA开发板,如有入手开发板,可以登录官方淘宝店购买,还有配套的学习视频。FIFO
    发表于 04-11 20:50

    标记的用法,用一个按键控制1个LED灯的亮灭,按键去抖

    标记的用法,用一个按键控制1个LED灯的亮灭,按键去抖 这一课,我们学习怎么用一个按键K1控制1个LE
    发表于 08-09 10:39 2.3w次阅读
    标记的用法,用一个<b class='flag-5'>按键控制</b>1个<b class='flag-5'>LED</b>灯的亮灭,<b class='flag-5'>按键</b>去抖

    利用FPGA DIY开发板实现按键控制LED的显示

    asean的 FPGA DIY 按键控制LED显示的视频
    的头像 发表于 06-20 14:06 6771次阅读
    利用<b class='flag-5'>FPGA</b> DIY开发板实现<b class='flag-5'>按键控制</b><b class='flag-5'>LED</b>的显示

    按键控制LED灯排

    基于51单片机仿真实现按键控制LED灯排的亮灭,压缩包中有程序和电路图。
    发表于 07-04 15:25 2次下载

    基于stm32的按键控制led亮灭

    基于stm32的按键控制led亮灭资料文件分享
    发表于 09-21 15:50 32次下载

    基于单片机按键控制多个LED

    两个按键控制8位LED灯。
    的头像 发表于 08-16 09:35 1216次阅读