以前写的矩阵键盘的驱动是以单片机的思想来实现的,在FPGA上完全失败了,考虑的太简单了emmmmmm。所以在查了一些资料后,对过去写过的矩阵键盘驱动做个修正

旧版本代码

module keyboard_4_4(input                    clk,input                   rst,output reg[3:0]         c_pin,input[3:0]                r_pin,output reg[3:0]       key_out
);reg[15:0]                 div_cnt;reg[2:0]                state;reg                       cnt_full;localparam             CHECK_R1=3'b000;localparam                CHECK_R2=3'b001;localparam                CHECK_R3=3'b011;localparam                CHECK_R4=3'b010;//always@(posedge clk or negedge rst)begin//1msif(!rst)begindiv_cnt <= 16'd0;cnt_full <= 1'b0;endelseif(div_cnt==16'd49999)begindiv_cnt <= 16'd0;cnt_full <= 1'b1;endelse begindiv_cnt <= div_cnt + 1'b1;cnt_full <= 1'b0;endendalways@(posedge cnt_full or negedge rst)beginif(!rst)state <= CHECK_R1;elsecase(state)CHECK_R1:if(cnt_full)state <= CHECK_R2;elsestate <= CHECK_R1;CHECK_R2:if(cnt_full)state <= CHECK_R3;elsestate <= CHECK_R2;CHECK_R3:if(cnt_full)state <= CHECK_R4;elsestate <= CHECK_R3;CHECK_R4:if(cnt_full)state <= CHECK_R1;elsestate <= CHECK_R4;default:state <= state;endcaseendalways@(posedge clk or negedge rst)beginif(!rst)c_pin <= 4'b0000;elsecase(state)CHECK_R1:beginc_pin <= 4'b1000;case(r_pin)4'b1000:key_out <= 4'd0;4'b0100:key_out <= 4'd1;4'b0010:key_out <= 4'd2;4'b0001:key_out <= 4'd3;endcaseendCHECK_R2:beginc_pin <= 4'b0100;case(r_pin)4'b1000:key_out <= 4'd4;4'b0100:key_out <= 4'd5;4'b0010:key_out <= 4'd6;4'b0001:key_out <= 4'd7;endcaseendCHECK_R3:beginc_pin <= 4'b0010;case(r_pin)4'b1000:key_out <= 4'd8;4'b0100:key_out <= 4'd9;4'b0010:key_out <= 4'd10;4'b0001:key_out <= 4'd11;endcaseendCHECK_R4:beginc_pin <= 4'b0001;case(r_pin)4'b1000:key_out <= 4'd12;4'b0100:key_out <= 4'd13;4'b0010:key_out <= 4'd14;4'b0001:key_out <= 4'd15;endcaseend   default:beginc_pin <= 4'b0000;key_out <= 4'd0;endendcaseend
endmodule

旧版思想是典型的单片机应用思想:循环给每行置高电平,同时循环检测各列的电平状态。
这种思想在仿真时不会有任何问题,但在实际使用时有很大问题。在FPGA上应用失败的原因在于FPGA的引脚未上拉,在测试时电平有特别大的波动。
改进的方法:要在矩阵键盘上加上拉电阻,阻值10k即可。

我在网上看了小梅哥的一篇,测试也成功了,先贴出来,之后我优化一下代码
原地址:http://bbs.eeworld.com.cn/forum.php?mod=viewthread&tid=510834

电路图

代码

