一天一个设计实例-轻触开关的应用设计

轻触开关的应用设计

本节介绍轻触开关的有关设计,主要介绍按键防抖动和矩阵键盘的应用设计。

1.1.1轻触开关的功能描述

(1) 轻触开关的工作原理。轻触开关在操作时通过触动按键来改变当前的逻辑状态(高、低电平之间的变换),而达到开/关的目的。每按一次按键,就向 FPGA 控制系统发出一个电平信号,输入变为 一个与原输入相反的电平,松开后立即回到原来的状态。简单地说,轻触开关就是触发一个暂态的信号。基于以上特点,轻触开关通常被广泛地运用于 “+ ”、 “-”键置数和复位按钮等。

(2) 轻触开关的内部结构。轻触开关的几种内部结构如图5‑1所示。

图5‑1 轻触开关的几种内部结构

按键是在设计中常见的装置,不论进行复位或者其他模块控制,按键电平检测都是必须的。

按键抖动通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。

图5‑2 按键过程电平抖动

如果在FPGA引脚上直接读取按键的电平,就会造成误触发,所以对于电平检测需要一些“措施”以保证每次读取的电平值都是实际的电平值。

一、  硬件消抖 :

所示利用RC 积分电路来达成杂波的滤除与波形修整的电路(如图5‑3 )。

在S1 ON 的瞬间由于接触弹跳的关系,会使A 点电压呈现高速的断续现象,再S1 OFF时亦然,详(如图2所示),然而由于电容两端电压需由电压经电阻慢慢充电才会上升,使得B 点电位缓步上升情形:S1 OFF 时亦然,电容电压经R 放电,使B 点电压缓缓下降。此一变化,经史密特反相修整后,可得一标准负脉波输出,如波形图C 点所示。

图5‑3 硬件消抖

用其他的各类触发器,锁存器亦可达到消抖效果。

二、软件消抖 :

软件消抖主要利用2.3UART协议相关知识,在此不再赘述。

1.1.2轻触开关的应用

5.1.2.1 轻触开关的普通应用

图5‑4 轻触开关的普通应用框图

表5‑1 消抖模块(debounce_module.v)模块间信号定义

模块间信号

管脚

传输方向

作用/说明

H2L_Sig

detect_module.v模块传输给delay_module.v

输入电平由高到低输出标志

L2H_Sig

detect_module.v模块传输给delay_module.v

输入电平由低到高输出标志

时序

没有特殊要求。

表5‑2 消抖模块(debounce_module.v)顶层模块信号定义

顶层模块

输入管脚

作用/说明

输出管脚

作用/说明

Pin_in

待检测电平输入引脚

Pin_Out

消抖之后的输出信号

时序

没有特殊要求。

图5‑4上是一个简单的按键消抖模块。设计的方法主要是由“电平检查模块”和“10ms 延迟模块”组合合成。

设计的思路如下:

1) 一但检测到按键资源按下(高电平到低电平变化),“电平检查模块” 就会拉高H2L_Sig 电平,然后拉低。

2) “10ms 延迟模块”,检测到 H2L_Sig 高电平,就会利用 10ms 过滤 H2L_Sig,拉高输出。

3) 当按键被释放“电平检测模块”,会拉高 L2H_Sig 电平,然后拉低。

4) “10ms 延迟模块”,检查到 L2H_Sig 就会利用 10ms 过滤 H2L_Sig,然后拉低输出。

电平检测模块详见2.3.4实用UART传输FPGA实现介绍。

图5‑5 10ms 延迟模块

代码5‑1 10ms 延迟模块

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-06-05 21:05:29

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-05 21:15:41

7.//# Description:

8.//# @Modification History: 2012-10-03 16:26:17

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2012-10-03 16:26:17

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module delay_module

17.(

18.    CLOCK, RST_n, H2L_Sig, L2H_Sig, Pin_Out

19.);

20.

21.    input CLOCK;

