差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 后一修订版 两侧同时换到之后的修订记录 | ||
8._计时控制 [2017/03/23 00:56] zhijun |
8._计时控制 [2017/04/03 21:04] zhijun |
||
---|---|---|---|
行 30: | 行 30: | ||
// V1.0 |2017/03/02 |Initial ver | // V1.0 |2017/03/02 |Initial ver | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | // Module Function:按键消抖 | + | // Module Function:计时器 |
- | module debounce (clk,rst,key,key_pulse); | + | module segment_counter |
+ | ( | ||
+ | clk , | ||
+ | rst , | ||
+ | hold , | ||
+ | seg_led_1 , | ||
+ | seg_led_2 , | ||
+ | ); | ||
- | parameter N = 1; //要消除的按键的数量 | + | input clk,rst; |
+ | input hold; | ||
- | input clk; | + | output reg [8:0] seg_led_1,seg_led_2; |
- | input rst; | + | |
- | input [N-1:0] key; //输入的按键 | + | reg clk_divided; |
- | output [N-1:0] key_pulse; //按键动作产生的脉冲 | + | reg hold_flag; |
- | | + | reg back_to_zero_flag = 0; |
- | reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值 | + | reg [6:0] seg [9:0]; |
- | reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值 | + | reg [23:0] cnt; |
- | + | reg [3:0] cnt_ge; | |
- | wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲 | + | reg [3:0] cnt_shi; |
- | + | ||
- | //利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中 | + | parameter PERIOD=6000000; //1秒 |
- | always @(posedge clk or negedge rst) | + | |
- | begin | + | initial |
- | if (!rst) begin | + | begin |
- | key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1,{}中表示N个1 | + | seg[0] = 7'h3f; // 0 |
- | key_rst_pre <= {N{1'b1}}; | + | seg[1] = 7'h06; // 1 |
- | end | + | seg[2] = 7'h5b; // 2 |
- | else begin | + | seg[3] = 7'h4f; // 3 |
- | key_rst <= key; //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre | + | seg[4] = 7'h66; // 4 |
- | key_rst_pre <= key_rst; //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值 | + | seg[5] = 7'h6d; // 5 |
- | end | + | seg[6] = 7'h7d; // 6 |
- | end | + | seg[7] = 7'h07; // 7 |
- | + | seg[8] = 7'h7f; // 8 | |
- | assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平 | + | seg[9] = 7'h6f; // 9 |
- | + | /*若需要显示A-F,解除此段注释即可 | |
- | reg [17:0] cnt; //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器 | + | seg[10]= 7'hf7; // A |
- | + | seg[11]= 7'h7c; // b | |
- | //产生20ms延时,当检测到key_edge有效是计数器清零开始计数 | + | seg[12]= 7'h39; // C |
- | always @(posedge clk or negedge rst) | + | seg[13]= 7'h5e; // d |
- | begin | + | seg[14]= 7'h79; // E |
- | if(!rst) | + | seg[15]= 7'h71; // F*/ |
- | cnt <= 18'h0; | + | end |
- | else if(key_edge) | + | |
- | cnt <= 18'h0; | + | always @ (posedge clk) begin // 用于分出一个1Hz的频率 |
- | else | + | if (!rst == 1) begin |
- | cnt <= cnt + 1'h1; | + | cnt <= 0; |
- | end | + | clk_divided <= 0; end |
- | | + | else begin |
- | reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量 | + | if (cnt < PERIOD-1) |
- | reg [N-1:0] key_sec; | + | cnt <= cnt + 1; |
- | + | else begin | |
- | | + | cnt <= 0; |
- | //延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效 | + | clk_divided <= ~clk_divided; end |
- | always @(posedge clk or negedge rst) | + | end |
- | begin | + | end |
- | if (!rst) | + | |
- | key_sec <= {N{1'b1}}; | + | always @ (*) begin |
- | else if (cnt==18'h3ffff) | + | if (!rst == 1) |
- | key_sec <= key; | + | back_to_zero_flag <= 1; |
- | end | + | else if (((cnt_shi*10) + cnt_ge)==24) |
- | always @(posedge clk or negedge rst) | + | back_to_zero_flag <= 1; |
- | begin | + | else |
- | if (!rst) | + | back_to_zero_flag <= 0; |
- | key_sec_pre <= {N{1'b1}}; | + | end |
- | else | + | |
- | key_sec_pre <= key_sec; | + | always @ (posedge hold) |
- | end | + | hold_flag <= ~hold_flag; |
- | end | + | |
- | assign key_pulse = key_sec_pre & (~key_sec); | + | always @ (posedge clk_divided or posedge back_to_zero_flag) begin |
- | | + | if (back_to_zero_flag == 1) begin |
- | endmodule | + | cnt_ge <= 0; |
+ | cnt_shi <= 0; end | ||
+ | else if (cnt_ge == 9) begin | ||
+ | cnt_ge <= 0; | ||
+ | cnt_shi <= cnt_shi + 1; end | ||
+ | else if (hold_flag == 1) | ||
+ | cnt_ge <= cnt_ge; | ||
+ | else | ||
+ | cnt_ge <= cnt_ge + 1; | ||
+ | end | ||
+ | |||
+ | always @ (cnt_ge) begin | ||
+ | seg_led_1[8:0] <= {2'b00,seg[cnt_ge]}; | ||
+ | end | ||
+ | |||
+ | always @ (cnt_shi) begin | ||
+ | seg_led_2[8:0] <= {2'b00,seg[cnt_shi]}; | ||
+ | end | ||
+ | |||
+ | endmodule | ||
</code> | </code> | ||
行 102: | 行 129: | ||
\\ | \\ | ||
- | 以上就是一个N位按键的消抖程序,如果有按键按下会输出一个时钟周期的高脉冲。下面我们可以试试用这个按键消抖的输出来触发LED的显示,既按键一次LED翻转。你也可以不加按键消抖试试用按键来控制LED(按一次变亮,再按一次灭掉)。 | ||
- | |||
- | \\ | ||
- | 下面的程序是例化调用debounce模块来控制LED | ||
- | \\ | ||
- | <code verilog> | ||
- | // ******************************************************************** | ||
- | // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | ||
- | // ******************************************************************** | ||
- | // File name : top.v | ||
- | // Module name : top | ||
- | // Author : STEP | ||
- | // Description : | ||
- | // Web : www.stepfpga.com | ||
- | // | ||
- | // -------------------------------------------------------------------- | ||
- | // Code Revision History : | ||
- | // -------------------------------------------------------------------- | ||
- | // Version: |Mod. Date: |Changes Made: | ||
- | // V1.0 |2017/03/02 |Initial ver | ||
- | // -------------------------------------------------------------------- | ||
- | // Module Function:进过按键消抖后控制led显示翻转 | ||
- | |||
- | module top (clk,rst,key,led); | ||
- | |||
- | input clk; | ||
- | input rst; | ||
- | input key; | ||
- | output reg led; | ||
- | |||
- | wire key_pulse; | ||
- | | ||
- | //当按键按下时产生一个高脉冲,翻转一次led | ||
- | always @(posedge clk or negedge rst) | ||
- | begin | ||
- | if (!rst) | ||
- | led <= 1'b1; | ||
- | else if (key_pulse) | ||
- | led <= ~led; | ||
- | else | ||
- | led <= led; | ||
- | end | ||
- | //例化消抖module,这里没有传递参数N,采用了默认的N=1 | ||
- | debounce u1 ( | ||
- | .clk (clk), | ||
- | .rst (rst), | ||
- | .key (key), | ||
- | .key_pulse (key_pulse) | ||
- | ); | ||
- | endmodule | ||
- | </code> | ||
- | |||
- | \\ | ||
====引脚分配==== | ====引脚分配==== | ||
------- | ------- | ||
行 162: | 行 136: | ||
|clk |C1 ^ | |clk |C1 ^ | ||
|rst |L14 ^ | |rst |L14 ^ | ||
- | |key |N14 ^ | + | |hold |M13 ^ |
- | |led |N13 ^ | + | |seg_led_1[0] |C12 ^ |
+ | |seg_led_1[1] |B14 ^ | ||
+ | |seg_led_1[2] |J1 ^ | ||
+ | |seg_led_1[3] |H1 ^ | ||
+ | |seg_led_1[4] |H2 ^ | ||
+ | |seg_led_1[5] |B12 ^ | ||
+ | |seg_led_1[6] |A11 ^ | ||
+ | |seg_led_1[7] |K1 ^ | ||
+ | |seg_led_1[8] |A12 ^ | ||
+ | |seg_led_2[0] |A10 ^ | ||
+ | |seg_led_2[1] |C11 ^ | ||
+ | |seg_led_2[2] |F2 ^ | ||
+ | |seg_led_2[3] |E1 ^ | ||
+ | |seg_led_2[4] |E2 ^ | ||
+ | |seg_led_2[5] |A9 ^ | ||
+ | |seg_led_2[6] |B9 ^ | ||
+ | |seg_led_2[7] |F1 ^ | ||
+ | |seg_led_2[8] |C9 ^ | ||
====小结==== | ====小结==== | ||
------ | ------ | ||
- | 在本实验学习了如何进行按键的消抖。在很多应用情况下我们必须采取消抖才能更好地控制逻辑。在下一个实验[[8. 计时控制|计时控制]]中我们将学习计时的显示和控制,在这里我们要用到按键的消抖以及数码管,我们甚至可以用小脚丫做一个计时器甚至电子表。 | + | 本实验主要介绍了计时器的实现方式,并且包含了复位与暂停功能,读者可自行修改程序内部的时钟参数来调节计时时间。下一节将介绍PWM调制技术的应用[[9. 呼吸灯|呼吸灯]]。 |