差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
矩阵按键模块 [2017/05/25 11:47] anran [硬件说明] |
矩阵按键模块 [2022/06/22 14:53] (当前版本) haihang |
||
---|---|---|---|
行 20: | 行 20: | ||
通过上面的描述:在这一时刻只有K1、K2、K3、K4按键被按下,才会导致4根列线输出COL1=0、COL2=0、COL3=0、COL4=0,否则COL1=1、COL2=1、COL3=1、COL4=1,反之当FPGA检测到列线(COL1、COL2、COL3、COL4)中有低电平信号时,对应的K1、K2、K3、K4按键应该是被按下了。 | 通过上面的描述:在这一时刻只有K1、K2、K3、K4按键被按下,才会导致4根列线输出COL1=0、COL2=0、COL3=0、COL4=0,否则COL1=1、COL2=1、COL3=1、COL4=1,反之当FPGA检测到列线(COL1、COL2、COL3、COL4)中有低电平信号时,对应的K1、K2、K3、K4按键应该是被按下了。 | ||
- | 按照扫描的方式,一共分为4个时刻,分别对应4根行线中的一根拉低,4个时刻一次循环,这样就完成了矩阵按键的全部扫描检测 | + | 按照扫描的方式,一共分为4个时刻,分别对应4根行线中的一根拉低,4个时刻依次循环,这样就完成了矩阵按键的全部扫描检测,我们在程序中以这4个时刻对应状态机的4个状态。 |
+ | 至于循环的周期,根据我们基础教程里可知,按键抖动的不稳定时间在10ms以内,所以对同一个按键采样的周期大于10ms,这同样取20ms时间。20ms时间对应4个状态,每5ms进行一次状态转换。 | ||
+ | \\ | ||
+ | {{ :矩阵按键程序框图.jpg?800 |}} | ||
\\ | \\ | ||
{{ :矩阵按键扫描法原理.jpg |}} | {{ :矩阵按键扫描法原理.jpg |}} | ||
行 28: | 行 31: | ||
<code verilog> | <code verilog> | ||
- | // ******************************************************************** | + | // -------------------------------------------------------------------- |
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | ||
- | // ******************************************************************** | + | // -------------------------------------------------------------------- |
- | // File name : LED.v | + | // Module: Array_KeyBoard |
- | // Module name : LED | + | |
- | // Author : STEP | + | |
- | // Description : control LED | + | |
- | // Web : www.stepfpga.com | + | |
// | // | ||
+ | // Author: Step | ||
+ | // | ||
+ | // Description: Array_KeyBoard | ||
+ | // | ||
+ | // Web: www.stepfapga.com | ||
+ | // | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | // Code Revision History : | + | // Code Revision History : |
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
// Version: |Mod. Date: |Changes Made: | // Version: |Mod. Date: |Changes Made: | ||
- | // V1.0 |2017/03/02 |Initial ver | + | // V1.0 |2015/11/11 |Initial ver |
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | // Module Function:利用按键和开关的状态来控制LED灯的亮灭。 | + | module Array_KeyBoard # |
+ | ( | ||
+ | parameter NUM_FOR_200HZ = 60000 //定义计数器cnt的计数范围,例化时可更改 | ||
+ | ) | ||
+ | ( | ||
+ | input clk_in, //系统时钟 | ||
+ | input rst_n_in, //系统复位,低有效 | ||
+ | input [3:0] col, //矩阵按键列接口 | ||
+ | output reg [3:0] row, //矩阵按键行接口 | ||
+ | output reg [15:0] key_out //消抖后的信号 | ||
+ | ); | ||
+ | /* | ||
+ | 因使用4x4矩阵按键,通过扫描方法实现,所以这里使用状态机实现,共分为4种状态 | ||
+ | 在其中的某一状态时间里,对应的4个按键相当于独立按键,可按独立按键的周期采样法采样 | ||
+ | 周期采样时每隔20ms采样一次,对应这里状态机每隔20ms循环一次,每个状态对应5ms时间 | ||
+ | 对矩阵按键实现原理不明白的,请去了解矩阵按键实现原理 | ||
+ | */ | ||
+ | localparam STATE0 = 2'b00; | ||
+ | localparam STATE1 = 2'b01; | ||
+ | localparam STATE2 = 2'b10; | ||
+ | localparam STATE3 = 2'b11; | ||
- | module LED (key,sw,led); | + | //计数器计数分频实现5ms周期信号clk_200hz |
+ | reg [15:0] cnt; | ||
+ | reg clk_200hz; | ||
+ | always@(posedge clk_in or negedge rst_n_in) begin | ||
+ | if(!rst_n_in) begin //复位时计数器cnt清零,clk_200hz信号起始电平为低电平 | ||
+ | cnt <= 16'd0; | ||
+ | clk_200hz <= 1'b0; | ||
+ | end else begin | ||
+ | if(cnt >= ((NUM_FOR_200HZ>>1) - 1)) begin //数字逻辑中右移1位相当于除2 | ||
+ | cnt <= 16'd0; | ||
+ | clk_200hz <= ~clk_200hz; //clk_200hz信号取反 | ||
+ | end else begin | ||
+ | cnt <= cnt + 1'b1; | ||
+ | clk_200hz <= clk_200hz; | ||
+ | end | ||
+ | end | ||
+ | end | ||
- | input [3:0] key; //按键输入信号 | + | reg [1:0] c_state; |
- | input [3:0] sw; //开关输入信号 | + | //状态机根据clk_200hz信号在4个状态间循环,每个状态对矩阵按键的行接口单行有效 |
- | output [7:0] led; //输出信号到LED | + | always@(posedge clk_200hz or negedge rst_n_in) begin |
- | + | if(!rst_n_in) begin | |
- | assign led = {key,sw}; //assign连续赋值。大括号是拼接符,表示把key和sw拼接组成一个新的8位数赋值给led | + | c_state <= STATE0; |
+ | row <= 4'b1110; | ||
+ | end else begin | ||
+ | case(c_state) | ||
+ | STATE0: begin c_state <= STATE1; row <= 4'b1101; end //状态c_state跳转及对应状态下矩阵按键的row输出 | ||
+ | STATE1: begin c_state <= STATE2; row <= 4'b1011; end | ||
+ | STATE2: begin c_state <= STATE3; row <= 4'b0111; end | ||
+ | STATE3: begin c_state <= STATE0; row <= 4'b1110; end | ||
+ | default:begin c_state <= STATE0; row <= 4'b1110; end | ||
+ | endcase | ||
+ | end | ||
+ | end | ||
+ | //因为每个状态中单行有效,通过对列接口的电平状态采样得到对应4个按键的状态,依次循环 | ||
+ | always@(negedge clk_200hz or negedge rst_n_in) begin | ||
+ | if(!rst_n_in) begin | ||
+ | key_out <= 16'hffff; | ||
+ | end else begin | ||
+ | case(c_state) | ||
+ | STATE0:key_out[3:0] <= col; //采集当前状态的列数据赋值给对应的寄存器位 | ||
+ | STATE1:key_out[7:4] <= col; | ||
+ | STATE2:key_out[11:8] <= col; | ||
+ | STATE3:key_out[15:12] <= col; | ||
+ | default:key_out <= 16'hffff; | ||
+ | endcase | ||
+ | end | ||
+ | end | ||
+ | |||
endmodule | endmodule | ||
行 59: | 行 126: | ||
\\ | \\ | ||
\\ | \\ | ||
- | ====引脚分配==== | + | |
- | ------- | + | |
- | 综合(synthesize)完成之后一定要配置FPGA的引脚到相应的外设,这样下载FPGA程序后才能达到我们想要的效果。 | + | |
- | \\ | + | |
- | {{led1.png?300|}} {{button1.png?300|}} | + | |
- | \\ | + | |
====小结==== | ====小结==== | ||
------ | ------ | ||
- | 下载完程序后就可以实现按键开关控制LED灯的亮灭。了解小脚丫STEP-MXO2 V2上的外设LED、按键和开关的使用。如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | + | 本节主要为大家讲解了矩阵按键的工作原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 |
- | + | \\ | |
+ | 如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | ||
+ | ====相关资料==== | ||
+ | ------ | ||
+ | \\ | ||
+ | 使用[[STEP-MXO2第二代]]的矩阵按键程序: 后续会有下载连接 待更新 | ||
+ | \\ | ||
+ | 使用[[STEP-MAX10]]的矩阵按键程序: 后续会有下载连接 待更新 | ||
+ | \\ |