22.     input RST_n;

23.     input H2L_Sig;

24.     input L2H_Sig;

25.     output Pin_Out;

26.

27.     /****************************************/

28.

29.     parameter T1MS = 16'd49_999;//DB4CE15开发板使用的晶振为50MHz,50M*0.001-1=49_999

30.

31.     /***************************************/

32.

33.     reg [15:0]Count1;

34.

35.     always @ ( posedge CLOCK or negedge RST_n )

36.         if( !RST_n )

37.              Count1 <= 16'd0;

38.          else if( isCount && Count1 == T1MS )

39.              Count1 <= 16'd0;

40.          else if( isCount )

41.              Count1 <= Count1 + 1'b1;

42.          else if( !isCount )

43.              Count1 <= 16'd0;

44.

45.    /****************************************/

46.

47.    reg [3:0]Count_MS;

48.

49.     always @ ( posedge CLOCK or negedge RST_n )

50.        if( !RST_n )

51.              Count_MS <= 4'd0;

52.          else if( isCount && Count1 == T1MS )

53.              Count_MS <= Count_MS + 1'b1;

54.          else if( !isCount )

55.              Count_MS <= 4'd0;

56.

57.    /******************************************/

58.

59.    reg isCount;

60.    reg rPin_Out;

61.    reg [1:0]i;

62.

63.    always @ ( posedge CLOCK or negedge RST_n )

64.        if( !RST_n )

65.             begin

66.                 isCount <= 1'b0;

67.                    rPin_Out <= 1'b0;

68.                    i <= 2'd0;

69.              end

70.         else

71.              case ( i )

72.

73.                    2'd0 :

74.                     if( H2L_Sig ) i <= 2'd1;

75.                     else if( L2H_Sig ) i <= 2'd2;

76.

77.                    2'd1 :

78.                     if( Count_MS == 4'd10 ) begin isCount <= 1'b0; rPin_Out <= 1'b1; i <= 2'd0; end

79.                    else    isCount <= 1'b1;

80.

81.                     2'd2 :

82.                     if( Count_MS == 4'd10 ) begin isCount <= 1'b0; rPin_Out <= 1'b0; i <= 2'd0; end

83.                    else    isCount <= 1'b1;

84.

85.

86.                endcase

87.

88.    /********************************************/

89.

90.     assign Pin_Out = rPin_Out;

91.

92.     /********************************************/

93.

94.

95.

96.endmodule

45~86 行的设计思路:

1) 如果 H2L_Sig 信号有反应,就进入步骤 1;

2) 在进入步骤 1 之后,由于达不到 if 条件, isCount 使能。定时器,计数器呀开始执行。

3)在经过 10ms 之后, isCount 不使能,定时器,计数器停止执行。rPin_Out 为逻辑 1。返回步骤 0。

又或者:

1)如果 L2H_Sig 信号有反应,就进入步骤 2,

2)在进入步骤 2 之后,由于达不到 if 条件, isCount 使能。定时器,计数器呀开始执行。

3)在经过 10ms 之后, isCount 不使能,定时器,计数器停止执行。rPin_Out 为逻辑 0。返回步骤 0。

最后就是将上述模块封装,封装的结构框图如图5‑4所示。

代码5‑2 模块封装

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-06-05 21:05:29

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-05 21:15:43

7.//# Description:

8.//# @Modification History: 2010-08-07 14:36:26

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2010-08-07 14:36:26

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module debounce_module

17.(

18.    CLOCK, RST_n, Pin_In, Pin_Out

19.);

20.

21.     input CLOCK;

22.     input RST_n;

23.     input Pin_In;

24.     output Pin_Out;

25.

26.     /**************************/

27.

28.     wire H2L_Sig;

29.     wire L2H_Sig;

30.

31.     detect_module U1

