玩转VHDL013-4x4按键扫描

2020-02-02 11:31发布

4x4按键扫描前几贴介绍了时钟使用与反跳处理,本帖以4x4按键扫描一个具体的简单示例展示如何运用时钟与反跳处理。4x4按键电路简介4x4按键排列成44列结构共16个按键,8根引线。这8根引线分别是行线4根和列线4根。在FPGA连接电路中可以把行线作为输入,列线作为输出,或者相反。本示例选用列作为输入,行作为输出。作为输入的4条列线应该分别接10K上拉电阻,或者在FPGA内部设置列输入为弱上拉。VHDL定义行和列引脚如下:        col_in               : in std_vector(0 to 3);    --列输入        ln_out              : out std_vector(0 to 3); --行输出按键扫描方法ln_out循环输出0111, 1011, 1101, 1110,每次输出只有1行为0其他3行为1。同时每改变一次输出,读取col_in一次。那么一轮循环共读取16个比特的数值。这16个比特中值为0的表示对应按键被按下,如果全1说明没有按键按下。具体实现按键实现模块命名为Key4x4_scan,系统时钟采用50MEntity Key4x4_scan is Port(        clk50M                     : in std_logic;        col_in                       : in std_vector(0 to 3);        ln_out                       : out std_vector(0 to 3);        qKey                                 : out std_vector(0 to 3);        kPress                       : out std_logic        );End entity Key4x4_scan;引脚功能描述:clk50M:系统50M时钟。kPress:无按键按下时值为0,有按键按下时值为1qKey:按键号的4比特编码,值0~15kPress=0时不不关心qKey数值。模块实现全部代码Architecture myFavor of Key4x4_scan is        attributealtera_attribute       : string;        alias clock                                 : std_logic isclk50M;        signal C1K                                 : std_vector(0to 15);        signal kDn                                 : std_vector(0to 15);        signal scan                                : std_vector(0to 1);        signal P1K,smp                         : std_logic;        signal k_rd,k_same          : std_logic;        signal kCode                     : std_vector(0 to 4);        signal cn_bounce             : std_vector(0 to 4); --128ms        signal vKey,kBuf               : std_vector(0 to 4);        attributealtera_attribute of vKey : signal is "power_up_level=high";BeginProcess(clock) begin                if rising_edge(clock)then1.              RstIncDec(C1K,C1K=50e3-1, true);2.              P1K <=b_nor(C1K);3.              smp <=STDZ(C1K=40e3-1);4.              IncDec(scan,P1K);        end if;      End process;With scan select ln_out<=    "0111"     when "00",        "1011"     when "01",        "1101"     when "10",        "1110"     when others;Process(clock) begin                if rising_edge(clock)then5.              LoadValue(kDn(0to 3),   col_in, smp and scan=0);6.              LoadValue(kDn(4to 7),   col_in, smp and scan=1);7.              LoadValue(kDn(8to 11), col_in, smp and scan=2);8.              LoadValue(kDn(12to 15),col_in, smp and scan=3);9.              k_rd <= P1Kand scan=3;10.           kCode <=pri_encoder(not kDn);11.           LoadValue(kBuf,kCode, k_rd);12.           LoadValue(k_same,STDZ(kCode=kCode), k_rd);13.           RstIncDec(cn_bounce,not k_same, k_rd);14.           LoadValue(vKey,kBuf, b_and(cn_bounce&k_rd&k_same));        end if;      End process;15.   kPress <= not vKey(0);16.   qKey <= vKey(1 to 4);End myFavor;11ms计数器,用于定时每1ms扫描一行。2P1K1KHz周期脉冲,010贴中提到用作使能下一行扫描,等效为1KHz时钟。3smp为扫描一行时采样列数据时刻。4scan扫描行计数,03循环。控制ln_out输出。5~8:读取16个按键是否按下状态放入kDn9k_rd指示4行扫描完毕,可以一次读取16键按下状态。k_rd周期是4ms10pri_encoder(v)优先编码函数,返回从左到右v中第一个比特为1的位置,v0时返回v的比特个数。由于kDn中比特为0表示按键按下,所以采用notkDn来判断第一个0的位置。所以kCode=16时表示无按键按下,kCode=0~15表示对应按键被按下。11~14:对kCode值进行反跳处理,kCode持续128ms值保持不变则装载到vKey中。关于并行反跳处理已在012贴中论述。1516,最后输出。行15 not vKey(0)取反目的是用1表示有键按下,更加符合常规思维习惯。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。