本帖最后由 芯航线跑堂 于 2017-1-7 23:34 编辑
FPGA矩阵键盘驱动设计与验证
本文由西安网友张昭贡献,特此感谢 课程简介本章我们主要是来实现用verilog语言实现矩阵键盘的驱动。提到矩阵键盘,许多读者应该不会陌生,因为学过单片机、ARM的人都应该知道并用C语言做过矩阵键盘的驱动。本章作者将用verilog语言来写一个矩阵键盘(4*4)的驱动,并用LED灯的状态指示按键的状态。课后会留有和本章内容有关的作业,希望所有读者能独立完成作业。接下来就让我们一块走进今天的学习内容“矩阵键盘学习之旅”。 矩阵键盘诞生的背景相信许多人经常用到矩阵键盘但是却不知道“它”的由来。由于最早的MCU(即单片机)其IO口相对较少,而且用到按键过多的话,就会占用过多的IO。人们为了解决这个问题就引入了“矩阵键盘”。在矩阵键盘中,每条行线和列线在交叉处都不是直接连同,而是通过一个按键直接相连,这样以来一个4*4的矩阵键盘只需要8根控制线就可以完成16个按键的控制。下面就是常见的两类4*4矩阵键盘:
注意:我们的键盘是有上拉电阻的,而淘宝上的这款没有上拉所以不能直接用的。 矩阵键盘工作原理
要说起矩阵键盘是如何工作的?就得从它的硬件原理图来理解它工作机理。啥话不说,直接上图有图有真相。 通常我们检测矩阵键盘中某一按键是否被按下,常用的方法是行扫描法。图中一共有8条控制线,4条行控制线(ROW),4条列控制线(COL),而且可以看到8条控制线的初始状态都位高电平。那我们如何去检测某一个按键被按下,并且还能找到其具体的位置?假如我们让COL0=0,然后去逐行的进行扫描每一行,如果ROW0=0出现低电平通过20ms的延迟再次判断该行是否仍然为零,如果仍然为零,那么说明按键0被按下。其它按键的检测类似这种方法。例如: 如果COL=4’b0100时,当检测到ROW=4’b1011,则说明“A”被按下;可能这块有些读者会说为啥不是“5”被按下?如果有读者提出这个疑惑的话,那就很有必要跟着作者学完这节课,再仔细思考思考。
总体框架图端口列表如下:
状态转移图现在作者就来给大家讲解今天的重点,状态转移图的设计。可能会有读者说,这个东西有什么用处?给大家举个例子,“如何去建筑一座楼房”。在建造前肯定是工程师设计建筑的建造图纸,然后工人们按照图纸进行分工建造房屋。今天作者讲的状态转移图就像是工程师设计图纸没有图纸,直接编代码,肯定会来回修改多次。下面进入正题: 矩阵键盘的状态转移图如下所示: 1、IDLE状态:主要是用来检测是否有按键被按下,无按键按下时,行控制线Key_Board_Row_i等于15,有按键按下时Key_Board_Row_i不等于15,则进入P_FILTER状态; 2、P_FILTER状态: 主要是进行按键消抖检测,判断是否有按键真实被按下,如果有按键真实被按下则跳转至下一个状态READ_ROW_P获取行状态的值,否则不跳转; 3、READ_ROW_P状态:读取行状态并将存入的寄存器中Key_Board_Row_r(ps:存入寄存器是因为按键按下的时间比较短暂,所以要将其状态缓存起来),并将第0列拉低,进入SCAN_C0状态进行行扫描; 4、SCAN_C0状态: 进行列扫描,来判断该列是否有按键被按下(ps:通俗地讲就是确定按键位置),判断行输入是否等于15,如果不等于则说明该列有按键被按下,否则将第1列拉低,状态跳转到SCAN_C1状态进行行扫描; 5、SCAN_C1状态: 进行列扫描,来判断该列是否有按键被按下(ps:通俗地讲就是确定按键位置),判断行输入是否等于15,如果不等于则说明该列有按键被按下,否则将第2列拉低,状态跳转到SCAN_C3状态进行行扫描; 6、SCAN_C2状态: 进行列扫描,来判断该列是否有按键被按下(ps:通俗地讲就是确定按键位置),判断行输入是否等于15,如果不等于则说明该列有按键被按下,否则将第3列拉低,状态跳转到SCAN_C3状态进行行扫描; 7、SCAN_C3状态: 进行列扫描,来判断该列是否有按键被按下(ps:通俗地讲就是确定按键位置),判断行输入是否等于15,如果不等于则说明该列有按键被按下,否则状态跳转到PRESS_RESULT状态输出扫描结果; 8、PRESS_RESULT状态: 输出扫描结果。这块给大家教一种比较特别的方法来确定整个键盘上只有一个按键被按下:4位行控制线如果4位行线值加起来如果等于3则说明有一行被按下: (Key_Board_Row_i[0]+ Key_Board_Row_i[1]+Key_Board_Row_i[2]+ Key_Board_Row_i[3]=3),同样如果4位列控制线值加起来如果等于1则说明有一列被按下: (Col_Tmp [0]+ Col_Tmp [1]+ Col_Tmp [2]+ Col_Tmp[3]=1) 通过这两个参数的限定,确保了只有一个按键被按下。如果不满足,则不产生检测成功标志信号。状态跳转到WAIT_R等待按键释放状态 9、WAIT_R状态: 等待按键释放,如果Key_Board_Row_i=15则说明按键被释放,状态跳转到释放消抖状态R_FILTER 10、R_FILTER状态:检测按键是否完全被释放如果释放则跳转到READ_ROW_R状态读取按键行输入状态,读取行的状态。 11、READ_ROW_R状态:读取按键行输入状态。
通过这些状态,我们把一个按键按下,到释放的过程完美的进行了一次检测,最终将输出结果用LED灯的状态表示。接下来,就是照着下面的状态转移图敲写程序。这下读者们可以自由选择语言编程,Verilog或者VHDL随意选,然后去盖起自己的矩阵键盘“大厦”。
程序部分下面是整个矩阵键盘驱动的程序部分:
以上就是程序部分,主要部分状态机部分的代码完全是按照,状态及设计部分的状态转移图来实现的。可能刚开始让大家,先设计状态转移图后敲代码比较难,但是还是希望大家从刚开始就养成一个好的习惯,这样日积月累自己独立思考能力也就上去了。 仿真验证与逻辑分析仪检测作者通过和周围初学FPGA的朋友交流,发现了一个严重问题,许多初学的朋友,不喜欢写测试文件,而是喜欢直接下板进行板及验证。在这里作者想指正大家这个不好的习惯,通过分析初学者不爱仿真,作者总结出以下几个原因: 1、 对于刚开始学FPGA的朋友,根本就不会写测试脚本文件,就算会写仿真出来的波形不会分析; 2、 简单的测试脚本写起来感觉没意思纯属是在浪费时间,复杂的又不会写,出问题自己又搞不定 3、 复杂的不会写,没办法只会下板。
大家学习过程可以这样直接下板,假如说进公司,硬件部门的板卡未设计好之前,难道大家要告诉我,等他们弄好之后暂态开始逻辑方面的设计吗?所以,作者请大家一定要养成没有板卡,通过测试分析可以保证下板就能实现的好习惯。今天作者就给大家结合本节的内容,讲解测试脚本的编写,今天我们的测试脚本是一个仿真模型。测试脚本如下图:
由上图知道本节内容的测试脚本由两部分组成:被测试部分和仿真模型;被测试部分我们已将前面已经讲完了,下面给大家讲解仿真模型如何编写.
以上就是本节内容的仿真模型代码部分,可能刚开始大家不习惯这么做觉得太繁琐了;但是这样写的结果大大提高了你的仿真正确性,而且模拟的行状态比你用延迟那样让某一行有效要高效的多准确性高得多。下面贴上整个仿真的测试顶层代码:
经过上面的编写整个工程的所有代码都给大家呈现出来了,接下来我们可以进行仿真了
下面是仿真结果图:
通过观察可以见到当按键检测完成信号Key_Flag有效时,Key_Board_Row_r寄存器中行值为1110,此时的列值Col_Tmp为0001,检测结果Key_Value_tmp为:1110_0001,通过译码结果Key_Value为第一行第一列所以键值为“0000”,同理可以分析其他键值情况。
下面我们再通过另开一种方法也是进入工作中比较常用的一种验证方法,逻辑分析仪。在使用逻辑分析仪之前我们需要对工程中的输入输出端口分配对应的管脚如下图所示:
分配完管脚之后进行全编译,因为逻辑分析仪为在线可调试下板之前需要连接电路,下图是电路的正确连接方法: 可能有些读者会说对芯航线开发板不熟悉该怎么能准确无误的将矩阵键盘有对应的IO连接起来呢。下面作者给大家讲一种方法,只要你知道键盘的一个IO管脚可以通过它在原理图里面找到对应的位置然后对照的原理图上的标号去板子上寻找对应的位置。下图是键盘对原理图的连接方式: 经过上述描述,硬件的环境搭建完毕,下面就是使用Quartus ii里面SignalTap进行在线调试抓取实时数据分析波形。
观察逻辑分析仪抓取到的信号可以见到当按键检测完成信号Key_Flag有效时,Key_Board_Row_r寄存器中行值为0010,此时的列值Col_Tmp为0010,检测结果Key_Value_tmp为:0010_0010,通过译码结果Key_Value为第一行第一列所以键值为“0101”,同理可以分析其他键值情况。
目标板验证许多读者到这可能有些烦躁了,希望大家能静下心来一步一步跟着作者的步伐。下面作者就给大伙展示出我们这节课最终的实验效果图:
其中,4个LED灯从左到右依次为LED0到LED3,状态为亮灭亮灭,对应的4位驱动IO逻辑由低到高为0101,与按键值从低到高的0101一致 总结及分析问题本次试验的难点主要是状态转移图的设计和仿真模型的设计,这两块相对比较困难一些。 还有个问题就是在下板时如何通过查看原理图去链接电路等,还有就是当出现错误如何去定位解决它。比如说作者在做这个实验室出现了这样一个问题“某个按键按下板子掉电程序流失LED状态不对”这个是什么原因造成的?首先我先拆除硬件然后再去进行Modelsim的仿真,分析波形发现波形是正确的,下板就不对。我开始怀疑是不是管脚分配不正确导致的,仔细对照管脚分配表发现关键分配也是正确的,这下我就开始怀疑是不是键盘的位置插的不对,我找到一个键盘的IO然后去原理图上查找和这个IO相连的GPIO,最后发现是自己把键盘插错地方了,结果导致上述情况。最终同过更改键盘位置,一切问题迎刃而解。 课后作业今后每节课讲授完毕,作者都会给大家布置2个小作业,希望大家可以积极独立去完成。 作业一: 将矩阵键盘的键值显示到数码管上。 要求: 1、 完成整体架构框图设计; 2、 完成状态转移图的设计; 3、 自己独立完成成个工程代码的编写; 4、 进行逻辑验证(ps:即modelsim的仿真)
作业二: 制作简单的计算器 设计要求: 1、 完成整体架构框图设计; 2、 完成状态转移图的设计; 3、 自己独立完成成个工程代码的编写; 4、 进行逻辑验证(ps:即modelsim的仿真)。 功能要求: 1、 使用矩阵键盘、数码管; 2、 只做简单的加减乘除运算; 温馨提示:由于计算只用到0~9这几个键,那么剩下的A~F可以用作符号键。 要将计算结果正确显示到数码管上就需要用二进制转BCD。
六月飞鱼 芯航线电子工作室
|