【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验五:按键模块④ — 点击,长点击,双击

简介: 实验五:按键模块④ — 点击,长点击,双击 实验二至实验四,我们一共完成如下有效按键: l 点击(按下有效) l 点击(释放有效) l 长击(长按下有效) l 双击(连续按下有效) 然而,不管哪个实验都是只有两项“功能”的按键模块而已,如今我们要创建三项“功能”的按键模块,亦即点击(按下有效),长击,还有双击。

实验五:按键模块④ — 点击,长点击,双击

实验二至实验四,我们一共完成如下有效按键:

l 点击(按下有效)

l 点击(释放有效)

l 长击(长按下有效)

l 双击(连续按下有效)

然而,不管哪个实验都是只有两项“功能”的按键模块而已,如今我们要创建三项“功能”的按键模块,亦即点击(按下有效),长击,还有双击。实验继续之前,让我们先来复习一下各种有效按键。

clip_image002

图5.1 点击(按下有效)。

如图5.1所示,所谓点击(按下有效)就是按键按下以后,isSClick信号(Single Click)

产生一个高脉冲。

clip_image004

图5.2 长点击。

如图5.2所示,所谓长点击就是按键按下以后,长达3秒不放,isLClick信号(Long Click)

就会产生一个高脉冲。

clip_image006

图5.3 双点击。

如图5.3所示,所谓双点击就是距离第一次“点击(按下有效)”,如果在有效的连击时限内容完成第二次“点击(按下有效)”,那么isDClick信号(Double Click)就会产生一个高脉冲。

话语上,实验五虽然要整合3项按键功能,然而实验五相较实验二至实验四却有一定程度的难度。那是因为仅有两项功能的按键模块,仅需判断一次性的有效按键而已,反之三项功能的按键模块却要分开二次判断,而且判断也要有序。根据实验五,核心操作会优先判断按键是否“长点击”,然后再来判断“点击”还是“双点击”。期间绝对不能搞错判断的次序。

具体内容,我们还是直接来看代码吧:

clip_image008

图5.4 实验五的建模图。

如图5.4所示,那是实验五的按键功能模块,输入端一边是连接至按键资源的KEY信号,输出端另一边则是连接至3位LED资源的LED信号。

key_funcmod.v
1.    module key_funcmod
2.    (
3.         input CLOCK, RESET,
4.         input KEY,
5.         output [2:0]LED
6.    );

以上为相关的出入端声明。

7.         parameter T10MS         = 28'd500_000;
8.         parameter T100MS     = 28'd5_000_000; 
9.         parameter T200MS     = 28'd10_000_000; 
10.         parameter T300MS     = 28'd15_000_000; 
11.         parameter T400MS     = 28'd20_000_000; 
12.         parameter T500MS     = 28'd25_000_000; 
13.         parameter T3S        = 28'd150_000_000; 
14.         
15.         /**********************************/ //sub
16.         
17.         reg F2,F1;
18.             
19.         always @ ( posedge CLOCK or negedge RESET )
20.             if( !RESET ) 
21.                  { F2, F1 } <= 2'b11;
22.              else 
23.                  { F2, F1 } <= { F1, KEY };
24.                    
25.         /**********************************/ //core
26.        
27.         wire isH2L = ( F2 == 1 && F1 == 0 );
28.         wire isL2H = ( F2 == 0 && F1 == 1 );

以上内容是时间常量声明以及周边操作。第17~23行是检测电平状态的周边操作,第27~28行则是按下事件还有释放事件的声明。

29.         reg [3:0]i;
30.         reg isLClick, isDClick,isSClick;
31.         reg [1:0]isTag;
32.         reg [27:0]C1;
33.         
34.         always @ ( posedge CLOCK or negedge RESET )
35.             if( !RESET )
36.                   begin
37.                         i <= 4'd0;
38.                         isLClick <= 1'b0;
39.                         isDClick <= 1'b0;
40.                         isSClick <= 1'b0;
41.                         isTag <= 2'd0;
42.                         C1 <= 28'd0;
43.                     end
44.              else

以上内容为相关的寄存器声明以及复位操作。i指向步骤,寄存器isLClick,寄存器isDClick,还有寄存器isSClick则是相关的“有效按键”标志。isTag表示“有效按键”的标签,1为“点击”,2为“双点击”,3为“长点击”。C1用来计数。第35~43行则是相关的复位操作。

