差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
按键消抖 [2016/06/12 10:13]
anran [流水灯]
按键消抖 [2016/06/12 17:16] (当前版本)
anran [相关文档]
行 4: 行 4:
 ------ ------
   - [[STEP-MXO2第一代]]   - [[STEP-MXO2第一代]]
-  - [[STEP-Baseboard]] 
- 
 ====设计要求==== ====设计要求====
 ------ ------
-  - 掌握分频功能的设计 +  - 掌握FPGA边沿检测的设计 
-  - 掌握时序逻辑设计 +  - 掌握按键消抖原理 
-  - 掌握case的基本语法 +  - 基于小脚丫[[STEP-MXO2第一代]]开发平台实现按键消抖的功能,实现脉冲和状态翻转输出。
-  - 基于小脚丫STEP ​FPGA Base Board开发平台LED实现流水灯的功能,每个LED点亮时间为1秒+
  
 ====工作原理==== ====工作原理====
 ------ ------
 +{{ :​抖动原理.png |抖动原理}}
  
-本设计为流水灯实验,我们需要结合使用硬件平台实现[[STEP-Baseboard]]平台上的8个LED循环闪烁,每个LED灯点亮时间为1秒。+按键抖动原理
  
-LED也叫发光二极管,属于二极管一种,具有二极管单项导电性,使用时需要给LED施加正向压差,产生电流(一般20mA以内,具体参考设计中使用LED参数)点亮LED+  - 抖动产生 :通常的按键所用开关为机械弹开关当机械触点断开、闭合时,由于机械触点的弹性作,一个按键开关在闭合不会马稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动为了不产生这种现象而作的措施就是按键消抖。 
 +  - 消除抖动的措施:按键按下的时刻,会出现波形的抖动,在之后的一段时间内,才会出现平稳波形。我们舍弃了刚刚检测到按键按下时刻读取这一时刻之后20ms左右的按键信息,这样可以防止一次按键被误读多次
  
-为了使每个LED点亮1秒时间,我们需要一个1Hz的信号,因为硬件平台[[STEP-MXO2第一代]]上使用的晶振为25MHz,2^25 = 33554432 > 25000000,所以我们需要做一个位宽为25的计数器。计数器初值为0计数到24999999时,总共计数25000000也就是1秒时间。 +根据上面原理描述,我们可以对按键输入管脚进行边沿检测,当检测到输入信号变化后计数清零并开始计数,计数到20ms进行采样然后再对每次采样的值进行下降沿检测检测作为按键消抖脉冲输出然后每次检测下降沿让状态输出进行翻转并输出
- +
-为了实现流水,我们需要一个寄存器,寄存器值不同控制着不同的LED点亮而寄存器的值在每次计数器计数24999999改变,这样每隔1秒时间,寄存器的值改变,对应控制8个LED按照同一方向循环闪烁,就实现了流水灯的功能+
  
  
行 29: 行 26:
 ====硬件连接==== ====硬件连接====
 ------ ------
-结合实验平台[[STEP-Baseboard]]的硬件配置,我们使用8个LED灯作为流水灯的输出 
  
-{{ :图10.LED模块电路连接.png |LED模块电路连接}}+为了方便我们在硬件平台上更直观的观察,我们使用25MHz时钟晶振分频产生1Hz的信号作为序列检测的时钟,按键信号作为按键消抖的信号输入,LED灯LD1和LD2分别作为按键消抖的脉冲和状态输出指示。
  
 +{{ :​按键硬件图.jpg |按键硬件图}}
  
 +{{ :​led电路连接.jpg |LED电路连接}}
 ====代码设计==== ====代码设计====
 ---- ----
-===设计文件=== 
  
-{{ :流水灯程序设计.jpg |流水灯程序设计}}+{{ :按键消抖程序设计.jpg |按键消抖程序设计}}
  
-为了实现对8个LED的控制,我们设计了25位的计数器cnt进行1s周期循环计数,同时我们定义一个4位寄存器led_cnt作为状态机的状态控制流水灯的闪烁。状态机共有8个状态,每一个状态应点亮一个LED灯。 +如上图所示,我们首先进行边沿检测,边沿检测方法是定义一个寄存器对输入信号进行锁存然后将寄存器的数据与下一时刻输入信号做对比如果两者不相等则认输入信号这个间段发生了变化产生边沿key_an产生高电平的脉冲。
- +
-首先是计数器的设计计数器的范围为0~CNT_NUM-1,为了实现每LED灯1秒点亮时间设计文件代码中我们定义参数CNT_NUM25000000,但是仿真文件调用设计文件时,方便仿真我们会将参数CNT_NUM重新赋值为10.+
  
 <code verilog> <code verilog>
