关于矩阵键盘扫描的理解
来源:互联网 发布:网络数据传输 编辑:程序博客网 时间:2024/05/20 03:41
设计思路:
要理解扫描原理,就必须重点理解这一点:
我们知道row【3:0】作为FPGA的输入口,而col【3:0】作为输出口,当没有键按下时,row为上拉为高电平(因为
IC的输入口阻抗很大,导致上拉电阻两侧几乎没有电流流过,就没有形成压降,所以上拉电阻两侧电压相等=3.3V左右,为高电平),而在初始状态col作为输
出,处于输出低电平状态(col=4‘b0000),当键被按下时,只有当col输出有低电平时,row【3:0】才有可能有低电平输入。因为如果键被按下
则row【3:0】与col【3:0】是接通了的,所以col为低,则row才可能为低,相反,如果col为高,即使键被按下,row也为高。这为后面扫描原理
形成判断具体哪个按键值有关。
行判断: 由4*4矩阵键盘的原理图我们可知:行输入信号row[3:0]在上拉电阻的作用下,初始状态保持高电平,当有键被按下的时候才会变成低电平,而且对于4*4的
矩阵一行中只要有一个键被按下(且在按键被按下那一行的COL输出为0时),则整行电平都会被拉低(如果col为1 就算按键按下row也不会为低) ,所以我们可以根据
row[3:0]这4个引脚信号的高低,判定具体哪一行有键被按下。(因为初始状态col为低电平4’b0000).
如:假设第一行被按下,则引脚信号即为0111;
假设第二行被按下,则引脚信号即为1011;
假设第三行被按下,则引脚信号即为1101;
假设第四行被按下,则引脚信号即为1110;
列判断: 由上可知,我们已经得到了行的键值,现在只需要确定列的键值col[3:0],则可以确定具体的输出键值和具体那个键被按下。 所以,我们对列进行编码,我们假设对列进行扫描,第一列。。第二列。。第三列。。第四列,一旦对那一列扫描,我们就将那一列设 为低电平(设为低电平,假设第二列第二行的键被按下,那么由行引脚信号可知,row为1011,现在开始扫描列了,扫描第一列,则col设为0111,),其余三列为高点平。 如:假设对第一列进行扫描,则列键值可编码为0111; 假设对第二列进行扫描,则列键值可编码为1011; 假设对第三列进行扫描,则列键值可编码为1101; 假设对第四列进行扫描,则列键值可编码为1110; 具体扫描如下:1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 当用0111来扫描第一列时, 如果第一列有键被按下,那么row的值肯定就不会再是4‘b1111(因为第一列有四行,且第一列的col值全为0,所以当有键被按下时, 四行之中的每一行row与第一列col(全为0)接通,所以检测到row的值不会为4’b1111,有可能是4‘b0111,4'b1011,4'b1101,4'b1110),而col为0111,将键值保留下来, 所以就可以确定具体哪个键被按下了。 如果第一列没有键按下,那么row的值肯定就会是4’b1111,为啥呢?(因为如果没有键被按下,就算你col的值为0,但是你的row与col并没有接通,所以 row不会存在低电平,而你后面的键(如上述第二行第二列的键按下为0)就算被按下了,但是col这个时候却为高电平1,所以就算按下,row也不会有低电平输入,故怎么检测row也还是4'b1111), 所以第一列没有键按下时,则转入第二列扫描,以此类推。。。。。。。。(后面状态机就是根据此原理写的)。 由以上可知,行,列的键值我们都已经确定了,则可进行译码输出键值了。 编码表如下: 行键值 列键值 译码输出键值 0 1 1 1 0 1 1 1 1
第一行 0 1 1 1 1 0 1 1 2
0 1 1 1 1 1 0 1 3
0 1 1 1 1 1 1 0 4
1 0 1 1 0 1 1 1 5
第二行 1 0 1 1 1 0 1 1 6
1 0 1 1 1 1 0 1 7
1 0 1 1 1 1 1 0 8
1 1 0 1 0 1 1 1 9
第三行 1 1 0 1 1 0 1 1 A
1 1 0 1 1 1 0 1 B
1 1 0 1 1 1 1 0 C
1 1 1 0 0 1 1 1 D
第四行 1 1 1 0 1 0 1 1 E
1 1 1 0 1 1 0 1 F
1 1 1 0 1 1 1 0 G
具体代码如下:
module 4*4_key_design ( input clk, //50M主时钟 input rst_n, input [3:0] row, //行输入键值 output reg [3:0] col,//列输出键值 output reg [3:0] key_value //译码输出键值 ); //按键有个消抖的过程(经验是10ms左右),我们取延迟20ms,因为始终50M,就是20ns一个周期,那么20ms也就 20*10^6/20=100000个时钟周期; 所以设置计数器; reg [19:0] delay_cnt; parameter delay_20ms=1000000; wire delay_20ms_flag; always@(posedge clk or negedge rst_n) if(!rst_n) delay_cnt<=0; else begin if(delay_cnt<delay_20ms) delay_cnt<=delay_cnt+1'b1; else delay_cnt<=0; end assign delay_20ms_flag=(delay_cnt==delay_20ms)?1'b1:1'b0; // 因为我们知道,没有键被按下时,[3:0] row 是全部为高电平,即1111; 所以利用状态机来判断; 三段式状态机: reg [2:0] current_state; reg [2:0] next_state; parameter key_idle=3'd0, key_panduan=3'd1, col_one=3'd2, col_two=3'd3, col_three=3'd4,col_fore=3'd5; parameter latch_key_value=3'd6, open_key_value=3'd7; // 第一段:给于状态转换逻辑(时序逻辑)always@(posedge clk or negedge rst_n) if(!rst_n) current_state<=key_idle; else begin if(delay_20ms_flag) current_state<=next_state; else current_state<=current_state; end // 第二段:状态转换(组合逻辑)always@(*) begin next_state=key_idle; case(current_state) key_idle: begin if(row!=4'b1111) // 如果有键被按下 next_state=key_panduan; //转移到下个状态判断是真按下了还是误触发 else next_state=key_idle; end key_panduan: //状态的跳转有个20ms的延迟,所以刚好滤出抖动的情况 begin if(row!=4'b1111) // 也就是说滤出抖动之后如果还是不等于4'b1111(初始状态),则表明真的有键被按下,不是误触发 next_state=col_one; //则可以进入列扫描,去找具体的那个键被按下了。 else next_state=key_idle; //但是如如果滤出抖动之后等于4'b1111,则表明是误触发,就回到key_idle,继续等待 end col_one: begin if(row!=4'b1111) next_state=latch_key_value; //如果在列扫描期间,仍然检测到有键按下,则保留键值 else next_state=col_two; //如果没有键被按下,则扫描第二列 end col_two: begin if(row!=4'b1111) next_state=latch_key_value; //如果在列扫描期间,仍然检测到有键按下,则保留键值 else next_state=col_three; //如果没有键被按下,则扫描第三列 end col_three: begin if(row!=4'b1111) next_state=latch_key_value; //如果在列扫描期间,仍然检测到有键按下,则保留键值 else next_state=col_fore; //如果没有键被按下,则扫描第四列 end col_fore: begin if(row!=4'b1111) next_state=latch_key_value; //如果在列扫描期间,仍然检测到有键按下,则保留键值 else next_state=key_idle; //如果还没有键被按下,则说明检测有错误,返回初始状态 end latch_key_value: begin if(row!=4'b1111) next_state=open_key_value; //如果在保存键值期间还有有键按下,则准备跳转到松开按键状态 else next_state=key_idle; //如果没有按键按下,则回到初始状态 end open_key_value: //20ms消抖 begin if(row!=4'b1111) next_state=open_key_value; //如果还有键,说明还没松开,继续等待20ms释放 else next_state=key_idle; //松完了,回到初始状态 end endcase end 第三段输出读者自己写了。。。。。。。
- 关于矩阵键盘扫描的理解
- 关于P口矩阵键盘扫描的零的作用
- 矩阵键盘的扫描接口函数
- FPGA矩阵键盘的扫描方法
- 4*4矩阵键盘的扫描原理
- 矩阵键盘扫描
- 矩阵键盘扫描程序
- 矩阵键盘扫描程序
- 矩阵键盘中断扫描
- 矩阵键盘中断扫描
- 矩阵键盘终端扫描
- 矩阵键盘行列扫描
- 个人感觉很好的键盘矩阵键盘扫描程序
- 矩阵键盘扫描显示键值
- C51矩阵键盘扫描程序
- 单片机,矩阵键盘扫描驱动
- 51单片机矩阵键盘扫描
- 矩阵键盘扫描实验报告
- php kahana widget
- 设计模式学习—外观模式(Facade Design Pattern)
- 快速排序
- 深入PHP内核(一)——弱类型变量原理探究
- Android 支付宝支付
- 关于矩阵键盘扫描的理解
- x264源代码简单分析:滤波(Filter)部分
- java线程同步之条件对象
- httpMessageConverter
- python之模块
- css基础知识
- JQuery知识点
- Go实战--go语言操作MySQL数据库(go-sql-driver/mysql)
- Java语句