module Key4x4_Board(input                        Clk,input                       Rst_n,input [3:0]               Key_Board_Row_i,output reg [3:0]            Key_Board_Col_o,output reg                  Key_Flag,output reg[3:0]            Key_Value
);reg [19:0]                    counter1; //延时计数器reg                        En_Cnt1; //延时计数器使能控制信号,当进入延时消抖阶段时为高reg                       Cnt_Done1; //延时计数器延时完成(计满 20ms)信号reg [25:0]               counter2; //连按间隔计数器reg                      En_Cnt2; //连按间隔计数器使能控制信号,当进入连按间隔阶段时为高reg                         Cnt_Done2; //连按间隔计数器延时完成(计满 200ms)信号reg [10:0]                    state; //状态寄存器,存储系统的状态reg [3:0]                  Key_Board_Row_r;//矩阵键盘行输入寄存器,存储行状态reg [3:0]                  Col_Tmp; //reg [7:0]                    Key_Value_tmp;//矩阵键盘扫描结果reg                         Key_Flag_r; //按键检查成功标志信号localparamIDLE = 11'b00000000001, //空闲态,无按键按下P_FILTER = 11'b00000000010, //按下消抖状态READ_ROW_P = 11'b00000000100, //读取按下时矩阵键盘行状态SCAN_C0 = 11'b00000001000, //扫描矩阵键盘第 0 列(Col0)SCAN_C1 = 11'b00000010000, //扫描矩阵键盘第 1 列(Col1)SCAN_C2 = 11'b00000100000, //扫描矩阵键盘第 2 列(Col2)SCAN_C3 = 11'b00001000000, //扫描矩阵键盘第 3 列(Col3)PRESS_RESULT = 11'b00010000000, //获得扫描结果WAIT_R = 11'b00100000000, //等待释放信号到来R_FILTER = 11'b01000000000, //释放消抖READ_ROW_R = 11'b10000000000; //读取释放时矩阵键盘行状态
// 延时计数器,计数以延时 20msalways@(posedge Clk or negedge Rst_n)if(!Rst_n)counter1 <= 20'd0;else if(En_Cnt1)beginif(counter1 == 20'd999999)counter1 <= 20'd0;elsecounter1 <= counter1 + 1'b1;endelsecounter1 <= 20'd0;//产生延时完成标志信号,(当延时 20ms 时产生一个计数完成信号 Cnt_Done1) always@(posedge Clk or negedge Rst_n)if(!Rst_n)Cnt_Done1 <= 1'b0;else if(counter1 == 20'd999999)Cnt_Done1 <= 1'b1;elseCnt_Done1 <= 1'b0;// 连按间隔计数器,计数以延时 20msalways@(posedge Clk or negedge Rst_n)if(!Rst_n)counter2 <= 26'd49_999_999; //初始时设定间隔为 1selse if(En_Cnt2)beginif(counter2 == 26'd0)counter2 <= 26'd999999; //启动间隔后每 20ms 发出一次间隔标志elsecounter2 <= counter2 - 1'b1;endelsecounter2 <= 26'd49_999_999;//产生连按间隔完成标志信号,(当延时 20ms 时产生一个计数完成信号 Cnt_Done2) always@(posedge Clk or negedge Rst_n)if(!Rst_n)Cnt_Done2 <= 1'b0;else if(counter2 == 26'd0)Cnt_Done2 <= 1'b1;elseCnt_Done2 <= 1'b0;//矩阵键盘扫描状态机 always@(posedge Clk or negedge Rst_n)if(!Rst_n)beginEn_Cnt1 <= 1'b0;state <= IDLE;//默认需要让列输出为 0,这样,当有按键按下时,行列接通,行输入才能读到有低电平Key_Board_Col_o <= 4'b0000;Col_Tmp <= 4'd0;Key_Flag_r <= 1'b0;Key_Value_tmp <= 8'd0;Key_Board_Row_r <= 4'b1111;endelse begincase(state)
//空闲态,持续判断是否有按键被按下(按键按下时 Key_Board_Row_i 将不为全 1)IDLE: if(Key_Board_Row_i != 4'b1111)begin //有按键按下En_Cnt1 <= 1'b1; //启动延时计数器state <= P_FILTER; //跳转到按下消抖状态endelse beginEn_Cnt1 <= 1'b0;Key_Board_Col_o <= 4'b0000;state <= IDLE; endP_FILTER: //按下消抖状态if(Cnt_Done1) begin //20ms 延时完成En_Cnt1 <= 1'b0; //停止延时计数器state <= READ_ROW_P; //跳转到读取矩阵键盘行输入状态endelse begin //20ms 延时还没有完成En_Cnt1 <= 1'b1; //保持延时计数器继续计数state <= P_FILTER; endREAD_ROW_P: //读取矩阵键盘行输入状态if(Key_Board_Row_i != 4'b1111)begin //行输入不全为 1,表明确实有按键按下Key_Board_Row_r <= Key_Board_Row_i; //将当期行输入状态存入行状态寄存器state <= SCAN_C0; //跳转到扫描矩阵键盘第 0 列(Col0)状态Key_Board_Col_o <= 4'b1110; //将第 0 列列输出置 0endelse begin //若行输入恢复为了全 1,则表明此次为抖动,不再执行扫描,跳回空闲态state <= IDLE;Key_Board_Col_o <= 4'b0000;endSCAN_C0: //扫描矩阵键盘第 0 列(Col0)状态beginstate <= SCAN_C1; //下一个状态为扫描矩阵键盘第 1 列(Col1)状态Key_Board_Col_o <= 4'b1101; //扫描第 1 列对应的行输出为 1101if(Key_Board_Row_i != 4'b1111) //行输入不全为 1,表明为当前列(第 0列)有按键按下Col_Tmp <= 4'b0001;//将列值存入列寄存器中elseCol_Tmp <= 4'b0000;endSCAN_C1: //扫描矩阵键盘第 1 列(Col1)状态beginstate <= SCAN_C2; //下一个状态为扫描矩阵键盘第 2 列(Col2)状态Key_Board_Col_o <= 4'b1011; //扫描第 1 列对应的行输出为 1011if(Key_Board_Row_i != 4'b1111) //行输入不全为 1,表明为当前列(第 1列)有按键按下Col_Tmp <= Col_Tmp | 4'b0010;//将列值存入列寄存器中elseCol_Tmp <= Col_Tmp; endSCAN_C2: //扫描矩阵键盘第 2 列(Col2)状态beginstate <= SCAN_C3; //下一个状态为扫描矩阵键盘第 3 列(Col3)状态Key_Board_Col_o <= 4'b0111;//扫描第 1 列对应的行输出为 0111if(Key_Board_Row_i != 4'b1111)//行输入不全为 1,表明为当前列(第 2列)有按键按下Col_Tmp <= Col_Tmp | 4'b0100;//将列值存入列寄存器中elseCol_Tmp <= Col_Tmp; endSCAN_C3: //扫描矩阵键盘第 3 列(Col3)状态beginstate <= PRESS_RESULT; //下一个状态为得到扫描结果状态if(Key_Board_Row_i != 4'b1111)//行输入不全为 1,表明为当前列(第 3列)有按键按下Col_Tmp <= Col_Tmp | 4'b1000;//将列值存入列寄存器中elseCol_Tmp <= Col_Tmp; endPRESS_RESULT: //得到扫描结果状态beginstate <= WAIT_R; //下一个状态为等待按键释放状态//让列输出全 0,这样,当有按键按下时,行列接通,行输入才能读到有低电平Key_Board_Col_o <= 4'b0000;/*4 位行输入值相加为 3,表明有且只有一个行输入为 0,既保证只有一行中有按键被
按下*4 位列扫描结果相加为 1,表明有且只有列中有按键被按下,通过这两个条件保证了
一次*按键中只有一个按键被按下时才检测有效*/if(((Key_Board_Row_r[0] + Key_Board_Row_r[1] +Key_Board_Row_r[2] + Key_Board_Row_r[3]) == 4'd3) &&((Col_Tmp[0] + Col_Tmp[1] + Col_Tmp[2] + Col_Tmp[3]) ==4'd1))beginKey_Flag_r <= 1'b1;//产生检测成功标志信号Key_Value_tmp <= {Key_Board_Row_r,Col_Tmp};//将行列结果组合得到按键扫描结果endelse begin //若不满足只有一个按键被按下,则不产生检测成功标志信号Key_Flag_r <= 1'b0;Key_Value_tmp <= Key_Value_tmp;endendWAIT_R://等待按键释放状态beginKey_Flag_r <= 1'b0;//清零检测成功标志信号if(Key_Board_Row_i == 4'b1111)begin//无按键按下,表明按键被释放En_Cnt1 <= 1'b1;//启动延时计数器state <= R_FILTER;//进入释放消抖状态En_Cnt2 <= 1'b0; //停止连按间隔计数器endelse beginstate <= WAIT_R;En_Cnt1 <= 1'b0;En_Cnt2 <= 1'b1;//启动连按间隔计数器endendR_FILTER: //释放消抖状态 if(Cnt_Done1) begin //延时时间到En_Cnt1 <= 1'b0;state <= READ_ROW_R;//跳转入读取按键行输入状态(按键释放阶段)endelse beginEn_Cnt1 <= 1'b1;state <= R_FILTER; endREAD_ROW_R://读取按键行输入状态(按键释放阶段)if(Key_Board_Row_i == 4'b1111) //无按键按下,表明确实已经稳定的释放了state <= IDLE; //跳转回空闲状态else begin //否则表明此次释放为抖动,回到释放消抖状态继续等待En_Cnt1 <= 1'b1;state <= R_FILTER; enddefault:;endcaseend
//将扫描结果译码输出 always@(posedge Clk or negedge Rst_n)if(!Rst_n)beginKey_Flag <= 1'd0;Key_Value <= 4'd0;endelse begin//按键检查成功输出标志为扫描成功与连按间隔的逻辑或Key_Flag <= Key_Flag_r | Cnt_Done2;case(Key_Value_tmp)8'b1110_0001 : Key_Value <= 4'h1; //第 0 行,第 0 列8'b1110_0010 : Key_Value <= 4'h2; //第 0 行,第 1 列8'b1110_0100 : Key_Value <= 4'h3; //第 0 行,第 2 列8'b1110_1000 : Key_Value <= 4'ha; //第 0 行,第 3 列8'b1101_0001 : Key_Value <= 4'h4; //第 1 行,第 0 列8'b1101_0010 : Key_Value <= 4'h5; //第 1 行,第 1 列8'b1101_0100 : Key_Value <= 4'h6; //第 1 行,第 2 列8'b1101_1000 : Key_Value <= 4'hb; //第 1 行,第 3 列8'b1011_0001 : Key_Value <= 4'h7; //第 2 行,第 0 列8'b1011_0010 : Key_Value <= 4'h8; //第 2 行,第 1 列8'b1011_0100 : Key_Value <= 4'h9; //第 2 行,第 2 列8'b1011_1000 : Key_Value <= 4'hc; //第 2 行,第 3 列8'b0111_0001 : Key_Value <= 4'h0; //第 3 行,第 0 列8'b0111_0010 : Key_Value <= 4'h0; //第 3 行,第 1 列8'b0111_0100 : Key_Value <= 4'h0; //第 3 行,第 2 列8'b0111_1000 : Key_Value <= 4'hd; //第 3 行,第 3 列default:begin Key_Value <= Key_Value;Key_Flag <= Key_Flag; endendcase endendmodule

