差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
按键消抖 [2016/06/12 11:35] anran [硬件连接] |
按键消抖 [2016/06/12 17:16] (当前版本) anran [相关文档] |
||
---|---|---|---|
行 19: | 行 19: | ||
- 消除抖动的措施:在按键按下的时刻,会出现波形的抖动,在之后的一段时间内,才会出现平稳的波形。我们舍弃了刚刚检测到按键按下的时刻,读取这一时刻之后20ms左右的按键信息,这样可以防止一次按键被误读多次。 | - 消除抖动的措施:在按键按下的时刻,会出现波形的抖动,在之后的一段时间内,才会出现平稳的波形。我们舍弃了刚刚检测到按键按下的时刻,读取这一时刻之后20ms左右的按键信息,这样可以防止一次按键被误读多次。 | ||
- | 根据上面的原理描述,我们可以对按键的输入管脚进行下降沿检测,当检测到下降沿后计数开始,计数到20ms时进行采样,然后再对每次采样的值进行下降沿检测,检测的结果作为按键消抖的脉冲输出,然后每次检测到下降沿时让状态输出进行翻转并输出。 | + | 根据上面的原理描述,我们可以对按键的输入管脚进行边沿检测,当检测到输入信号变化后计数清零并开始计数,计数到20ms时进行采样,然后再对每次采样的值进行下降沿检测,检测的结果作为按键消抖的脉冲输出,然后每次检测到下降沿时让状态输出进行翻转并输出。 |
行 34: | 行 34: | ||
====代码设计==== | ====代码设计==== | ||
---- | ---- | ||
- | ===设计文件=== | ||
- | {{ :流水灯程序设计.jpg |流水灯程序设计}} | + | {{ :按键消抖程序设计.jpg |按键消抖程序设计}} |
- | 为了实现对8个LED的控制,我们设计了25位的计数器cnt进行1s周期的循环计数,同时我们定义了一个4位寄存器led_cnt作为状态机的状态控制流水灯的闪烁。状态机共有8个状态,每一个状态对应点亮一个LED灯。 | + | 如上图所示,我们首先进行边沿检测,边沿检测的方法是定义一个寄存器对输入信号进行锁存,然后将寄存器的数据与下一个时刻的输入信号做对比,如果两者不相等则认为输入信号在这个时间段发生了变化,产生了边沿,key_an产生高电平的脉冲。 |
- | + | ||
- | 首先是计数器的设计,计数器的计数范围为0~CNT_NUM-1,为了实现每个LED灯1秒的点亮时间,设计文件代码中我们定义参数CNT_NUM为25000000,但是在仿真文件调用设计文件时,为了方便仿真,我们会将参数CNT_NUM重新赋值为10. | + | |
<code verilog> | <code verilog> | ||
- | reg [24:0] cnt = 25'd0; | + | reg key_rst; |
- | always@(posedge clk_in or negedge rst_n_in) begin | + | //Register key_rst, lock key1_n to next clk |
- | if(!rst_n_in) begin | + | always @(posedge clk or negedge rst_n) |
- | cnt <= 25'd0; | + | if (!rst_n) key_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_cnt) begin | + | 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_sw, generate 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_in| rst_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] | | + | ^ 管脚名称 | clk| rst_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管脚 | 5 | | | |
^ 时钟频率 | 25MHz | | | | ^ 时钟频率 | 25MHz | | | | ||
====知识点==== | ====知识点==== | ||
- | * 分频设计 | + | * 按键消抖原理 |
- | * 时序控制 | + | * 边沿检测设计 |
- | * 简单状态机 | + | |
行 133: | 行 101: | ||
^ **文件名称** | **功能** | | ^ **文件名称** | **功能** | | ||
- | ^ **[[Water_led.v]]** | **流水灯** | | + | ^ **[[Debounce.v]]** | **按键消抖** | |
- | ^ **[[Water_led_test.v]]** | **测试文件** | | + | |