差别

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

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
按键消抖 [2016/06/12 14:06]
anran [代码设计]
按键消抖 [2016/06/12 17:16] (当前版本)
anran [相关文档]
行 37: 行 37:
 {{ :​按键消抖程序设计.jpg |按键消抖程序设计}} {{ :​按键消抖程序设计.jpg |按键消抖程序设计}}
  
- +如上图所示,我们首先进行边沿检测,边沿检测方法是定义一个寄存器对输入信号进行锁存然后将寄存器的数据与下一时刻输入信号做对比如果两者不相等则认输入信号这个间段发生了变化产生边沿key_an产生高电平的脉冲。
- +
- +
- +
-为了实现对8个LED的控制,我们设计了25位的计数器cnt进行1s周期循环计数,同时我们定义一个4位寄存器led_cnt作为状态机的状态控制流水灯的闪烁。状态机共有8个状态,每一个状态应点亮一个LED灯。 +
- +
-首先是计数器的设计计数器的范围为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 |   ​| ​   |
  
 ====知识点==== ====知识点====
  
-  * 分频设计 +  * 按键消抖原理 
-  * 时序控制 +  * 边沿检测设计 
-  * 简单状态机+
  
  
行 136: 行 101:
  
 ^ **文件名称** ​ | **功能** | ^ **文件名称** ​ | **功能** |
-^ **[[Water_led.v]]** | **流水灯** | +^ **[[Debounce.v]]** | **按键消抖** | 
-^ **[[Water_led_test.v]]** | **测试文件** |+