打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
一天一个设计实例-矩阵开关的应用

矩阵键盘又叫行列式键盘。用带IO口的线组成行列结构,按键设置在行列的交点上。例如用4×4的行列式结构可以构成16个键的键盘。这样,当按键数量平方增长时,I/O口只是线性增长,这样就可以节省I/O口。矩阵键盘的原理图如5‑18所示:

518 矩阵键盘的原理图

按键设置在行列线交叉点,行列线分别连接到按键开关的两端。列线通过上拉电阻接3.3V电压,即列线的输出被钳位到高电平状态。判断键盘中有无按键按下式通过行线送入扫描线好然后从列线读取状态得到的。其方法是依次给行线送低电平,检查列线的输入。如果列线全是高电平,则代表低电平信号所在的行中无按键按下;如果列线有输入为低电平,则代表低电平信号所在的行和出现低电平的列的交点处有按键按下。

一个完整的键盘控制程序应解决以下任务:

1)检测有无按键按下

2)有键按下,在无硬件去抖得情况下,应有软件延时除去抖动影响

3)键扫描程序

4)将键编码转换成相应建值

接下来看下整个模块结构:

519 矩阵键盘模块结构

59 矩阵键盘(Key4x4_module.v)模块间信号定义

模块间信号

管脚

传输方向

作用/说明

Pin_Out[3:0]

key4x4funcmod_module.v模块传输给smg_interface.v

Pin_Out值0~15代表16个按键KEY0~KEY15

时序

没有特殊要求。




510 矩阵键盘(Key4x4_module.v)顶层模块信号定义

顶层模块

输入管脚

作用/说明

输出管脚

作用/说明

key_in_y

key_out_x

key_in_y

输入矩阵键盘的列信号(即带上拉信号的列信号)

       key_out_x,        输出矩阵键盘的行信号(不带上拉信号列)      

数码管

数码管显示键值

时序

没有特殊要求。





5‑19上是一个简单的点击与长按模块。设计的方法主要是由“按键功能模块”和“LED显示模块”组合合成,“按键功能模块”主要做“点击”和“长按击”检测。

“按键功能模块”中电平检测思路详见2.3.4实用UART传输FPGA实现节介绍。设计的思路如图所示:

520 矩阵键盘设计框图

整个模块设计思路如下:

先第一行输出 0,检查列线是否非为高;

再第二行输出 0,检查列线是否非为高;

再第三行输出 0,检查列线是否非为高;

再第三行输出 0,检查列线是否非为高;

如果某行输出 0 时,查到列线非全高,则该行有按键按下;

根据第几行线输出 0 与第几列线读入为 0,即可判断在具体什么位置的按键按下。

整个代码如下:

代码56 矩阵键盘设计代码

1.//****************************************************************************//  

2.//# @Author: 碎碎思  

3.//# @Date:   2019-06-09 03:52:48  

4.//# @Last Modified by:   zlk  

5.//# @WeChat Official Account: OpenFPGA  

6.//# @Last Modified time: 2019-06-10 19:40:30  

7.//# Description:   

8.//# @Modification History: 2019-06-10 19:40:30  

9.//# Date                By             Version             Change Description:   

10.//# ========================================================================= #  

11.//# 2019-06-10 19:40:30  

12.//# ========================================================================= #  

13.//# |                                                                       | #  

14.//# |                                OpenFPGA                               | #  

15.//****************************************************************************//  