FPGA的矩阵键盘驱动( 修正版)相关推荐

  1. 矩阵键盘与六位数码管_[走近FPGA]之矩阵键盘

    注:由于新学期较为繁忙,本文由不愿透露姓名的 @Cardia 撰写.以下为正文. 在上一篇文章中,介绍了二进制转十进制电路的实现,其文章链接如下: 人生状态机:[走近FPGA]之二进制转BCD码​zh ...

  2. Arduino与Proteus仿真实例-4x4矩阵键盘驱动仿真

    4x4矩阵键盘驱动仿真 键盘是广泛用于各种电子和嵌入式项目的输入设备. 它们用于以数字和字母的形式获取输入,并将其输入系统以进行进一步处理. 矩阵键盘由一组相互连接的按钮组成. 在本次实例中使用 4X ...

  3. 基于FPGA的 矩阵键盘按键识别 【原理+源码】

    目录 引言 原理阐述 实现方法 源码分享 板级调试演示 引言 最近了解了矩阵键盘扫描的原理,动手实现了一下,在这里做一个简单的总结. 原理阐述 矩阵键盘典型电路: FPGA的应用电路: 其中,行信号为 ...

  4. linux下矩阵键盘设备名,Linux下矩阵键盘驱动分析与移植

    Post Views: 1,598 首先要介绍一下Linux中input子系统的模型,一图胜千言,所以直接上图. 上图一目了然,我们的键盘驱动就是工作在input子系统的最低层.单纯地从驱动角度讲,我 ...

  5. 嵌入式linux矩阵键盘,嵌入式linux matrix_keypad矩阵键盘驱动

    ARM:AM3517 linux2.6.37 TI官方开发板AM3517EVM 我想移植一个8*5的GPIO矩阵键盘,在linux源码/drivers/input/目录下有很多种键盘驱动程序,但是 能 ...

  6. 41 linux标准输入设备之矩阵键盘驱动的实现

    准备知识点: 原子位操作 , linux输入设备的应用程序编程 在linux内核里用struct input_dev的一个对象来表示一个输入设备. 用一位二进制表示是否支持相应的功能, 多种功能需要多 ...

  7. linux下矩阵键盘驱动

    1_>路径:linux\drivers\input\keyboard 2_>文件名:matrix_keypad.c 说明:这是一个平台驱动程序,在上面的.c文件里没有建一个设备,只有驱动 ...

  8. 最易移植的I/O任意定义的矩阵键盘驱动

    网上的矩阵键盘代码非常非常多,但绝大部分都是要连续I/O口的,就比如PA0-PA7.PB3-PB10等等等,这些都要用到一排的连续的单片机引脚.用过STM32单片机的都知道,STM32单片机一排过去连 ...

  9. FPGA矩阵键盘的驱动设计与验证

    请关注微信公众号"FPGA科技室" 本文讲解利用***verilog实现矩阵键盘的驱动设计*** ,在此之前,想必学过单片机的小伙伴应该很熟悉矩阵键盘,单片机用c语言实现了矩阵键盘 ...

