集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 11061|回复: 24

FPGA初级课程第十一讲 键盘矩阵

[复制链接]
lcytms 发表于 2016-11-11 16:18:39 | 显示全部楼层 |阅读模式
FPGA初级课程
第十一讲 键盘矩阵

Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:键盘矩阵。
本节课我先简要地介绍一下键盘矩阵的物理原理,然后实际演示一下键盘矩阵驱动逻辑电路的建模与仿真,我们还要结合第四讲的数码管一起编写一个完整的演示逻辑,并下板查看实际效果。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:23:20 | 显示全部楼层
打开《ZX_NO3.pdf》文件,我们看一下矩阵键盘的电路图。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:27:55 | 显示全部楼层
我们打开至芯科技编写的《40.炼狱传奇-矩阵键盘之战.pdf》文档。


在使用按键的时候,如果按键不多的话,我们可以直接按键与FPGA相连接,但是如果按键比较多的时候,如何还继续使用直接按键与FPGA相连接的话,所会大量增加FPGA端口的消耗,为了减少FPGA端口的消耗,我们可以把按键设计成矩阵的形式,就如下图所示:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:29:51 | 显示全部楼层
由上图可以知道,矩阵键盘的行row(行)与col(列)的交点,都是通过一个按键来相连接。
传统的一个按键一个端口的方法,若要实现16个按键,则需要16个端口。
而现在这个矩阵键盘的设计,16个按键,仅仅需要8个端口,如果使用16个端口来做矩阵键盘的话,可以识别64个按键,端口的利用率远远比传统的设计好的多。
所以如果需要的按键少的话,可以选择传统的按键设计,如果需要的按键比较多的话,可以采用这种矩阵键盘的设计。
而我们现在就以扫描法为例来介绍矩阵键盘的工作原理。


首先col(列)是FPGA给矩阵键盘输出的扫描信号,而row(行)是矩阵键盘反馈给FPGA的输入信号,用于检测哪一个按键被按下来,如下图所示:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:31:43 | 显示全部楼层
详细如上图所示,FPGA给出扫描信号COL[3:0],COL = 4’b0111,等下一个时钟周期COL = 4’b1011,再等下一个时钟周期COL =4’b1101,再等下一个时钟周期COL = 4’b1110,再等下一个时钟周期COL = 4’b0111,COL就是这样不断循环,给矩阵键盘一个低电平有效的扫描信号。
当FPGA给矩阵键盘COL扫描信号的同时,FPGA也要在检测矩阵键盘给FPGA的的反馈信号ROW。
举个例子,假若矩阵键盘中的9号按键被按下了:

        当COL = 4’b0111,ROW = 4’b1111;
        当COL = 4’b1011,ROW = 4’b1111;
        当COL = 4’b1101,ROW = 4’b1011;
        当COL = 4’b1110,ROW = 4’b1111;

有人问,为什么当COL = 4’b1101的时候,ROW = 4’b1011呢?
我们现在就以矩阵键盘的电路来分析一下这个原因,如下图所示:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:42:35 | 显示全部楼层
当9号按键被按下的时候,9号按键的电路就会被导通,扫描电路COL开始扫描,当扫描到COL[1]的时候,由于9号按键的电路被导通了,COL[1]的电压等于ROW[2]的电压。
所以会出现当COL = 4’b1101的时候ROW = 4’b1011。
然后我们就可以利用这一种现象,来设计一个识别按键的电路。
 楼主| lcytms 发表于 2016-11-11 16:43:28 | 显示全部楼层
矩阵键盘的扫描原理既然已经清楚,我们下面来进行系统设计。
命名逻辑为key_pad。
架构图如下所示。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:44:57 | 显示全部楼层
加上数码管数据预处理模块pre_seg7和数码管模块seg7后,架构图如下。
其中,数码管数据预处理模块pre_seg7将键盘矩阵模块key_pad输出的1位按键数补充到显示的6位数的低位上,高位左移。
比如,数码管原显示012345,如果键盘按下6,则数码管显示变为123456。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:45:40 | 显示全部楼层
本帖最后由 lcytms 于 2016-11-11 16:56 编辑