16.`timescale 1ns / 1ps  

17.module key4x4funcmod_module   

18.(  

19.   CLOCK,   

20.    RST_n,            // 开发板上复位按键  

21.    key_in_y,         // 输入矩阵键盘的列信号(KEY0~KEY3)  

22.    key_out_x,        // 输出矩阵键盘的行信号(KEY4~KEY7)    

23.   LED,   

24.    Pin_Out           // 输出LED灯,用于矩阵键盘板上16个LED(LED1~LED16)  

25.      

26.);  

27.  

28.//========================================================  

29.// PORT declarations  

30.//========================================================                        

31.input        CLOCK;   

32.input        RST_n;  

33.input  [3:0] key_in_y;  

34.output reg [3:0] key_out_x;  

35.output [3:0] Pin_Out;  

36.output reg[3:0] LED;  

37.  

38.//寄存器定义  

39.reg [19:0] count;  

40.  

41.//==============================================  

42.// 输出矩阵键盘的行信号,20ms扫描矩阵键盘一次,采样频率小于按键毛刺频率,相当于滤除掉了高频毛刺信号。  

43.//==============================================  

44.always @(posedge CLOCK or negedge RST_n)     //检测时钟的上升沿和复位的下降沿  

45.begin  

46.   if(!RST_n) begin               //复位信号低有效  

47.      count <= 20'd0;        //计数器清0  

48.      key_out_x <= 4'b1111;    

49.   end        

50.   else begin  

51.           if(count == 20'd0)           //0ms扫描第一行矩阵键盘  

52.            begin  

53.               key_out_x <= 4'b1110;   //开始扫描第一行矩阵键盘,第一行输出0  

54.                    count <= count + 20'b1; //计数器加1  

55.            end  

56.         else if(count == 20'd249_999) //5ms扫描第二行矩阵键盘,5ms计数(50M/200-1=249_999)  

57.            begin  

58.               key_out_x <= 4'b1101;   //开始扫描第二行矩阵键盘,第二行输出0  

59.                    count <= count + 20'b1; //计数器加1  

60.            end               

61.            else if(count ==20'd499_999)   //10ms扫描第三行矩阵键盘,10ms计数(50M/100-1=499_999)  

62.            begin  

63.               key_out_x <= 4'b1011;   //扫描第三行矩阵键盘,第三行输出0  

64.                    count <= count + 20'b1; //计数器加1  

65.            end   

66.            else if(count ==20'd749_999)   //15ms扫描第四行矩阵键盘,15ms计数(50M/67.7-1=749_999)  

67.            begin  

68.               key_out_x <= 4'b0111;   //扫描第四行矩阵键盘,第四行输出0  

69.                    count <= count + 20'b1; //计数器加1  

70.            end               

71.         else if(count ==20'd999_999)  //20ms计数(50M/50-1=999_999)  

72.               begin  

73.               count <= 0;             //计数器为0  

74.            end   

75.          else  

76.                count <= count + 20'b1;    //计数器加1  

77.              

78.     end  

79.end  

80.//====================================================  

81.// 采样列的按键信号  

82.//====================================================  

83.reg [3:0] key_h1_scan;    //第一行按键扫描值KEY  

84.reg [3:0] key_h1_scan_r;  //第一行按键扫描值寄存器KEY  

85.reg [3:0] key_h2_scan;    //第二行按键扫描值KEY  

86.reg [3:0] key_h2_scan_r;  //第二行按键扫描值寄存器KEY  

87.reg [3:0] key_h3_scan;    //第三行按键扫描值KEY  

88.reg [3:0] key_h3_scan_r;  //第三行按键扫描值寄存器KEY  

89.reg [3:0] key_h4_scan;    //第四行按键扫描值KEY  

90.reg [3:0] key_h4_scan_r;  //第四行按键扫描值寄存器KEY  

91.always @(posedge CLOCK)  

92.    begin  

93.        if(!RST_n) begin               //复位信号低有效  

94.            key_h1_scan <= 4'b1111;       

95.            key_h2_scan <= 4'b1111;            

96.            key_h3_scan <= 4'b1111;            

97.            key_h4_scan <= 4'b1111;          

98.        end       

99.        else begin  

100.          if(count == 20'd124_999)           //2.5ms扫描第一行矩阵键盘值  

101.               key_h1_scan<=key_in_y;         //扫描第一行的矩阵键盘值  

102.          else if(count == 20'd374_999)      //7.5ms扫描第二行矩阵键盘值  

103.               key_h2_scan<=key_in_y;         //扫描第二行的矩阵键盘值  

104.          else if(count == 20'd624_999)      //12.5ms扫描第三行矩阵键盘值  

105.               key_h3_scan<=key_in_y;         //扫描第三行的矩阵键盘值  

106.          else if(count == 20'd874_999)      //17.5ms扫描第四行矩阵键盘值  

107.               key_h4_scan<=key_in_y;         //扫描第四行的矩阵键盘值   

108.        end  

109.end  

110.  

111.//====================================================  

112.// 按键信号锁存一个时钟节拍  

113.//====================================================  

114.always @(posedge CLOCK)  

115.   begin  

116.         key_h1_scan_r <= key_h1_scan;         

117.         key_h2_scan_r <= key_h2_scan;   

118.         key_h3_scan_r <= key_h3_scan;   

119.         key_h4_scan_r <= key_h4_scan;    

120.    end   

121.     

122.wire [3:0] flag_h1_key = key_h1_scan_r[3:0] & (~key_h1_scan[3:0]);  //当检测到按键有下降沿变化时,代表该按键被按下,按键有效   

123.wire [3:0] flag_h2_key = key_h2_scan_r[3:0] & (~key_h2_scan[3:0]);  //当检测到按键有下降沿变化时,代表该按键被按下,按键有效   

124.wire [3:0] flag_h3_key = key_h3_scan_r[3:0] & (~key_h3_scan[3:0]);  //当检测到按键有下降沿变化时,代表该按键被按下,按键有效   

125.wire [3:0] flag_h4_key = key_h4_scan_r[3:0] & (~key_h4_scan[3:0]);  //当检测到按键有下降沿变化时,代表该按键被按下,按键有效   

126.//=====================================================  

127.// 方便封装,将按键值进行赋值  

128.//=====================================================  

129.reg [3:0] rPin_Out;  

130.always @ (posedge CLOCK or negedge RST_n)      //检测时钟的上升沿和复位的下降沿  

131.begin  

132.    if (!RST_n)                 //复位信号低有效  

133.         rPin_Out <= 4'd0;     //  

134.    else  

135.         begin              

136.             if ( flag_h1_key[0] ) begin LED<=4< span="">'b0000;rPin_Out <= 4'd0;  end  //按键第一行的KEY1值变化时,LED1将做亮灭翻转  

137.             if ( flag_h1_key[1] ) begin LED<=4< span="">'b0001;rPin_Out <= 4'd1; end   //按键第一行的KEY2值变化时,LED2将做亮灭翻转  

138.             if ( flag_h1_key[2] ) begin LED<=4< span="">'b0010;rPin_Out <= 4'd2;  end  //按键第一行的KEY3值变化时,LED3将做亮灭翻转  

139.             if ( flag_h1_key[3] ) begin LED<=4< span="">'b0011;rPin_Out <= 4'd3;  end  //按键第一行的KEY4值变化时,LED4将做亮灭翻转  

140.               

141.             if ( flag_h2_key[0] ) begin LED<=4< span="">'b0100;rPin_Out <= 4'd4; end   //按键第二行的KEY5值变化时,LED5做亮灭翻转  

142.             if ( flag_h2_key[1] ) begin LED<=4< span="">'b0101;rPin_Out <= 4'd5;  end  //按键第二行的KEY6值变化时,LED6将做亮灭翻转  

143.             if ( flag_h2_key[2] ) begin LED<=4< span="">'b0110;rPin_Out <= 4'd6;  end  //按键第二行的KEY7值变化时,LED7将做亮灭翻转  

144.             if ( flag_h2_key[3] ) begin LED<=4< span="">'b0111;rPin_Out <= 4'd7;  end  //按键第二行的KEY8值变化时,LED8将做亮灭翻转  

145.               

146.             if ( flag_h3_key[0] ) begin LED<=4< span="">'b1000;rPin_Out <= 4'd8;  end  //按键第三行的KEY9值变化时,LED9将做亮灭翻转  

147.             if ( flag_h3_key[1] ) begin LED<=4< span="">'b1001; rPin_Out <= 4'd9;  end  //按键第三行的KEY10值变化时,LED10将做亮灭翻转  

148.             if ( flag_h3_key[2] ) begin LED<=4< span="">'b1010;rPin_Out <= 4'd10; end   //按键第三行的KEY11值变化时,LED11将做亮灭翻转  

149.             if ( flag_h3_key[3] ) begin LED<=4< span="">'b1011;rPin_Out <= 4'd11; end   //按键第三行的KEY12值变化时,LED12将做亮灭翻转  

150.              

151.             if ( flag_h4_key[0] ) begin LED<=4< span="">'b1100;rPin_Out <= 4'd12;   end //按键第四行的KEY13值变化时,LED13将做亮灭翻转  

152.             if ( flag_h4_key[1] ) begin LED<=4< span="">'b1101;rPin_Out <= 4'd13;  end  //按键第四行的KEY14值变化时,LED14将做亮灭翻转  

153.             if ( flag_h4_key[2] ) begin LED<=4< span="">'b1110;rPin_Out <= 4'd14;  end  //按键第四行的KEY15值变化时,LED15将做亮灭翻转  

154.             if ( flag_h4_key[3] ) begin LED<=4< span="">'b1111;rPin_Out <= 4'd15; end   //按键第四行的KEY16值变化时,LED16将做亮灭翻转  

155.         end  

156.end  

157.//====================================================  

158.// 输出引脚  

159.//====================================================  

160.   

161.assign Pin_Out = rPin_Out;  

162.             

163.endmodule  

行130~156,将检测到的按键值赋值给4位LED,分别代表0~15的键值,同时将键值赋值给Pin_Out。

数码管模块见1.8节,在此不再赘述。

最后按照5‑20进行顶层模块的设计,详细的代码如下:

代码57 矩阵键盘顶层模块代码

1.//****************************************************************************//  

2.//# @Author: 碎碎思  

3.//# @Date:   2019-06-05 21:05:29  

4.//# @Last Modified by:   zlk  

5.//# @WeChat Official Account: OpenFPGA  

6.//# @Last Modified time: 2019-06-09 04:34:28  

7.//# Description:   

8.//# @Modification History: 2010-08-07 14:36:26  

9.//# Date                By             Version             Change Description:   

10.//# ========================================================================= #  

11.//# 2010-08-07 14:36:26  

12.//# ========================================================================= #  

13.//# |                                                                       | #  

14.//# |                                OpenFPGA                               | #  

15.//****************************************************************************//  

16.module Key4x4_module  

17.(  

18.    CLOCK, RST_n,   

19.    key_in_y,         // 输入矩阵键盘的列信号(KEY0~KEY3)  

20.    key_out_x,        // 输出矩阵键盘的行信号(KEY4~KEY7)    

21.    LED,  

22.    SMG_Data,  

23.    Scan_Sig  

24.);  

25.      

26.    input CLOCK;  

27.    input RST_n;  

28.   input  [3:0] key_in_y;  

29.    output [3:0] key_out_x;  

30.    output [3:0] LED;  

31.    output [7:0]SMG_Data;  

32.    output [5:0]Scan_Sig;  

33.  

34.    /**************************/  

35.       

36.    wire [3:0]Pin_Out;  

37.  

38.    key4x4funcmod_module  U1  

39.     (  

40.        .CLOCK( CLOCK ),  

41.        .RST_n( RST_n ),  

42.        .key_in_y( key_in_y ),   // input - from top  

43.        .key_out_x(key_out_x),   // output - to top  

44.        .LED(LED),  

45.        .Pin_Out( Pin_Out )      // < core  

46.     );  

47.       

48.     /**************************/  

49.     smg_interface U2  

50.     (  

51.         .CLOCK( CLOCK ),  

52.         .RST_n( RST_n ),  

53.         .SMG_Data( SMG_Data ),          // output - to top  

54.         .Scan_Sig( Scan_Sig ),          // output - to top  

55.         .Number_Sig( Number_Sig )          // < core  

56.     );  

57.  

58.    reg [23:0]Number_Sig;  

59.      

60.    always @ ( posedge CLOCK or negedge RST_n )  

61.        if( !RST_n )  

62.             begin  

63.                Number_Sig[7:0] <= 8'h16;  

64.              end  

65.         else   

66.             case( Pin_Out )  

67.                0:  

68.                    Number_Sig[7:0] <= 8'h00;   

69.                 1:  

70.                    Number_Sig[7:0] <= 8'h01;  

71.                 2:  

72.                    Number_Sig[7:0] <= 8'h02;  

73.                 3:  

74.                    Number_Sig[7:0] <= 8'h03;  

75.                 4:  

76.                    Number_Sig[7:0] <= 8'h04;  

77.                 5:  

78.                    Number_Sig[7:0] <= 8'h05;  

79.                 6:  

80.                    Number_Sig[7:0] <= 8'h06;  

81.                 7:  

82.                    Number_Sig[7:0] <= 8'h07;  

83.                 8:  

84.                    Number_Sig[7:0] <= 8'h08;  

85.                 9:  

86.                    Number_Sig[7:0] <= 8'h09;  

87.                 10:  

88.                    Number_Sig[7:0] <= 8'h10;  

89.                 11:  

90.                    Number_Sig[7:0] <= 8'h11;  

91.                 12:  

92.                    Number_Sig[7:0] <= 8'h12;  

93.                 13:  

94.                    Number_Sig[7:0] <= 8'h13;  

95.                 14:  

96.                    Number_Sig[7:0] <= 8'h14;  

97.                 15:  

98.                    Number_Sig[7:0] <= 8'h15;  

99.                      

100.                default:  

101.                   Number_Sig[7:0]<=8'h16;  

102.  

103.              endcase  

104.  

105.endmodule  

行60~103是顶层模块的核心操作,主要将Pin_Out值进行解析显示到数码管上。

将上述代码综合后下载到板子上:

矩阵键盘 K0 按一下-----------LED[3:0]显示0000,同时二位数码管显示00;

矩阵键盘 K1 按一下-----------LED[3:0]显示0001,同时二位数码管显示01;

矩阵键盘 K2 按一下-----------LED[3:0]显示0010,同时二位数码管显示02;

矩阵键盘 K3 按一下-----------LED[3:0]显示0011,同时二位数码管显示03;

矩阵键盘 K4 按一下-----------LED[3:0]显示0100,同时二位数码管显示04;

……………

整个模块的RTL如下所示:

521 整个模块综合后RTL


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
键盘Keyboard中的扫描码Scan Code 通码Make code 断码Break Code
一个应用于单片机的按键处理模块
单片机4*4矩阵键盘-Changing's Blog
Verilog HDL按键消抖
51单片机按键防抖这么处理
PIC16F505单片机按键处理总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服