-reg [24:0] cnt = 25'd0+reg  ​key_rst   
-always@(posedge ​clk_in ​or negedge ​rst_n_inbegin +//Register key_rst, lock key1_n to next clk 
- if(!rst_n_inbegin +always @(posedge ​clk  ​or  negedge ​rst_n
- cnt <= 25'​d0;​ +    if (!rst_nkey_rst ​<= 1'b1
- end else if(cnt>​=CNT_NUM-1) begin +    else  ​key_rst ​<=key1_n;
- cnt <= 25'd0+
- end else begin +
- cnt <= cnt + 25'd1; +
- end +
-end +
-</​code>​+
  
-然后我们需要对状态机的状态进行控制,使得作为状态的寄存器led_cnt实现从0到7的循环加一操作。 +//Detect the edge of key1_n 
- +wire  key_an ​= (key_rst==key1_n)? 0:1;
-<code verilog>​ +
-reg [3:0] led_cnt ​4'​d0;​ +
-always@(posedge clk_in or negedge rst_n_in) begin +
- if(!rst_n_in) begin +
- led_cnt <4'​d0;​ +
- end else if(cnt==CNT_NUM-1) begin +
- if(led_cnt==4'​d7) led_cnt <= 4'd0; +
- else led_cnt <= led_cnt + 4'​d1;​ +
- end +
-end+
 </​code>​ </​code>​
  
-最后是组合逻辑根据led_cnt不同状态控制不同的LED点亮+当key_an产生脉冲时计数器cnt清零并计数,因为我们要采集输入信号变化后20ms的状态值,系统时钟25MHz,计数器终值 = 25MHz/50 = 500000,所以计数器计数到500000时采样
  
 <code verilog> <code verilog>
-always@(led_cntbegin +reg  low_sw; 
- case(led_cnt) +//Lock the status to register low_sw when cnt count to 19'​d500000 
- 4'​d0:​ led_out ​8'b1111_1110+always @(posedge clk  or  negedge rst_n
- 4'd1: led_out ​8'​b1111_1101;​ +    ​if ​(!rst_n ​low_sw <1'b1
- 4'​d2:​ led_out ​8'b1111_1011; + else if (cnt == 19'd500000) 
- 4'd3: led_out ​8'​b1111_0111; +        ​low_sw <key1_n;
- 4'​d4:​ led_out = 8'​b1110_1111;​ +
- 4'​d5:​ led_out = 8'​b1101_1111;​ +
- 4'​d6:​ led_out = 8'​b1011_1111;​ +
- 4'​d7:​ led_out = 8'​b0111_1111;​ +
- default: led_out = 8'​b1111_1111;​ +
- endcase +
-end+
 </​code>​ </​code>​
  
-===试文件=== +然后对将采样寄存器low_sw的数据锁存至寄存器low_sw_r,然后检下降沿(因为我们的硬是按键时输出低电平,采用下降沿实时性更好一些)。
- +
-测试文件中我们需要对设计文中的参数CNT_NUM进行重新赋值+
  
 <code verilog> <code verilog>
-parameter CNT_NUM = 10; +//Detect the negedge of low_swgenerate pulse 
-Water_led #​(.CNT_NUM(CNT_NUM)) +assign key_pulse= low_sw_r & ~low_sw);
-Water_led_uut +
-+
-.clk_in(sys_clk)+
-.rst_n_in(sys_rst_n),​ +
-.led_out(led_out) +
-);+
 </​code>​ </​code>​
  
 引脚分配如下: 引脚分配如下:
  
-^ 管脚名称 | clk_inrst_n_in ​led_out[0] ​ |led_out[1] ​ |led_out[2] ​ |led_out[3] ​ |led_out[4] ​ |led_out[5] ​ |led_out[6] ​ |led_out[7] ​ | +^ 管脚名称 | clkrst_n key_n  ​| ​key_pulse ​ |key_state ​ | 
-^ FPGA管脚 | C1 | A2 |B14  ​|C14  ​|E14  |F14  |G14  |J14  |K14  |L14  ​+^ FPGA管脚 | C1 | A2    B7     A3         |A7         
-====仿真结果====+====运行结果====
  
-{{:流水灯仿真.jpg|流水灯仿真}}+{{:img20160612165641.jpg?500 |按}} 
 + 
 +{{:​img20160612165704.jpg?​500|再按}}
 ====资源报告==== ====资源报告====
  
 ^ 资源 | 数量 ​ | 比例 ​ | 说明 ​ | ^ 资源 | 数量 ​ | 比例 ​ | 说明 ​ |
-^ LUTs | 28   | 4%   ​| ​  |  +^ LUTs | 16   | 3%   ​| ​  |  
-^ 寄存器 | 33    ​| ​2% |   |+^ 寄存器 | 23    ​| ​1% |   |
 ^ 存储器 | 0  | 0%   ​| ​   | ^ 存储器 | 0  | 0%   ​| ​   |
-^ IO管脚 ​  ​| ​10 |   ​| ​   |+^ IO管脚 ​  ​| ​|   ​| ​   |
 ^ 时钟频率 | 25MHz |   ​| ​   | ^ 时钟频率 | 25MHz |   ​| ​   |
  
 ====知识点==== ====知识点====
  
-  * 分频设计 +  * 按键消抖原理 
-  * 时序控制 +  * 边沿检测设计 
-  * 简单状态机+
  
  
行 135: 行 101:
  
 ^ **文件名称** ​ | **功能** | ^ **文件名称** ​ | **功能** |
-^ **[[Water_led.v]]** | **流水灯** | +^ **[[Debounce.v]]** | **按键消抖** | 
-^ **[[Water_led_test.v]]** | **测试文件** |+