集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 2239|回复: 1

FPGA快速入门-矩阵键盘

[复制链接]
lxw 发表于 2019-6-22 17:49:48 | 显示全部楼层 |阅读模式
FPGA快速入门-矩阵键盘键盘分编码键盘和非编码键盘。键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或键值的称为编码键盘,如计算机键盘。而靠软件编程来识别的称为非编码键盘。
在一般嵌入式应用中,用的最多的是非编码键盘,也有用到编码键盘的。非编码键盘又分为独立键盘和行列式(又称为矩阵式)键盘。所谓独立式键盘,即嵌入式CPU(或称MCU)的一个GPIO口对应一个按键输入,这个输入值的高低状态就是键值。矩阵键盘用于采集键值的GPIO是复用的,一般分为行和列采集,例如4*4矩阵键盘就只需要行列各4个按键就可以了,矩阵键盘的控制较独立键盘要复杂得多,本实验未涉及,所以对其原理不做详细介绍。
         独立按键一般有2组管脚,虽然市面上我们常常看到有4个管脚的按键,但它们一般是两两导通的,这2组管脚在按键未被按下时是断开的,在按键被按下时则是导通的。基于此原理,我们一般会把按键的一个管脚接地,另一个管脚上拉到VCC,并且也连接到GPIO。这样,在按键未被按下时,GPIO的连接状态为上拉到VCC,则键值为1;按键被按下时,GPIO虽然还是上拉到VCC,但同时被导通的另一个管脚拉到地了,所以它的键值实际上是0。
我们的zx1开发板上有一组4*4矩阵键盘。通过P12的PIN1-2短接时,其实S1/S2/S3/S4可以作为独立按键使用,它的一端接地,另一端在上拉的同时连接到FPGA的I/O口。当I/O口的电平为高(1)时,说明按键没有被按下,当I/O口的电平为低(0)时,说明按键被按下了。在本实例中,我们不再只局限于独立按键这么low的应用了,这里我们将要把所有16个按键都使用起来,实现我们真正的矩阵按键功能。

图1矩阵按键原理图
接续上面的原理图,我们来看看矩阵按键的键值如何获得。通常,我们将这个矩阵按键分为两组信号,即列信号和行信号。列信号作为FPGA的输入信号,行信号作为FPGA的输出信号。
若FPGA输出的行信号为高电平时,无论是否有按键被按下,列信号输入到FPGA的电平始终为高电平,这是无法实现任何的矩阵按键值采集的;若FPGA输出的行信号为低电平时,没有按键按下,那么列信号会保持高电平(因为有上拉),有键按下时,则由于按键将行、列信号短接,那么列信号的电平会由于行信号而被拉低,通过这种方式,我们就可以达到键值的检测。
但是,可能大家还有疑惑,4个行信号若同时拉低,那么任意一个4X4按键被按下,所有的列信号也都会拉低啊,这只能判断是否有按键被按下,具体哪一个按键被按下就不得而知了。确实如此,解决办法也很简单,我们在同一时刻只能拉低4个行信号中的一个,那么它就将按键状态定位到具体的行,这样就如同独立按键一样可以直接定位到这一行按键中的哪个按键被按下了。在实现上,我们会让4个行信号循环的拉低,同一时刻有且只有一个行信号输出为低电平,这就是我们所说的“键盘扫描”原理。
本实例实现矩阵按键值的采集(即判断16个按键的哪个被按下了),然后通过数码管显示按键值(显示值为16进制的0-F),数码管最低位显示最后一次的键值,高3位显示之前的值,即每按下一次按键,数码管的键值右移一位。
         如图2所示,用8个信号检测16个按键值,有点难度,不过原理上一节我们已经讲过。从功能上,我们首先对4个作为输入的列信号进行按键消抖处理,然后依次输出不同的行信号值,以此找到有键按下时的特殊列信号值,这样便能采集键值,送往数码管显示。