先从键盘矩阵模块key_pad.v做起吧!
新建工程文件夹key_pad。
新建key_pad.v文件。
module key_pad (clk, rst_n, col, row, data, flag);

        input clk, rst_n;
        input [3:0] row;
       
        output reg [3:0] col;
        output reg [3:0] data;
       
        output reg flag;
       
        reg [31:0] count;
        wire flag1ms;
       
        parameter T1ms = 50_000;         // 1ms/20ns =50_000
       
        always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                                begin
                                        count <= 0;
                                end
                        else
                                begin
                                        if (count < T1ms - 1)
                                                begin
                                                        count <= count + 1;
                                                end
                                        else
                                                begin
                                                        count <= 0;
                                                end
                                end
                end
       
        assign flag1ms = (count == T1ms - 1) ? 1'b1 : 1'b0;

        reg [7:0] state;
        reg [7:0] cnt_key;
       
        reg [7:0] row_col;
       
        parameter NUM_KEY = 20;

        always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                                begin
                                        col <= 4'b0000;
                                        state <= 0;
                                        cnt_key <= 0;
                                        flag <= 0;
                                        row_col <= 8'b1111_0000;
                                end
                        else
                                begin
                                        case (state)
                                        0        :        begin
                                                                if (!flag1ms)
                                                                        begin
                                                                                state <= 0;
                                                                        end
                                                                else
                                                                        begin
                                                                                if (row == 4'b1111)                //no key pressed
                                                                                        begin
                                                                                                state <= 0;
                                                                                        end
                                                                                else                //key pressed
                                                                                        begin
                                                                                                if (cnt_key < NUM_KEY - 1)
                                                                                                        cnt_key <= cnt_key + 8'b1;
                                                                                                else
                                                                                                        begin
                                                                                                                cnt_key <= 0;
                                                                                                                col <= 4'b1110;
                                                                                                                state <= 1;
                                                                                                        end
                                                                                        end
                                                                        end               
                                                        end
                                                       
                                        1        :        begin
                                                                if (!flag1ms)
                                                                        begin
                                                                                state = 1;
                                                                        end
                                                                else
                                                                        begin
                                                                                if (row == 4'b1111)                //no key pressed
                                                                                        begin
                                                                                                col <= {col[2:0], col[3]};
                                                                                        end
                                                                                else                //key pressed
                                                                                        begin
                                                                                                row_col <= {row, col};
                                                                                                flag <= 1;
                                                                                                col <= 4'b0000;
                                                                                                state <= 2;
                                                                                        end
                                                                        end               
                                                        end
                                                       
                                        2        :        begin
                                                                if (!flag1ms)
                                                                        begin
                                                                                flag <= 0;
                                                                                state = 2;
                                                                        end
                                                                else
                                                                        begin
                                                                                if (row != 4'b1111)                //key unreleased
                                                                                        begin
                                                                                                state = 2;
                                                                                        end
                                                                                else                //key released
                                                                                        begin
                                                                                                if (cnt_key < NUM_KEY - 1)
                                                                                                        cnt_key <= cnt_key + 8'b1;
                                                                                                else
                                                                                                        begin
                                                                                                                cnt_key <= 0;
                                                                                                                col <= 4'b0000;
                                                                                                                state <= 0;
                                                                                                        end
                                                                                        end
                                                                        end               
                                                        end
                                       
                                        default        :        state <= 0;

                                        endcase
                                end
                end
       
        always @ (*)
                begin
                        if (!rst_n)
                                begin
                                        data <= 4'h0;
                                end
                        else
                                begin
                                        case (row_col)
                                        8'b1110_1110        :        data <= 4'h0;
                                        8'b1110_1101        :        data <= 4'h1;
                                        8'b1110_1011        :        data <= 4'h2;
                                        8'b1110_0111        :        data <= 4'h3;
                                        8'b1101_1110        :        data <= 4'h4;
                                        8'b1101_1101        :        data <= 4'h5;
                                        8'b1101_1011        :        data <= 4'h6;
                                        8'b1101_0111        :        data <= 4'h7;
                                        8'b1011_1110        :        data <= 4'h8;
                                        8'b1011_1101        :        data <= 4'h9;
                                        8'b1011_1011        :        data <= 4'hA;
                                        8'b1011_0111        :        data <= 4'hB;
                                        8'b0111_1110        :        data <= 4'hC;
                                        8'b0111_1101        :        data <= 4'hD;
                                        8'b0111_1011        :        data <= 4'hE;
                                        8'b0111_0111        :        data <= 4'hF;
                                        default                        :        data <= 4'h0;    //no key pressed
                                        endcase
                                end
                end
               
endmodule

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
 楼主| lcytms 发表于 2016-11-11 16:57:41 | 显示全部楼层
本帖最后由 lcytms 于 2016-11-11 17:03 编辑

进行分析综合检查。
编写Testbench。
新建key_pad_tb.v文件。
`timescale 1ns/1ps

module key_pad_tb;
       
        reg clk, rst_n;
        reg [3:0] row;
       
        wire [3:0] col;
        wire [3:0] data;
       
        wire flag;
       
        reg [4:0] key;
       
        key_pad #(.T1ms(50), .NUM_KEY(20))
                dut (.clk(clk), .rst_n(rst_n), .col(col), .row(row), .data(data), .flag(flag));
       
        initial
                begin
                        clk = 1;
                        rst_n = 0;
                        key = 5'h10;
                        row = 4'b1111;
                                               
                        #200.1
                        rst_n = 1;
                        key = 5'h09;
                        #25_000
                        key = 5'h10;
                        #50_000

                        key = 5'h0a;
                        #30_000
                        key = 5'h10;
                        #50_000
                       
                        key = 5'h0b;
                        #45_000
                        key = 5'h10;
                        #50_000
                       
                        $stop;
                end

        always @ (*)
                case (key)
                5'h10        :        row = 4'b1111;                                                // no key pressed
                5'h00        :        row = {1'b1, 1'b1, 1'b1, col[0]};
                5'h01        :        row = {1'b1, 1'b1, 1'b1, col[1]};
                5'h02        :        row = {1'b1, 1'b1, 1'b1, col[2]};
                5'h03        :        row = {1'b1, 1'b1, 1'b1, col[3]};
                5'h04        :        row = {1'b1, 1'b1, col[0], 1'b1};
                5'h05        :        row = {1'b1, 1'b1, col[1], 1'b1};
                5'h06        :        row = {1'b1, 1'b1, col[2], 1'b1};
                5'h07        :        row = {1'b1, 1'b1, col[3], 1'b1};
                5'h08        :        row = {1'b1, col[0], 1'b1, 1'b1};
                5'h09        :        row = {1'b1, col[1], 1'b1, 1'b1};
                5'h0a        :        row = {1'b1, col[2], 1'b1, 1'b1};
                5'h0b        :        row = {1'b1, col[3], 1'b1, 1'b1};
                5'h0c        :        row = {col[0], 1'b1, 1'b1, 1'b1};
                5'h0d        :        row = {col[1], 1'b1, 1'b1, 1'b1};
                5'h0e        :        row = {col[2], 1'b1, 1'b1, 1'b1};
                5'h0f        :        row = {col[3], 1'b1, 1'b1, 1'b1};
                default        :        row = 4'b1111;                                        // no key pressed
                endcase
       
        always #10 clk = ~clk;

endmodule

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|fpga论坛|fpga设计论坛 ( 京ICP备20003123号-1 )

GMT+8, 2024-12-23 23:44 , Processed in 0.067580 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表