image.png

一、前置知识

电容触摸按键主要由按键 IC 部分和电容部分构成。按键 IC 部分主要由元器件供应商提供,用于将电容的变化转换为电信号。手指接触到触摸按键时,按键和手指之间产生寄生电容,使按键的总容值增加。
电容式触摸按键 IC 在检测到按键的感应电容值改变,并超过一定的阈值后,将输出有效信号表示按键被按下。
image.png

二、原理图分析

image.png image.png
触摸 IC 型号为 AR101,其引脚功能如下:

引脚标号 功能描述
OP1 = 0 OUT 引脚输出信号高电平有效
OP1 = 1 OUT 引脚输出信号低电平有效
OP2 = 0 触摸 IC 工作在同步模式,即触摸时输出有效电平,松开后无有效电平输出。
OP2 = 1 触摸 IC 工作在保持模式,即检测到触摸操作后输出有效电平,松开后,输出电平保持不变。当再次检测到触摸操作时,输出电平变化并继续保持。

原理图中,触摸 IC 的引脚 OP1 和 OP2 均拉低,因此当手指按在触摸按键上时,TOUT 管脚输出高电平,松开后输出低电平。
需要注意,TOUT是被连在了P4排针座的TOUT端口上,需要用跳线帽将TOUT与连接在FPGA的TPAD端口短接。
image.png
image.png

三、代码流程分析

image.png

方法一:直接检测按键上升沿

需要判断TOUT产生的上升沿位置,在每个TOUT的上升沿,切换LED的状态。
按上述分析,我写出了以下简单的代码,it’s work。

  1. //---------------------- Copyright (c) ----------------------
  2. // Copyright(C) ZHJ0125 2022
  3. // All rights reserved
  4. //-----------------------------------------------------------
  5. // File Name : touch_led.v
  6. // Created Date : 2022-04-15 17:54
  7. // Modified Date : 2022-04-15 17:54
  8. // Created By : ZHJ0125
  9. // Last Version : V0.1
  10. // Descriptions : 使用触摸按键控制LED。
  11. // 开发板上电后LED为熄灭状态,手指触摸后LED点亮;
  12. // 再次触摸,LED熄灭,以此循环。
  13. //-----------------------------------------------------------
  14. module touch_led(
  15. input clk,
  16. input rst_n,
  17. input touch_key,
  18. output reg [3:0] led
  19. );
  20. always @(posedge touch_key or negedge rst_n) begin
  21. if(!rst_n)
  22. led <= 4'd0; // 复位后LED全灭
  23. else
  24. led <= ~led;
  25. end
  26. endmodule

touch_led_1.mp4 (8.34MB)

方法二:保留两个KEY状态来判断上升沿

在正点原子手册中提供了以下思路:使用系统时钟触发方式,保留两个时钟周期内的KEY状态,根据两状态是否为低→高,判断是否为触摸按键的上升沿。

  1. //---------------------- Copyright (c) ----------------------
  2. // Copyright(C) ZHJ0125 2022
  3. // All rights reserved
  4. //-----------------------------------------------------------
  5. // File Name : touch_led.v
  6. // Created Date : 2022-04-15 17:54
  7. // Modified Date : 2022-04-15 18:25
  8. // Created By : ZHJ0125
  9. // Last Version : V0.1
  10. // Descriptions : 使用触摸按键控制LED。
  11. // 开发板上电后LED为熄灭状态,手指触摸后LED点亮;
  12. // 再次触摸,LED熄灭,以此循环。
  13. //-----------------------------------------------------------
  14. //module touch_led(
  15. // input clk,
  16. // input rst_n,
  17. // input touch_key,
  18. // output reg [3:0] led
  19. //);
  20. //
  21. //always @(posedge touch_key or negedge rst_n) begin
  22. // if(!rst_n)
  23. // led <= 4'd0; // 复位后LED全灭
  24. // else
  25. // led <= ~led;
  26. //end
  27. //
  28. //endmodule
  29. module touch_led(
  30. input clk,
  31. input rst_n,
  32. input touch_key,
  33. output reg [3:0] led
  34. );
  35. reg touch_key_d0; // 本周期即当前的按键状态
  36. reg touch_key_d1; // 上一个周期的按键状态
  37. wire key_en; // 上升沿触发标志
  38. assign key_en = (~touch_key_d1) && touch_key_d0;
  39. // 处理记录两个周期的按键状态
  40. always @(posedge clk or negedge rst_n) begin
  41. if(!rst_n) begin
  42. touch_key_d0 <= 1'b0;
  43. touch_key_d1 <= 1'b0;
  44. end
  45. else begin
  46. touch_key_d0 <= touch_key;
  47. touch_key_d1 <= touch_key_d0;
  48. end
  49. end
  50. // 处理设置LED状态
  51. always @(posedge clk or negedge rst_n) begin
  52. if(!rst_n) begin
  53. led <= 4'd0; // 复位后LED全灭
  54. end
  55. else begin
  56. if(key_en) // 出现上升沿
  57. led <= ~led;
  58. else
  59. led <= led;
  60. end
  61. end
  62. endmodule

实验效果与我编写的代码效果一致。
正点原子的方法巧妙之处在于记录了两次周期中按键的状态,根据两次按键状态来判断上升沿;而我的方法是直接使用Verilog语法判断按键上升沿。