32.     (

33.         .CLOCK( CLOCK ),

34.          .RST_n( RST_n ),

35.          .Pin_In( Pin_In ),   // input - from top

36.          .H2L_Sig( H2L_Sig ), // output - to U2

37.          .L2H_Sig( L2H_Sig )  // output - to U2

38.     );

39.

40.     /**************************/

41.

42.     delay_module U2

43.     (

44.         .CLOCK( CLOCK ),

45.          .RST_n( RST_n ),

46.          .H2L_Sig( H2L_Sig ), // input - from U1

47.          .L2H_Sig( L2H_Sig ), // input - from U1

48.          .Pin_Out( Pin_Out )  // output - to top

49.     );

50.

51.     /*******************************/

52.

53.endmodule

完成后RTL如下:

图5‑6 轻触开关普通应用RTL

编译后将程序下载到板子上,按按键后,对应的输出引脚的LED灯就会随着按键按下而被点亮,而且不会出现亮多次或者点不亮的情况。

5.1.2.2 轻触开关的点击与长按

在使用轻触开关时,还会出现长按的使用情景,例如长按“关机”。轻触开关的长按的基本理论和5.1.2.1节一样,首先看下整个模块结构:

图5‑7 轻触开关的点击与长按

表5‑3 点击与长按(SClicKLClick_module.v)模块间信号定义

模块间信号

管脚

传输方向

作用/说明

Pin_Out[1:0]

keyfuncmod_module.v模块传输给led_module.v

Pin_Out[1]-点击isSClick,

Pin_Out[0]-长点击 isLClick

时序

没有特殊要求。

表5‑4 点击与长按(SClicKLClick_module.v)顶层模块信号定义

顶层模块

输入管脚

作用/说明

输出管脚

作用/说明

KEY

待检测电平输入引脚

LED[1:0]

KEY的输出信号

时序

没有特殊要求。

图5‑7是一个简单的点击与长按模块。设计的方法主要是由“按键功能模块”和“LED显示模块”组合合成,“按键功能模块”主要做“点击”和“长按击”检测。

“按键功能模块”中电平检测思路详见2.3.4实用UART传输FPGA实现节介绍。设计的思路如图所示:

图5‑8 点击与长按模块设计框图及思路

代码5‑3 点击与长按模块设计代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-06-09 00:13:23

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-09 01:29:16

7.//# Description:

8.//# @Modification History: 2019-06-09 01:29:16

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-06-09 01:29:16

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module keyfuncmod_module

17.(

18.    CLOCK, RST_n,

19.    KEY,

20.    Pin_Out

21.);

22.

23.   input CLOCK, RST_n;

24.    input KEY;

25.    output [1:0]Pin_Out;

26.

27.    /*****************************************/ //sub

28.     parameter T10MS = 26'd500_000;   // Deboucing time

29.     parameter T3S = 28'd150_000_000; // Long press time

30.

31.     /*****************************************/ //sub

32.

33.     reg F2,F1;

34.

35.     always @ ( posedge CLOCK or negedge RST_n )

36.         if( !RST_n )

37.              { F2, F1 } <= 2'b11;

38.          else

39.              { F2, F1 } <= { F1, KEY };

40.

41.     /*****************************************/ //core

42.

43.     wire isH2L = ( F2 == 1 && F1 == 0 );

44.     wire isL2H = ( F2 == 0 && F1 == 1 );

45.     reg [3:0]i;

46.     reg isLClick,isSClick;

47.     reg [1:0]isTag;

48.     reg [27:0]C1;

49.

50.     always @ ( posedge CLOCK or negedge RST_n )

51.         if( !RST_n )

52.               begin

53.                    i <= 4'd0;

54.                     isLClick <= 1'd0;

55.                     isSClick <= 1'b0;

56.                     isTag <= 2'd0;

57.                     C1 <= 28'd0;

58.                 end

59.          else

60.              case(i)

61.

62.                     0: // Wait H2L

63.                     if( isH2L ) i <= i + 1'b1;

64.

65.                     1: // H2L debouce

