首页 > 其他分享 >基于EP4CE6F17C8的FPGA键控灯实例

基于EP4CE6F17C8的FPGA键控灯实例

时间:2024-04-05 16:44:20浏览次数:20  
标签:LED FPGA 引脚 EP4CE6F17C8 key 按键 键控 时钟

一、电路模块

1、LED

开发板板载了4个用户LED发光二极管,其原理图如下所示,当 FPGA的引脚输出为逻辑 0时,LED会熄灭。输出为逻辑1时,LED被点亮。

其实物图如下所示。

LED的引脚分配见下表。

2、时钟晶振

开发板板载了一个50MHz的有源晶振,为系统提供时钟。

其实物图如下所示。

时钟输出引脚分配见下表。

3、按键

开发板板载了4个独立按键,其中有3个用户按键(KEY1~KEY3),1个功能按键(RESET)。按键按下为低电平(0),释放为高电平(1),4个按键的原理图如下图所示。

其实物图如下所示。

按键的引脚分配见下表。

 

二、实验代码

本例实现通过3个按键控制3个LED的亮灭,按键按下对应的LED点亮,再次按下LED熄灭,如此循环。模块名称为key_led,文件名称为key_led.v,代码如下。

module key_led(
            input               clk,                  //板载50HMz系统时钟
            input               rst,                  //复位按键
            input [2:0]         key_h,                //三个用户按键
            output reg[2:0]     led                   //三个LED
            );

//按键抖动判断逻辑
wire    key = key_h[0] & key_h[1] & key_h[2];         //定义三个按键相与

reg[1:0] keyr;                                        //定义按键存储变量
always@(posedge clk or negedge rst)                   //敏感信号为时钟上沿或复位下沿
begin
    if(!rst)                                          //低电平复位
        keyr <= 2'b11;                                //复位时按键值为全1
    else
      keyr <= {keyr[0], key};                         //并位,相当于每个时钟之后用key值向左填充keyr
end

wire    key_neg = ~keyr[0] & keyr[1];                 //按键按下之后判定有下降沿
wire    key_pos = keyr[0] & ~keyr[1];                 //按键释放之后判定有上升沿

