一、前置知识
电容触摸按键主要由按键 IC 部分和电容部分构成。按键 IC 部分主要由元器件供应商提供,用于将电容的变化转换为电信号。手指接触到触摸按键时,按键和手指之间产生寄生电容,使按键的总容值增加。
电容式触摸按键 IC 在检测到按键的感应电容值改变,并超过一定的阈值后,将输出有效信号表示按键被按下。
二、原理图分析
触摸 IC 型号为 AR101,其引脚功能如下:
引脚标号 | 功能描述 |
---|---|
OP1 = 0 | OUT 引脚输出信号高电平有效 |
OP1 = 1 | OUT 引脚输出信号低电平有效 |
OP2 = 0 | 触摸 IC 工作在同步模式,即触摸时输出有效电平,松开后无有效电平输出。 |
OP2 = 1 | 触摸 IC 工作在保持模式,即检测到触摸操作后输出有效电平,松开后,输出电平保持不变。当再次检测到触摸操作时,输出电平变化并继续保持。 |
原理图中,触摸 IC 的引脚 OP1 和 OP2 均拉低,因此当手指按在触摸按键上时,TOUT 管脚输出高电平,松开后输出低电平。
需要注意,TOUT是被连在了P4排针座的TOUT端口上,需要用跳线帽将TOUT与连接在FPGA的TPAD端口短接。
三、代码流程分析
方法一:直接检测按键上升沿
需要判断TOUT产生的上升沿位置,在每个TOUT的上升沿,切换LED的状态。
按上述分析,我写出了以下简单的代码,it’s work。
//---------------------- Copyright (c) ----------------------
// Copyright(C) ZHJ0125 2022
// All rights reserved
//-----------------------------------------------------------
// File Name : touch_led.v
// Created Date : 2022-04-15 17:54
// Modified Date : 2022-04-15 17:54
// Created By : ZHJ0125
// Last Version : V0.1
// Descriptions : 使用触摸按键控制LED。
// 开发板上电后LED为熄灭状态,手指触摸后LED点亮;
// 再次触摸,LED熄灭,以此循环。
//-----------------------------------------------------------
module touch_led(
input clk,
input rst_n,
input touch_key,
output reg [3:0] led
);
always @(posedge touch_key or negedge rst_n) begin
if(!rst_n)
led <= 4'd0; // 复位后LED全灭
else
led <= ~led;
end
endmodule
方法二:保留两个KEY状态来判断上升沿
在正点原子手册中提供了以下思路:使用系统时钟触发方式,保留两个时钟周期内的KEY状态,根据两状态是否为低→高,判断是否为触摸按键的上升沿。
//---------------------- Copyright (c) ----------------------
// Copyright(C) ZHJ0125 2022
// All rights reserved
//-----------------------------------------------------------
// File Name : touch_led.v
// Created Date : 2022-04-15 17:54
// Modified Date : 2022-04-15 18:25
// Created By : ZHJ0125
// Last Version : V0.1
// Descriptions : 使用触摸按键控制LED。
// 开发板上电后LED为熄灭状态,手指触摸后LED点亮;
// 再次触摸,LED熄灭,以此循环。
//-----------------------------------------------------------
//module touch_led(
// input clk,
// input rst_n,
// input touch_key,
// output reg [3:0] led
//);
//
//always @(posedge touch_key or negedge rst_n) begin
// if(!rst_n)
// led <= 4'd0; // 复位后LED全灭
// else
// led <= ~led;
//end
//
//endmodule
module touch_led(
input clk,
input rst_n,
input touch_key,
output reg [3:0] led
);
reg touch_key_d0; // 本周期即当前的按键状态
reg touch_key_d1; // 上一个周期的按键状态
wire key_en; // 上升沿触发标志
assign key_en = (~touch_key_d1) && touch_key_d0;
// 处理记录两个周期的按键状态
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
touch_key_d0 <= 1'b0;
touch_key_d1 <= 1'b0;
end
else begin
touch_key_d0 <= touch_key;
touch_key_d1 <= touch_key_d0;
end
end
// 处理设置LED状态
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
led <= 4'd0; // 复位后LED全灭
end
else begin
if(key_en) // 出现上升沿
led <= ~led;
else
led <= led;
end
end
endmodule
实验效果与我编写的代码效果一致。
正点原子的方法巧妙之处在于记录了两次周期中按键的状态,根据两次按键状态来判断上升沿;而我的方法是直接使用Verilog语法判断按键上升沿。