66.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end

67.                     else C1 <= C1 + 1'b1;

68.

69.                     2: // Key Tag Check

70.                     if( isL2H ) begin isTag <= 2'd1; C1 <= 28'd0; i <= i="" end="" span="" style="font-size:9.0pt; font-family:Consolas; color:#0000FF; mso-font-kerning:0.0pt" p="" b00="" c1="">= T3S -1 ) begin isTag <= 2'd2; C1 <= 28'd0; i <= i + 1'd1; end

72.                     else C1 <= C1 + 1'b1;

73.

74.                     3: // Tag Trigger (pree up)

75.                     if( isTag == 2'd1 ) begin isSClick <= 1'b1; i <= i + 1'b1; end

76.                     else if( isTag == 2'd2 ) begin isLClick <= 1'b1; i <= i + 1'b1; end

77.

78.                     4: // Tag Trigger (pree down)

79.                     begin { isLClick,isSClick } <= 2'b00; i <= i + 1'b1; end

80.

81.                     5: // L2H deboce check

82.                     if( isTag == 2'd1 ) begin isTag <= 2'd0; i <= i + 2'd2; end

83.                     else if( isTag == 2'd2 ) begin isTag <= 2'd0; i <= i + 1'b1; end

84.

85.                     6: // Wait L2H

86.                     if( isL2H )i <= i + 1'b1;

87.

88.                     7: // L2H debonce

89.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= 4'd0; end

90.                     else C1 <= C1 + 1'b1;

91.

92.                endcase

93.

94.    /*************************/

95.

96.    assign Pin_Out = { isSClick,isLClick };

97.

98.endmodule

其他模块就不再赘述,按照图5‑8进行整个模块的连接,整个模块的RTL如下所示:

图5‑9 点击与长按模块设计RTL

和图5‑8一样,综合下载后,第一次按下 3 秒不放会点亮 LED[1],换之按下不到 3秒便释放则会点亮 LED[0]。第二次按下3 秒不放会消灭 LED[0],按下不到 3 秒便释放会消灭 LED[0]。如此一来,实验已经完成。

5.1.2.3 轻触开关的单击与双击

在使用轻触开关时,还会出现双击的使用情景。轻触开关的双击的基本理论和5.1.2.2节一样。

双击实现起来,会比较麻烦一些,因为还要考虑额外的细节,即人为连打极限。所谓人为连打极限就是两次按下按键之间的最短间隔。

图5‑10 双击有效按键,时序示意图(双击成功)

常人的连打极限是 60ms 左右,超人是 20ms 左右。为了兼容常人的连打极限,我们必须设置有效的连击时限,为此 100ms 是最好的选择。如图5‑10所示,假设那是按键过程,笔者先是缓缓按下然后又缓缓释放按键完成第一次按键行为,结果有如往常般,按下事件发生,抖动发生,释放事件发生,抖动发生,但是 isDClick( Double Click) 信号还有 isSClick( Single Click)信号都没有产生高脉冲。第一次按键完成以后就会引来第二次按键的黄金时间,亦即有效连击时限,在此笔者设为 100ms。假设笔者在这 100ms 的黄金时间内按下按键,那么 isDClick 信号会立即产生高脉冲。余下有如往常那样,抖动发生,释放事件发生,抖动发生 ... 对此, isSClick由始至终都没有状况发生

图5‑11 双击有效按键,时序示意图(双击失败)

假设没在有限的 100ms 黄金时间内执行第二次按键按下的动作,那么“双击”就会失败,结果如图5‑11所示。第一次按键过程与图5‑10一样,反之第二次按键却不同了,如图5‑11所示,第二次按键的按下事件是发生在 100ms 以后,为此 isSClick 产生高脉冲,然而 isDClick 信号却没有动静。

接下来看下整个模块结构:

图5‑12 轻触开关的单击与双击框图

表5‑5 点击与双击(SClickDClick_module.v)模块间信号定义

模块间信号

管脚

传输方向

作用/说明

Pin_Out[1:0]

keyfuncmod_module.v模块传输给led_module.v

Pin_Out[1]-点击isSClick,

Pin_Out[0]-长点击 isDClick

时序

没有特殊要求。

表5‑6 点击与长按(SClicKLClick_module.v)顶层模块信号定义

顶层模块

输入管脚

作用/说明

输出管脚

作用/说明

KEY

待检测电平输入引脚

LED[1:0]

KEY的输出信号

时序

没有特殊要求。

图5‑12上是一个简单的点击与长按模块。设计的方法主要是由“按键功能模块”和“LED显示模块”组合合成,“按键功能模块”主要做“点击”和“长按击”检测。

“按键功能模块”中电平检测思路详见2.3.4实用UART传输FPGA实现节介绍。设计的思路如图所示:

图5‑13 点击与长按设计思路及框图

代码5‑4 点击与长按设计代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-06-09 02:48:43

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-09 02:52:59

7.//# Description:

8.//# @Modification History: 2019-06-09 02:52:59

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-06-09 02:52:59

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module keyfuncmod_module

17.(

18.    CLOCK, RST_n,

19.    KEY,

20.    Pin_Out

21.);

22.

23.   input CLOCK, RST_n;

24.    input KEY;

25.    output [1:0]Pin_Out;

26.

27.    /*****************************************/ //sub

28.    parameter T10MS     = 28'd500_000;

29.    parameter T100MS    = 28'd5_000_000;

30.    parameter T200MS    = 28'd10_000_000;

31.    parameter T300MS    = 28'd15_000_000;

32.    parameter T400MS    = 28'd20_000_000;

33.    parameter T500MS    = 28'd25_000_000;

34.    /*****************************************/ //sub

35.

36.     reg F2,F1;

37.

38.     always @ ( posedge CLOCK or negedge RST_n )

39.         if( !RST_n )

40.              { F2, F1 } <= 2'b11;

41.          else

42.              { F2, F1 } <= { F1, KEY };

43.

44.     /*****************************************/ //core

45.

46.     wire isH2L = ( F2 == 1 && F1 == 0 );

47.     wire isL2H = ( F2 == 0 && F1 == 1 );

48.     reg [3:0]i;

49.     reg isDClick,isSClick;

50.     reg [1:0]isTag;

51.     reg [27:0]C1;

52.

53.     always @ ( posedge CLOCK or negedge RST_n )

54.         if( !RST_n )

55.               begin

56.                    i <= 4'd0;

57.                     isDClick <= 1'd0;

58.                     isSClick <= 1'b0;

59.                     isTag <= 2'd0;

60.                     C1 <= 28'd0;

61.                 end

62.          else

63.              case(i)

64.

65.                     0: // Wait H2L

66.                     if( isH2L ) begin i <= i + 1'b1; end

67.

68.                     1: // H2L debounce

69.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end

70.                     else C1 <= C1 + 1'b1;

71.

72.                     2: // Wait L2H

73.                     if( isL2H ) i <= i + 1'b1;

74.

75.                     3: // L2H debounce

76.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end

77.                     else C1 <= C1 + 1'b1;

78.

79.                     4: // Key Tag Check

80.                     if( isH2L && C1 <= T100MS -1 ) begin isTag <= 2'd2; C1 <= 28'd0; i <= i + 1'b1; end

81.                     else if( C1 >= T100MS -1) begin isTag <= 2'd1; C1 <= 28'd0; i <= i + 1'b1; end

82.                     else C1 <= C1 + 1'b1;

83.

84.                     5: // Key trigger press up

85.                     if( isTag == 2'd2 ) begin isDClick <= 1'b1; i <= i + 1'b1; end

86.                     else if( isTag == 2'd1 ) begin isSClick <= 1'b1; i <= i + 1'b1; end

87.

88.                     6: // Key trigger pree down

89.                     begin { isSClick , isDClick } <= 2'b00; i <= i + 1'b1; end

90.

91.                     7: // L2H deounce check

92.                     if( isTag == 2'd1 ) begin isTag <= 2'd0; i <= 4'd0; end

93.                     else if( isTag == 2'd2 ) begin isTag <= 2'd0; i <= i + 1'b1; end

94.

95.                     8: // Wait L2H

96.                     if( isL2H ) begin i <= i + 1'b1; end

97.

98.                    9: // L2H debounce

99.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= 4'd0; end

100.                     else C1 <= C1 + 1'b1;

101.

102.                endcase

103.

104.    /***************************/

105.

106.    assign Pin_Out = { isSClick,isDClick };

107.

108.endmodule

其他模块就不再赘述,按照图5‑13进行整个模块的连接,整个模块的RTL如下所示:

图5‑14 点击与长按设计RTL

和图5‑13一样,综合下载后,当我们双击 建 LED[1] 就会发亮,然后再双击建 LED[1] 则会消灭,发生双击的前提条件是 ... 第一次按下时间的 100ms 之内必须发生第二次按下时间才能成立。换之,如果我们单击 建 LED[0] 便会发亮,再单击建LED[0]则会消灭。

5.1.2.4 轻触开关的单击、双击与长点击

最后将轻触开关的单击、双击与长点击进行组合,与上两节不同的是,两个组合检测在使用的时候检测条件比较简单,但是三个组合比较麻烦,核心操作会优先判断按键是否“长点击”,然后再来判断“点击”还是“双点击”,期间绝对不能搞错判断的次序。下面简单讲解下实现思路。

接下来看下整个模块结构:

图5‑15 轻触开关的单击、双击与长点击组合框图

表5‑7 轻触开关的单击、双击与长点(SClickDClick_module.v)模块间信号定义

模块间信号

管脚

传输方向

作用/说明

Pin_Out[1:0]

keyfuncmod_module.v模块传输给led_module.v

Pin_Out[1]-点击isSClick,

Pin_Out[0]-长点击 isDClick

时序

没有特殊要求。

表5‑8 轻触开关的单击、双击与长点(SClicKLClick_module.v)顶层模块信号定义

顶层模块

输入管脚

作用/说明

输出管脚

作用/说明

KEY

待检测电平输入引脚

LED[1:0]

KEY的输出信号

时序

没有特殊要求。

图5‑15上是一个简单的点击与长按模块。设计的方法主要是由“按键功能模块”和“LED显示模块”组合合成,“按键功能模块”主要做“点击”和“长按击”检测。

“按键功能模块”中电平检测思路详见2.3.4实用UART传输FPGA实现节介绍。设计的思路如图所示:

图5‑16 轻触开关的单击、双击与长点设计思路及框图

代码5‑5 轻触开关的单击、双击与长点设计代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-06-09 03:17:04

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-09 03:22:34

7.//# Description:

8.//# @Modification History: 2019-06-09 03:22:34

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-06-09 03:22:34

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module keyfuncmod_module

17.(

18.    CLOCK, RST_n,

19.    KEY,

20.    Pin_Out

21.);

22.

23.   input CLOCK, RST_n;

24.    input KEY;

25.    output [2:0]Pin_Out;

26.

27.    /*****************************************/ //sub

28.    parameter T10MS     = 28'd500_000;

29.    parameter T100MS    = 28'd5_000_000;

30.    parameter T200MS    = 28'd10_000_000;

31.    parameter T300MS    = 28'd15_000_000;

32.    parameter T400MS    = 28'd20_000_000;

33.    parameter T500MS    = 28'd25_000_000;

34.    parameter T3S           = 28'd150_000_000;

35.    /*****************************************/ //sub

36.

37.     reg F2,F1;

38.

39.     always @ ( posedge CLOCK or negedge RST_n )

40.         if( !RST_n )

41.              { F2, F1 } <= 2'b11;

42.          else

43.              { F2, F1 } <= { F1, KEY };

44.

45.     /*****************************************/ //core

46.

47.     wire isH2L = ( F2 == 1 && F1 == 0 );

48.     wire isL2H = ( F2 == 0 && F1 == 1 );

49.     reg [3:0]i;

50.     reg isLClick, isDClick,isSClick;

51.     reg [1:0]isTag;

52.     reg [27:0]C1;

53.

54.     always @ ( posedge CLOCK or negedge RST_n )

55.         if( !RST_n)

56.               begin

57.                    i <= 4'd0;

58.                     isLClick <= 1'b0;

59.                     isDClick <= 1'b0;

60.                     isSClick <= 1'b0;

61.                     isTag <= 2'd0;

62.                     C1 <= 28'd0;

63.                 end

64.          else

65.              case(i)

66.

67.                     0: // Wait H2L

68.                     if( isH2L ) begin i <= i + 1'b1; end

69.

70.                     1: // H2L debounce

71.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end

72.                     else C1 <= C1 + 1'b1;

73.

74.                     2: // Key Tag Check 1

75.                     if( isL2H ) begin C1 <= 28'd0; i <= i="" span="" style="font-size:9.0pt; font-family:Consolas; color:#0000FF; mso-font-kerning:0.0pt" end="" p="" b00="" c1="">= T3S -1 ) begin isTag <= 2'd3; C1 <= 28'd0; i <= 4'd5; end

77.                     else C1 <= C1 + 1'b1;

78.

79.                     3: // L2H debounce

80.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end

81.                     else C1 <= C1 + 1'b1;

82.

83.                     4: // Key Tag Check 2

84.                     if( isH2L && C1 <= T100MS -1 ) begin isTag <= 2'd2; C1 <= 28'd0; i <= i + 1'b1; end

85.                     else if( C1 >= T100MS -1) begin isTag <= 2'd1; C1 <= 28'd0; i <= i + 1'b1; end

86.                     else C1 <= C1 + 1'b1;

87.

88.                     5: // Key trigger press up

89.                     if( isTag == 2'd3 ) begin isLClick <= 1'b1; i <= i + 1'b1; end

90.                     else if( isTag == 2'd2 ) begin isDClick <= 1'b1; i <= i + 1'b1; end

91.                     else if( isTag == 2'd1 ) begin isSClick <= 1'b1; i <= i + 1'b1; end

92.

93.                     6: // Key trigger pree down

94.                     begin { isLClick, isSClick, isDClick } <= 3'b000; i <= i + 1'b1; end

95.

96.                     7: // L2H deounce check

97.                     if( isTag == 2'd1 ) begin isTag <= 2'd0; i <= i + 2'd2; end

98.                     else if( isTag == 2'd2 ) begin isTag <= 2'd0; i <= i + 1'b1; end

99.                     else if( isTag == 2'd3 ) begin isTag <= 2'd0; i <= i + 1'b1; end

100.

101.                     8: // Wait L2H

102.                     if( isL2H ) begin i <= i + 1'b1; end

103.

104.                    9: // L2H debounce

105.                     if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= 4'd0; end

106.                     else C1 <= C1 + 1'b1;

107.

108.                endcase

109.

110.    /***************************/

111.

112.    assign Pin_Out = { isSClick,isDClick,isLClick };

113.

114.endmodule

其他模块就不再赘述,按照图5‑16进行整个模块的连接,整个模块的RTL如下所示:

图5‑17 轻触开关的单击、双击与长点设计代码综合后RTL

和图5‑16一样,编译完后下载程序。如果点击一下 建,那么 LED[0] 会点亮,如果笔者双击建,结果 LED[1] 会点亮,再如果笔者长按建 3 秒不放,那么 LED[2] 则会点亮。总结说,一个按键资源可以执行 3 种功能,控制 3 位 LED 资源。

(0)

相关推荐

  • 凔海笔记之FPGA(八):Verilog描述RS232 UART

    在我看来,有些代码会用,但未必理解,有些代码理解,但未必会写,有些代码会写,但未必能用自己的话说出来.当能够以自己的想法深入浅出的讲解所学知识,那也就可以说自己掌握了,所以,我还是来发帖吧. 记得刚用 ...

  • 基于FPGA的数字电路实验7:流水灯的实现

    原创 Daniel收录于话题#数字电路9个继年前介绍的时序逻辑电路之时钟分频后,今天我们来介绍第7讲:流水灯.流水灯,有时候也叫跑马灯,是一个简单.有趣又经典的实验,基本所有单片机的玩家们在初期学习的 ...

  • 项目分享| 致敬经典收音机,围观制作过程

    不想错过我的推送,记得右上角-查看公众号-设为星标,摘下星星送给我 十多年前,收音机电路大多数还是采用分立元件构成的.现在用Arduino Nano和SparkFun Si4703 FM收音调谐模块就 ...

  • 一天一个设计实例-LCD12864的应用设计

    LCD12864的应用设计 LCD12864的应用基本和LCD1602的自定义字库非常类似,下面就简单介绍下LCD12864. 12864 中文 汉字图形点阵液晶显示模块,可显示汉字及图形,内置 81 ...

  • 一天一个设计实例-​LCD1602的应用设计

    LCD1602的应用设计 1.1.1LCD1602的简介 工业字符型液晶,能够同时显示16x02即32个字符.(16列2行) 图6‑16 LCD1602实物图 注:为了表示的方便 ,后文皆以1表示高电 ...

  • 一天一个设计实例-LED显示模块设计

    LED显示模块设计 LED点阵模块指的是利用封装8*8的模块组合点元板形成模块,而LED模组应用中一般指两类产品:一种是用插灯或表贴封装做成的单元板,常用户外门头单红屏.户外全彩屏,室内全彩屏等:另外 ...

  • 一天一个设计实例-基于FPGA的模数、数模转换器应用设计

    基于FPGA的模数.数模转换器应用设计 本节设计采用黑金ADDA模块,模块硬件结构如下: 图7‑32 硬件结构 数模转换( DA) 电路 如硬件结构图所示, DA 电路由高速 DA 芯片. 7 阶巴特 ...

  • 一天一个设计实例-基于FPGA的数模转换器应用设计

    基于FPGA的数模转换器应用设计 1.1.1带 EEPROM 存储器的 12 位MCP4725应用设计 7.4.1.1 MCP4725简介 MCP4725 是低功耗.高精度.单通道的 12 位缓冲电压 ...

  • 一天一个设计实例-基于FPGA的模数转换器应用设计

    基于FPGA的模数转换器应用设计 1.1.1八通道AD7606应用设计 7.3.1.1 AD7606简介 AD7606 是一款集成式 8 通道数据采集系统,片内集成输入放大器.过压保护电路.二阶模拟抗 ...

  • 一天一个设计实例-AD转换器原理

    AD转换器原理 A/D 转换器的基本原理 图7‑2 A/D转换器功能示意图 A/D转换器(Analog-to-Digital Converter)又叫模/数转换器,即是将模拟信号(电压或是电流的形式) ...

  • 一天一个设计实例-GPIO PWM应用

    GPIO PWM 1.1.1PWM简介 脉冲宽度调制脉冲宽度调制(PWM),是英文"Pulse Width Modulation"的缩写,简称脉宽调制,是利用微处理器的数字输出来对 ...

  • 一天一个设计实例-PS/2键盘及鼠标的应用设计

    PS/2键盘及鼠标的应用设计 1.1.1键盘与单次操作 PS/2接口用于许多现代的鼠标和键盘,由IBM最初开发和使用.物理上的PS/2接口有两种类型的连接器:5脚的DIN和6脚的mini-DIN.图1 ...