//定时计数20ms时间,用于对按键的消抖判断
reg[19:0]    cnt;
always@(posedge clk)
begin
     if(!rst)                                         //低电平复位时计数值清零
            cnt <= 20'd0;
    if(key_pos || key_neg)                            //如果有上升沿或下降沿发生,计数值清零
            cnt <= 20'd0;
    else if(cnt < 20'd999_999)                        //如果未计到20ms,则继续加1计数
            cnt <= cnt + 20'd1;
    else
            cnt <= 20'd0;                             //到20ms,计数值清零        
end

//定时采集按键值
reg[2:0]    key_halue[1:0];                           //定义两个健值存储变量
always@(posedge clk or negedge rst)                   //敏感信号为时钟上沿或复位下沿
begin
    begin
         if(!rst)                                     //低电平复位时健值变量全部置1
        begin
            key_halue[0] <= 3'b111;
            key_halue[1] <= 3'b111;
        end
        else
        begin
        key_halue[1] <= key_halue[0];                 //两次键值相差一个时钟节拍,用于在不相同时产生一个变化脉冲
        if(cnt == 20'd999_999)
                key_halue[0] <= key_h;                //到20ms后,获取外部按键值
        end
    end
end
/*key_halue[1] <= key_halue[0]一个时钟执行一次,当到20ms时,执行了key_halue[0] <= key_h,此时
key_halue[1]与key_halue[0]的值是不同的,直到下一个时钟到来时,才相同。因此,通过下面语句会产生
出一个时钟周期的窄脉冲,依靠这个窄脉冲,就可判断是哪个按键被按下了。由于些窄脉冲的宽度只有一个时钟
周期,所以本次时钟过后,又恢复低电平状态,因此不会被反复触发。且在释放按键时,不会产生此窄脉冲。 */
wire[2:0]    key_press = key_halue[1] & ~key_halue[0];    //按键值按下时产生一个变化脉冲
//wire[3:0]    key_press = ~key_halue[1] & key_halue[0];  //按键值释放时产生一个变化脉冲

//LED控制
always@(posedge clk or negedge rst)                   //敏感信号为时钟上沿或复位下沿
begin
     if(!rst)                                         //低电平复位时LED全灭
            led <= 3'b000;
    else if(key_press[0])                             //若按键0按下,则LED0取反
            led[0] <= ~led[0];
    else if(key_press[1])                             //若按键1按下,则LED1取反
            led[1] <= ~led[1];
    else if(key_press[2])                             //若按键2按下,则LED2取反
            led[2] <= ~led[2];
end
endmodule

三、代码说明

1、本例主要讨论按键消抖的设计方法,其主要思想为,当按键按下时,进行20毫秒的延时,若在20毫秒内检测到按键的边沿,则计数清零,重新开始延时,直到20毫秒结束,则获取键。
2、为了判断是否有键按下,先把三个按键值相与,若结果key为0,则表明有键被按下。
3、为了产生电平跳变的边沿,先进行keyr <= {keyr[0], key}操作,相当于每个时钟来时用key值向左填充keyr。由于keyr的初始值为11,当key等于1时,相当于没有变化,即没有按键按下。当key等于0时,并位操作后keyr的值为10,此时只要把前后两位的值进行~keyr[0] & keyr[1]的操作,其结果为1,表示有下降沿产生。而当下一个时钟来时,keyr的值变为了00,进行~keyr[0] & keyr[1]操作后的结果为0,表明没有边沿产生(因为按键一直处于按下状态)。当按键释放时,key等于1,并位后keyr的值为01,此时进行keyr[0] & ~keyr[1]的操作,其结果为1,表示有上升没产生。而当下一个时钟来时,keyr的值变为了11,进行keyr[0] & ~keyr[1]操作后的结果为0,表明没有边沿产生(因为按键一直处于释放状态)。
4、根据以上第3步,就可得到按键的下降沿或上升沿(代码中的key_neg或key_pos),且其高电平的维持时间只有一个时钟周期,故可以作为按键边沿信号来使用。这样做的好处在于,无论按下(或释放)哪个按键,都统一做一个边沿量来处理。
5、然后进行20毫秒的循环计数,在计数过程中,如果遇到前面的边沿量(key_neg或key_pos)有效,则计数清零重新计数,直到溢出。
6、20毫秒溢出后,表示肯定有按键按下了,此时需要计算出键值,即哪个按键被按下。先定义两个健值存储变量key_halue[1:0],初始值都为111,然后一个时钟执行一次key_halue[1] <= key_halue[0]。当计数到了20毫秒后,执行key_halue[0] <= key_h,即获取外部按键。由于已经是在20毫秒之后才执行的该语句,所以说明有键被按下,即key_halue[0]的值不为全1了(key_halue[1]的值仍没变,为全1,因为两个值相差一个时钟节拍),此时进行key_halue[1] & ~key_halue[0]的处理之后,其结果就是被按下的那一位的值为1,其余为0,这样就能找出按下的键值(代码中key_press的值)。同上面第3步中的情况一样,在下一个是时钟来时,key_press的值恢复为全0,即按键的键值只存在一个时钟周期。
7、若需要检测的是按键的释放,则换成~key_halue[1] & key_halue[0]的处理方式,其余一样。
8、综合以上步骤,最终获得的按键值key_press,是经过消抖处理之后,按位排列的键值(即一个按键占用一个位),当某位为1时表明该按键被触发(可能是按下或是释放),且只存在一个时钟的高电平宽度。
9、这样的按键设计,不仅能消除抖动引起的误触发,还解决了按键按下(或释放)一次,却得到多次键值的弊病。即一次按键操作,只产生一个键值信号,保证了按键操作的有效性。
10、为了容易理解,上述在获取按键并进行并位操作时,没有进行时钟打拍操作。在实际应用时,为了消除FPGA的亚稳态,一般需要再打两拍时钟,再进行其他操作(即keyr <= {keyr[2:0], key}),可自行分析。

四、实验步骤

FPGA开发的详细步骤请参见“基于EP4CE6F17C8的FPGA开发流程(以半加器为例)”一文,本例只对不同之处进行说明。

本例工程放在D:\EDA_FPGA\Exam_7文件夹下,工程名称为Exam_7。模块文件名称为key_led.v,并设置为顶层实体。其余步骤与“基于EP4CE6F17C8的FPGA开发流程”中的一样。

接下来看管脚约束,本例中使用了3个按键和3个LED,一共6个引脚,再加上复位和时钟晶振,一共8个。具体的端口分配如下图所示。

对于未用到的引脚设置为三态输入方式,多用用途引脚全部做为普通I/O端口,电压设置为3.3-V LVTTL(与”基于EP4CE6F17C8的FPGA开发流程“中的一样)。需要注意,程序中的每个端口都必须为其分配管脚,如果系统中存在未分配的I/O,软件可能会进行随机分配,这将造成不可预料的后果,存在烧坏FPGA芯片的风险。

接下来对工程进行编译,编译完成后,可查看一下逻辑器件的消耗情况,如下图所示。

另外,还可以点击菜单Tools->Netlist Viewers->RTL Viewer,查看一下生成的RTL电路图,如下图所示。

最后进行程序下载,并查看结果。下图是按下key1时点亮led1的图片。

下图为按下key2时点亮led2的图片。

下图为按下key3时点亮led3的图片。

当按下reset键时,所有led均熄灭,如下图。

 

标签:LED,FPGA,引脚,EP4CE6F17C8,key,按键,键控,时钟
From: https://www.cnblogs.com/fxzq/p/18108576

相关文章

  • 一些fpga相关的知识
    一、什么是LUT?二、芯片型号命名的意义 比如我用的是xc7a35tfgg484-2,那么它每一部分的意思是: 三、blockram ......
  • FPGA数字逻辑运行特点及常见方法
    模型功能FPGA的运行是并行的FPGA的串行依赖状态机FPGA的并行依赖流水线FPGA的大规模设计依赖精确设计模型框图FPGA是并行的系统,所有的代码同时运行,这是FPGA高效的根本所在实现步骤FPGA的并行特性和一般意义上的高级语言不同,verilog更多地是低级语言特性这一点可......
  • 产品推荐 | 中科亿海微推出亿迅®A8000金融FPGA加速卡
    01、产品概述亿迅®A8000金融加速卡,是中科亿海微联合金融证券领域的战略合作伙伴北京睿智融科,将可编程逻辑芯片与金融行业深度结合,通过可编程逻辑芯片对交易行情加速解码,实现低至纳秒级的解码引擎,端到端的处理时延降低到百纳秒级别,为证券、期货、基金、私募等机构用户提供高性......
  • CRC校验方法和FPGA实现
    参考:【科普向】谁都能看懂的CRC(循环冗余校验)原理_crc循环冗余校验原理-CSDN博客CRC校验原理和推导过程及Verilog实现(一文讲透)_crcverilog-CSDN博客介绍两个CRC源码生成工具,可生成Verilog和VHDL-niosII爱好者-博客园(cnblogs.com)GeneratorforCRCHDLcode(bues.ch)......
  • 基于EP4CE6F17C8的FPGA数码管时钟显示实例
    一、电路模块本例的电路模块与“基于EP4CE6F17C8的FPGA数码管动态显示实例”中的完全一样,此处就不再给出了。二、实验代码本例使用6个数码管显示时钟的时、分、秒,时与分之间及分与秒之间通过小数点来分隔,代码使用Verilog编写,采用例化的形式,使用了两种方式来实现。第一种方式,共......
  • FPGA入门笔记010——UART串口接收模块设计
    1、串口接收模块原理​当对于数据线Rs232_Rx上的每一位进行采样时,一般情况下认为每一位数据的中间点是最稳定的。因此一般应用中,采集中间时刻时的电平即认为是此位数据的电平,如图1所示。图1——串口接收时序图(图中BPS_CLK为采样时钟)​但是在实际工业应......
  • FPGA时序约束实战
    改编自8FPGA时序约束实战篇之主时钟约束_checktimingnoclock 以Vivado自带的wave_gen工程为例,该工程的各个模块功能较为明确,如下图所示。为了引入异步时钟域,我们在此程序上由增加了另一个时钟–clkin2,该时钟产生脉冲信号pulse,samp_gen中在pulse为高时才产生信号。下面我......
  • 实测52.4MB/s!全国产ARM+FPGA的CSI通信案例分享!
    CSI总线介绍与优势CSI(CMOSsensorparallelinterfaces)总线是一种用于连接图像传感器和处理器的并行通信接口,应用于工业自动化、能源电力、智慧医疗等领域,CSI总线接口示意图如下所示(以全志科技T3处理器的CSI0为例)。  图1高带宽:CSI总线支持高速数据传输,可以满足多通道高速......
  • FPGA原语
    ODDR代表的是双数据速率输出寄存器(OutputDoubleDataRateRegister)。这种原语用于在一个时钟周期内产生两个数据输出,通常用于高速数据传输和时钟数据恢复等应用。在以下示例VHDL代码中,ODDR原语被用来生成一个双数据速率的输出信号ad9653_1clk。ad1_clk:ODDRgenericmap(......
  • Xilinx ZYNQ 7000+Vivado2015.2系列(八)ARM+FPGA的优势,PS控制PL产生需要的PWM波(基于AXI
    上一节我们观察了AXI总线的信号,了解了基于AXI总线读写的时序,这一节我们继续探索基于AXI总线的设计,来看一看ZYNQ系列开发板的独特优势,PS可以控制PL产生定制化的行为,而不需要去动硬件代码。这次实验是产生频率和占空比可调的PWM(PulseWidthModulation)信号,调用8次,产生8路PWM......