最新文章

  1. poj2289二分图多重匹配
  2. flume的安装和部署
  3. huber loss
  4. linux 命令行选项
  5. Linux使用技巧15则
  6. 轻触开源(一)-Java泛型Type类型的应用和实践
  7. ubuntu16.04安装teamviewer12
  8. Vue 在beaforeCreate时获取data中的数据
  9. 基于标记不确定性和类别不平衡的语义分割在植被制图中的应用(soybean+FCN_segNet+newloss)
  10. iScroll示例,下拉刷新,上拉刷新
  11. 【计算机网络自顶向下方法】(哈工大)学习笔记
  12. 三星android智能手机usb驱动程序,三星手机驱动官方下载
  13. python与java前景分析-Java和Python哪个未来前景好?
  14. 海康摄像头视频视频转码H264处理
  15. 视频网关是什么,视频接入网关技术作用
  16. 【任务二】打卡——by 003-Vamein
  17. Redis 集群可用性测试
  18. 统信 Deepin为什么要摆脱Ubuntu和Debian?
  19. 关于美国安利的真实情况 !!!!!
  20. 谷粒商城-02-p20-p27

热门文章

  1. 暴雨,她还会再回来的,广东已开通本月降雨套餐
  2. 基于SSM+SpringBoot+MySQL+Vue前后端分离的博客论坛系统
  3. 关于validation验证框架不起作用的解决方法
  4. CIKM 2022|FwSeqBlock: 一种在序列建模中增强行为表征的方法
  5. 如何选择合适的CDN加速合作?关键在于这三个方面!
  6. 全网页CSS 超链接无下划线
  7. 唐桥云会议分组讨论——新的参会互动方式
  8. 计算机视觉——棋盘格标定法获取相机内参外参
  9. Android 经验: 本地 5555 端口会被 adb 误认为 emulator
  10. java实现html页面转pdf解决方案_[Java教程]纯js实现html转pdf