图2 矩阵按键扫描实例功能框图
具体代码实现有:
module keyboard4x4_drive (clk, rst_n, keyboard4x4_row, keyboard4x4_col, keyboard4x4_num, flag_keyboard4x4);

        input wire clk;
        input wire rst_n;         
        input wire [3:0] keyboard4x4_row;
       
        output reg [3:0] keyboard4x4_col;
        output reg [3:0] keyboard4x4_num;
        output reg flag_keyboard4x4;

       
        parameter        T_5ms = 250_000;
        localparam        S0          = 6'b000001;
        localparam        S1          = 6'b000010;
        localparam        S2          = 6'b000100;
        localparam        S3          = 6'b001000;
        localparam        S4          = 6'b010000;
        localparam        S5          = 6'b100000;
       
        reg                                [17:0]                cnt_5ms;
        reg                                [5:0]                c_state;
        reg                                [5:0]                n_state;
        reg                                [7:0]                row_col;
        reg                                [3:0]                reg_row [1:0];
        reg                                                        flag;
       
        always @ (posedge clk)
        begin
                reg_row[0] <= keyboard4x4_row;
                reg_row[1] <= reg_row[0];
        end
       
        always @ (posedge clk)
        begin
                if (rst_n == 0)
                        c_state <= S0;
                else
                        c_state <= n_state;
        end
       
        always @ (*)
        begin
                case (c_state)
                        S0                :                if (reg_row[1] == 4'hf)
                                                                n_state = S0;
                                                        else
                                                                n_state = S1;
                       
                        S1                :                if (reg_row[1] == 4'hf)
                                                                n_state = S0;
                                                        else
                                                                if (cnt_5ms >= T_5ms - 1)
                                                                        n_state = S2;
                                                                else
                                                                        n_state = S1;
                                                                       
                        S2                :                        n_state = S3;
                       
                        S3                :                        n_state = S4;
                               
                        S4                :               
                                                        if (reg_row[1] == 4'hf)
                                                                n_state = S2;
                                                        else
                                                                n_state = S5;
                                                               
                        S5                :                if (reg_row[1] != 4'hf)
                                                                n_state = S5;
                                                        else
                                                                if (cnt_5ms >= T_5ms - 1)
                                                                        n_state = S0;
                                                                else
                                                                        n_state = S5;
                                                                       
                        default        :                                n_state = S0;
                endcase
        end
       
        always @ (posedge clk)
        begin
                if (rst_n == 0)
                        cnt_5ms <= 0;
                else
                        case (c_state)
                                S0                        :                cnt_5ms <= 0;
                                S1                        :        if (reg_row[1] == 4'hf)
                                                                        cnt_5ms <= 0;
                                                                else
                                                                        if (cnt_5ms >= T_5ms - 1)
                                                                                cnt_5ms <= 0;
                                                                        else
                                                                                cnt_5ms <= cnt_5ms + 1'b1;
                                S2                        :                cnt_5ms <= 0;
                                S3                        :                cnt_5ms <= 0;
                                S4                        :                cnt_5ms <= 0;
                                S5                        :        if (reg_row[1] != 4'hf)
                                                                        cnt_5ms <= 0;
                                                                else
                                                                        if (cnt_5ms >= T_5ms - 1)
                                                                                cnt_5ms <= 0;
                                                                        else
                                                                                cnt_5ms <= cnt_5ms + 1'b1;
                                default                :                cnt_5ms <= 0;
                        endcase
        end
       
        always @ (posedge clk)
        begin
                if (rst_n == 0)
                        keyboard4x4_col <= 0;
                else
                        case (c_state)
                                S0         :                keyboard4x4_col <= 4'b0000;
                                S1         :        if (reg_row[1] == 4'hf)
                                                         keyboard4x4_col <= 4'b0000;
                                                 else
                                                         if (cnt_5ms >= T_5ms - 1)
                                                                 keyboard4x4_col <= 4'b0111;
                                                         else
                                                                 keyboard4x4_col <= 4'b0000;
                                S2         :                keyboard4x4_col <= keyboard4x4_col;
                                 
                                S3         :                keyboard4x4_col <= keyboard4x4_col;
                                S4         :        if (reg_row[1] == 4'hf)
                                                         keyboard4x4_col <= {keyboard4x4_col[0],keyboard4x4_col[3:1]};
                                                 else
                                                         keyboard4x4_col <= 4'b0000;
                                S5         :                keyboard4x4_col <= 4'b0000;
                                default         :  keyboard4x4_col <= 4'b0000;
                        endcase
        end
       
        always @ (posedge clk)
        begin
                if (rst_n == 0)
                        row_col <= 0;
                else
                        if (c_state == S4 && reg_row[1] != 4'hf)
                                row_col <= {reg_row[1], keyboard4x4_col};
                        else
                                row_col <= row_col;
        end
       
        always @ (posedge clk)
        begin
                if (rst_n == 0)
                        flag <= 0;
                else
                        if (c_state == S4 && reg_row[1] != 4'hf)
                                flag <= 1;
                        else
                                flag <= 0;
        end

        always @ (posedge clk) flag_keyboard4x4 <= flag;
       
        always @ (posedge clk)
        begin
                if (rst_n == 0)
                        keyboard4x4_num <= 0;
                else
                        case (row_col)
                                8'b1110_1110        :                keyboard4x4_num <= 0;
                                8'b1110_1101        :                keyboard4x4_num <= 1;
                                8'b1110_1011        :                keyboard4x4_num <= 2;
                                8'b1110_0111        :                keyboard4x4_num <= 3;
                               
                                8'b1101_1110        :                keyboard4x4_num <= 4;
                                8'b1101_1101        :                keyboard4x4_num <= 5;
                                8'b1101_1011        :                keyboard4x4_num <= 6;
                                8'b1101_0111        :                keyboard4x4_num <= 7;
                               
                                8'b1011_1110        :                keyboard4x4_num <= 8;
                                8'b1011_1101        :                keyboard4x4_num <= 9;
                                8'b1011_1011        :                keyboard4x4_num <= 10;
                                8'b1011_0111        :                keyboard4x4_num <= 11;
                               
                                8'b0111_1110        :                keyboard4x4_num <= 12;
                                8'b0111_1101        :                keyboard4x4_num <= 13;
                                8'b0111_1011        :                keyboard4x4_num <= 14;
                                8'b0111_0111        :                keyboard4x4_num <= 15;
                               
                                default                        :                keyboard4x4_num <= 0;
                        endcase
        end
       
endmodule

本帖子中包含更多资源

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

x
雷磊 发表于 2019-8-9 14:10:48 | 显示全部楼层
FPGA快速入门-矩阵键盘
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

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

QQ|小黑屋|手机版|Archiver|集成电路技术分享 ( 京ICP备20003123号-1 )

GMT+8, 2024-4-26 06:03 , Processed in 0.070197 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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