45.           case(i)
46.                         
47.                0: // Wait H2L
48.                if( isH2L ) begin i <= i + 1'b1; end
49.                         
50.                1: // H2L debounce
51.                if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
52.                else C1 <= C1 + 1'b1;
53.                         
54.                2: // Key Tag Check 1
55.                if( isL2H ) begin C1 <= 28'd0; i <= i + 1'b1; end
56.                else if( {F2,F1} == 2'b00 && C1 >= T3S -1 ) begin isTag <= 2'd3; C1 <= 28'd0; i <= 4'd5; end
57.                else C1 <= C1 + 1'b1;    
58.                         
59.                3: // L2H debounce
60.                if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
61.                else C1 <= C1 + 1'b1;
62.                         
63.                4: // Key Tag Check 2      
64.                if( isH2L && C1 <= T100MS -1 ) begin isTag <= 2'd2; C1 <= 28'd0; i <= i + 1'b1; end
65.                else if( C1 >= T100MS -1) begin isTag <= 2'd1; C1 <= 28'd0; i <= i + 1'b1; end
66.                else C1 <= C1 + 1'b1;    
67.                         
68.                5: // Key trigger press up
69.                if( isTag == 2'd3 ) begin isLClick <= 1'b1; i <= i + 1'b1; end
70.                else if( isTag == 2'd2 ) begin isDClick <= 1'b1; i <= i + 1'b1; end
71.                else if( isTag == 2'd1 ) begin isSClick <= 1'b1; i <= i + 1'b1; end
72.                         
73.                6: // Key trigger pree down
74.                begin { isLClick, isSClick, isDClick } <= 3'b000; i <= i + 1'b1; end
75.                         
76.                7: // L2H deounce check
77.                if( isTag == 2'd1 ) begin isTag <= 2'd0; i <= i + 2'd2; end
78.                else if( isTag == 2'd2 ) begin isTag <= 2'd0; i <= i + 1'b1; end
79.                else if( isTag == 2'd3 ) begin isTag <= 2'd0; i <= i + 1'b1; end
80.                         
81.                8: // Wait L2H
82.                if( isL2H ) begin i <= i + 1'b1; end
83.                             
84.                9: // L2H debounce
85.                if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= 4'd0; end
86.                 else C1 <= C1 + 1'b1;
87.                         
88.          endcase

第45~88行是核心操作,具体的操作过程如下:

步骤0,等待第一次按下事件;

步骤1,过滤抖动;

步骤2,检测是不是长点击,如果是isTag为3然后出发步骤5,否则等待释放事件;

步骤3,过滤抖动;

步骤4,检测是不是双击,如果是isTag为2,否则S为1;

步骤5~6,根据isTag内容产生高脉冲;

步骤7,根据isTag内容检测是否需要过滤抖动,isTag为1直接返回步骤0,其它需要;

步骤8,等待释放事件;

步骤9,过滤抖动然后返回步骤0.

89.         
90.        /*************************/ // sub-demo            
91.        
92.        reg [2:0]D1;
93.        
94.        always @ ( posedge CLOCK or negedge RESET )
95.            if( !RESET )
96.                 D1 <= 2'd0;
97.             else if( isLClick )
98.                 D12] <= ~D1[2];
99.             else if( isDClick )
100.                 D1[1] <= ~D1[1];
101.             else if( isSClick )
102.                 D1[0] <= ~D1[0];
103.                  
104.        /***************************/
105.             
106.        assign LED = D1;
107.    
108.    endmodule

以上内容为演示用的周边操作以及输出驱动。它会根据各种“有效按键”翻转D1的内容。第106行则是输出驱动的声明。编译完后下载程序。

如果笔者点击一下 <KEY1> 建,那么LED[0] 会点亮,如果笔者双击 <KEY1> 建,结果 LED[1] 会点亮,再如果笔者长按 <KEY1> 建 3秒不放,那么 LED[2] 则会点亮。总结说,一个按键资源可以执行3种功能,控制3位LED资源。

细节一:完整的个体模块

clip_image010

图5.5 完整的按键功能模块。

如图5.5所示,那是完整的按键功能模块,它有一位输入端KEY连接至按键资源,然后则有3位触发信号,Trig[2]产生“单击”的个高脉冲,Trig[1] 产生“双击”的个高脉冲,Trig[0]产生“长击”的个高脉冲

key_funcmod.v
1.    module key_funcmod
2.    (
3.         input CLOCK, RESET,
4.         input KEY,
5.         output [2:0]oTrig
6.    );
7.         parameter T10MS         = 28'd500_000;
8.         parameter T100MS     = 28'd5_000_000; 
9.         parameter T200MS     = 28'd10_000_000; 
10.         parameter T300MS     = 28'd15_000_000; 
11.         parameter T400MS     = 28'd20_000_000; 
12.         parameter T500MS     = 28'd25_000_000; 
13.         parameter T3S        = 28'd150_000_000; 
14.         
15.         /**********************************/ //sub
16.         
17.         reg F2,F1;
18.             
19.         always @ ( posedge CLOCK or negedge RESET )
20.             if( !RESET ) 
21.                  { F2, F1 } <= 2'b11;
22.              else 
23.                  { F2, F1 } <= { F1, KEY };
24.                    
25.         /**********************************/ //core
26.        
27.         wire isH2L = ( F2 == 1 && F1 == 0 );
28.         wire isL2H = ( F2 == 0 && F1 == 1 );
29.         reg [3:0]i;
30.         reg isLClick, isDClick,isSClick;
31.         reg [1:0]isTag;
32.         reg [27:0]C1;
33.         
34.         always @ ( posedge CLOCK or negedge RESET )
35.             if( !RESET )
36.                   begin
37.                        i <= 4'd0;
38.                         isLClick <= 1'b0;
39.                         isDClick <= 1'b0;
40.                         isSClick <= 1'b0;
41.                         isTag <= 2'd0;
42.                         C1 <= 28'd0;
43.                     end
44.              else
45.                  case(i)
46.                         
47.                         0: // Wait H2L
48.                         if( isH2L ) begin i <= i + 1'b1; end
49.                         
50.                         1: // H2L debounce
51.                         if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
52.                         else C1 <= C1 + 1'b1;
53.                         
54.                         2: // Key Tag Check 1
55.                         if( isL2H ) begin C1 <= 28'd0; i <= i + 1'b1; end
56.                         else if( {F2,F1} == 2'b00 && C1 >= T3S -1 ) begin isTag <= 2'd3; C1 <= 28'd0; i <= 4'd5; end
57.                         else C1 <= C1 + 1'b1;    
58.                         
59.                         3: // L2H debounce
60.                         if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= i + 1'b1; end
61.                         else C1 <= C1 + 1'b1;
62.                         
63.                         4: // Key Tag Check 2      
64.                         if( isH2L && C1 <= T100MS -1 ) begin isTag <= 2'd2; C1 <= 28'd0; i <= i + 1'b1; end
65.                         else if( C1 >= T100MS -1) begin isTag <= 2'd1; C1 <= 28'd0; i <= i + 1'b1; end
66.                         else C1 <= C1 + 1'b1;    
67.                         
68.                         5: // Key trigger press up
69.                         if( isTag == 2'd3 ) begin isLClick <= 1'b1; i <= i + 1'b1; end
70.                         else if( isTag == 2'd2 ) begin isDClick <= 1'b1; i <= i + 1'b1; end
71.                         else if( isTag == 2'd1 ) begin isSClick <= 1'b1; i <= i + 1'b1; end
72.                         
73.                         6: // Key trigger pree down
74.                         begin { isLClick, isSClick, isDClick } <= 3'b000; i <= i + 1'b1; end
75.                         
76.                         7: // L2H deounce check
77.                         if( isTag == 2'd1 ) begin isTag <= 2'd0; i <= i + 2'd2; end
78.                         else if( isTag == 2'd2 ) begin isTag <= 2'd0; i <= i + 1'b1; end
79.                         else if( isTag == 2'd3 ) begin isTag <= 2'd0; i <= i + 1'b1; end
80.                         
81.                         8: // Wait L2H
82.                         if( isL2H ) begin i <= i + 1'b1; end
83.                             
84.                         9: // L2H debounce
85.                         if( C1 == T10MS -1 ) begin C1 <= 28'd0; i <= 4'd0; end
86.                         else C1 <= C1 + 1'b1;
87.                         
88.                    endcase
89.                  
90.        /***************************/
91.             
92.        assign oTrig = { isSClick,isDClick,isLClick };
93.    
94.    endmodule
目录
相关文章
|
23天前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的16QAM调制+软解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本项目基于FPGA实现了16QAM基带通信系统,包括调制、信道仿真、解调及误码率统计模块。通过Vivado2019.2仿真,设置不同SNR(如8dB、12dB),验证了软解调相较于传统16QAM系统的优越性,误码率显著降低。系统采用Verilog语言编写,详细介绍了16QAM软解调的原理及实现步骤,适用于高性能数据传输场景。
129 69
|
6天前
|
数据采集 算法 测试技术
【硬件测试】基于FPGA的QPSK调制解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的QPSK调制解调系统的硬件实现与仿真效果。系统包含测试平台(testbench)、高斯信道模块、误码率统计模块,支持不同SNR设置,并增加了ILA在线数据采集和VIO在线SNR设置功能。通过硬件测试验证了系统在不同信噪比下的性能,提供了详细的模块原理及Verilog代码示例。开发板使用说明和移植方法也一并给出,确保用户能顺利在不同平台上复现该系统。
48 15
|
28天前
|
移动开发 算法 数据安全/隐私保护
基于FPGA的QPSK调制+软解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的QPSK调制解调系统,通过Vivado 2019.2进行仿真,展示了在不同信噪比(SNR=1dB, 5dB, 10dB)下的仿真效果。与普通QPSK系统相比,该系统的软解调技术显著降低了误码率。文章还详细阐述了QPSK调制的基本原理、信号采样、判决、解调及软解调的实现过程,并提供了Verilog核心程序代码。
66 26
|
14天前
|
数据采集 算法 数据安全/隐私保护
【硬件测试】基于FPGA的2FSK调制解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文介绍了基于FPGA的2FSK调制解调系统,包含高斯信道、误码率统计模块及testbench。系统增加了ILA在线数据采集和VIO在线SNR设置模块,支持不同SNR下的硬件测试,并提供操作视频指导。理论部分涵盖频移键控(FSK)原理,包括相位连续与不连续FSK信号的特点及功率谱密度特性。Verilog代码实现了FSK调制解调的核心功能,支持在不同开发板上移植。硬件测试结果展示了不同SNR下的性能表现。
57 6
|
2月前
|
算法 异构计算
基于FPGA的4ASK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的4-ASK调制解调系统的算法仿真效果、理论基础及Verilog核心程序。仿真在Vivado2019.2环境下进行,分别测试了SNR为20dB、15dB、10dB时的性能。理论部分概述了4-ASK的工作原理,包括调制、解调过程及其数学模型。Verilog代码实现了4-ASK调制器、加性高斯白噪声(AWGN)信道模拟、解调器及误码率计算模块。
65 8
|
2月前
|
算法 物联网 异构计算
基于FPGA的4FSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的4FSK调制解调系统的Verilog实现,包括高斯信道模块和误码率统计模块,支持不同SNR设置。系统在Vivado 2019.2上开发,展示了在不同SNR条件下的仿真结果。4FSK调制通过将输入数据转换为四个不同频率的信号来提高频带利用率和抗干扰能力,适用于无线通信和数据传输领域。文中还提供了核心Verilog代码,详细描述了调制、加噪声、解调及误码率计算的过程。
64 11
|
2月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的1024QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的1024QAM调制解调系统的仿真与实现。通过Vivado 2019.2进行仿真,分别在SNR=40dB和35dB下验证了算法效果,并将数据导入Matlab生成星座图。1024QAM调制将10比特映射到复数平面上的1024个星座点之一,适用于高数据传输速率的应用。系统包含数据接口、串并转换、星座映射、调制器、解调器等模块。Verilog核心程序实现了调制、加噪声信道和解调过程,并统计误码率。
50 1
|
3月前
|
算法 数据安全/隐私保护 异构计算
基于FPGA的64QAM基带通信系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本文介绍了基于FPGA的64QAM调制解调通信系统的设计与实现,包括信号生成、调制、解调和误码率测试。系统在Vivado 2019.2中进行了仿真,通过设置不同SNR值(15、20、25)验证了系统的性能,并展示了相应的星座图。核心程序使用Verilog语言编写,加入了信道噪声模块和误码率统计功能,提升了仿真效率。
59 4
|
3月前
|
监控 算法 数据安全/隐私保护
基于三帧差算法的运动目标检测系统FPGA实现,包含testbench和MATLAB辅助验证程序
本项目展示了基于FPGA与MATLAB实现的三帧差算法运动目标检测。使用Vivado 2019.2和MATLAB 2022a开发环境,通过对比连续三帧图像的像素值变化,有效识别运动区域。项目包括完整无水印的运行效果预览、详细中文注释的代码及操作步骤视频,适合学习和研究。
|
3月前
|
存储 算法 数据处理
基于FPGA的8PSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR
本系统在原有的8PSK调制解调基础上,新增了高斯信道与误码率统计模块,验证了不同SNR条件下的8PSK性能。VIVADO2019.2仿真结果显示,在SNR分别为30dB、15dB和10dB时,系统表现出不同的误码率和星座图分布。8PSK作为一种高效的相位调制技术,广泛应用于无线通信中。FPGA凭借其高度灵活性和并行处理能力,成为实现此类复杂算法的理想平台。系统RTL结构展示了各模块间的连接与协同工作。
68 16

热门文章

最新文章