第6章:按键与触摸传感器
本章介绍按键传感器、电容触摸传感器的工作原理与编程方法,重点讲解信号检测与防抖处理。
6.1 按键传感器原理
6.1.1 轻触开关结构
按键模块采用轻触开关(Tactile Switch):
┌─────────┐
│ 帽盖 │
├─────────┤
引脚1─┤ 弹片 ├─引脚3
│ │
引脚2─┤ ├─引脚4
└─────────┘
- 引脚 1 和 3 内部相连
- 引脚 2 和 4 内部相连
- 按下时 1-3 与 2-4 导通
6.1.2 电路设计
VCC
│
[R1 4.7K] 上拉电阻
│
├─────── S (信号输出到 GPIO)
│
[按键]
│
GND
工作逻辑:
- 按键松开时:信号端被上拉电阻拉高 → 高电平
- 按键按下时:信号端直接接地 → 低电平
6.1.3 编码方式解析
按键是最简单的数字编码设备:
| 状态 | 信号值 | 二进制 |
|---|---|---|
| 松开 | 1 | HIGH |
| 按下 | 0 | LOW |
6.2 按键检测代码
6.2.1 基础检测
'''
实验:按键状态检测
接线:按键 S 端连接 GP15
'''
from machine import Pin
import time
button = Pin(15, Pin.IN, Pin.PULL_UP)
while True:
if button.value() == 0:
print("按键按下!")
else:
print("按键松开")
time.sleep(0.1)
6.2.2 按键控制 LED
'''
实验:按键控制 LED 开关
'''
from machine import Pin
import time
button = Pin(15, Pin.IN, Pin.PULL_UP)
led = Pin(0, Pin.OUT)
led_state = False
while True:
if button.value() == 0: # 按键按下
time.sleep(0.05) # 防抖延时
if button.value() == 0: # 确认按下
led_state = not led_state
led.value(led_state)
print(f"LED {'开' if led_state else '关'}")
# 等待按键松开
while button.value() == 0:
time.sleep(0.01)
6.3 按键防抖
6.3.1 抖动现象
机械按键按下时,触点会产生机械振动,导致信号在短时间内多次跳变:
理想信号: ────┐ ┌────
└──────────┘
实际信号: ────┐ ┌─┐┌─┐ ┌─┐┌────
└─┘ └┘ └───┘ └┘
│ 抖动 │
└─────────┘
抖动持续时间通常为 5-20ms。
6.3.2 软件防抖
方法 1:延时消抖
def read_button(button, debounce_ms=50):
"""读取按键状态(带防抖)"""
if button.value() == 0:
time.sleep_ms(debounce_ms)
if button.value() == 0:
return True
return False
方法 2:状态机消抖
class DebouncedButton:
"""防抖按键类"""
def __init__(self, pin_num, debounce_ms=50):
self.pin = Pin(pin_num, Pin.IN, Pin.PULL_UP)
self.debounce_ms = debounce_ms
self.last_press = 0
self.last_state = 1
def is_pressed(self):
"""检测按键是否刚被按下(边沿检测)"""
current = self.pin.value()
now = time.ticks_ms()
# 状态变化且超过防抖时间
if current != self.last_state:
if time.ticks_diff(now, self.last_press) > self.debounce_ms:
self.last_press = now
self.last_state = current
return current == 0 # 按下时返回 True
return False
def is_down(self):
"""检测按键是否处于按下状态"""
return self.pin.value() == 0
# 使用示例
button = DebouncedButton(15)
while True:
if button.is_pressed():
print("按键按下!")
time.sleep(0.01)
6.3.3 中断+定时器防抖
from machine import Pin, Timer
button = Pin(15, Pin.IN, Pin.PULL_UP)
led = Pin(0, Pin.OUT)
debounce_timer = Timer()
pending_event = False
def debounce_callback(timer):
global pending_event
if button.value() == 0:
led.toggle()
print("确认按键事件")
pending_event = False
def button_irq(pin):
global pending_event
if not pending_event:
pending_event = True
debounce_timer.init(mode=Timer.ONE_SHOT, period=50, callback=debounce_callback)
button.irq(trigger=Pin.IRQ_FALLING, handler=button_irq)
6.4 电容触摸传感器
6.4.1 工作原理
电容触摸模块基于 TTP223-BA6 芯片,检测人体电容变化:
人体
│
感应片 ─┬─ TTP223 ─── S 输出
│ │
[Cs] GND
工作原理:
- 感应片与 GND 形成电容 Cs
- 人体触摸时,增加寄生电容
- TTP223 检测电容变化,输出信号
6.4.2 输出逻辑
与按键模块相反:
| 状态 | 信号值 |
|---|---|
| 未触摸 | 低电平 (0) |
| 触摸 | 高电平 (1) |
注意:上电后约 0.5 秒进行自校准,此期间勿触摸。
6.4.3 触摸检测代码
'''
实验:电容触摸检测
接线:触摸模块 S 端连接 GP3
'''
from machine import Pin
import time
touch = Pin(3, Pin.IN)
while True:
if touch.value() == 1:
print("触摸感应!")
else:
print("未触摸")
time.sleep(0.1)
6.4.4 触摸调光灯
'''
实验:触摸调光
短触:开/关
长触:调节亮度
'''
from machine import Pin, PWM
import time
touch = Pin(3, Pin.IN)
led = PWM(Pin(0))
led.freq(1000)
brightness = 0
is_on = False
BRIGHTNESS_STEP = 10
def adjust_brightness():
global brightness
if brightness >= 100:
brightness = 10
else:
brightness += BRIGHTNESS_STEP
led.duty_u16(int(brightness / 100 * 65535))
print(f"亮度: {brightness}%")
while True:
if touch.value() == 1: # 检测到触摸
press_start = time.ticks_ms()
# 等待触摸释放
while touch.value() == 1:
duration = time.ticks_diff(time.ticks_ms(), press_start)
if duration > 500: # 长按超过 500ms
adjust_brightness()
time.sleep(0.2)
duration = time.ticks_diff(time.ticks_ms(), press_start)
if duration < 500: # 短按
is_on = not is_on
if is_on:
led.duty_u16(int(brightness / 100 * 65535))
print("灯开")
else:
led.duty_u16(0)
print("灯关")
time.sleep(0.05)
6.5 多按键处理
6.5.1 多按键独立检测
'''
实验:三个按键控制三个 LED
'''
from machine import Pin
import time
# 按键列表
buttons = [
Pin(15, Pin.IN, Pin.PULL_UP),
Pin(16, Pin.IN, Pin.PULL_UP),
Pin(17, Pin.IN, Pin.PULL_UP),
]
# LED 列表
leds = [
Pin(0, Pin.OUT),
Pin(1, Pin.OUT),
Pin(2, Pin.OUT),
]
while True:
for i, button in enumerate(buttons):
if button.value() == 0:
leds[i].toggle()
while button.value() == 0:
time.sleep(0.01)
time.sleep(0.01)
6.5.2 组合按键
'''
实验:组合按键检测
'''
from machine import Pin
import time
btn1 = Pin(15, Pin.IN, Pin.PULL_UP)
btn2 = Pin(16, Pin.IN, Pin.PULL_UP)
def get_key_combo():
"""获取按键组合状态"""
return (btn1.value() << 1) | btn2.value()
NONE = 0b11
BTN1 = 0b01
BTN2 = 0b10
BOTH = 0b00
while True:
combo = get_key_combo()
if combo == BTN1:
print("按键1按下")
elif combo == BTN2:
print("按键2按下")
elif combo == BOTH:
print("双键同时按下!")
time.sleep(0.1)
6.6 AD 按键模块
6.6.1 原理解析
五路 AD 按键通过电阻分压,用单个 ADC 引脚识别 5 个按键:
VCC
│
[按键1] → 直接到 VCC → 最高电压
│
[R2]
│
[按键2] → VCC 通过 R2 分压
│
[R3]
│
[按键3] → 继续分压
│
[R4]
│
[按键4]
│
[R5]
│
[按键5] → 最低电压(接近 0)
│
[R1]
│
GND ← 信号输出点
6.6.2 电压计算
无按键时: ADC ≈ 0
按键1: ADC ≈ VCC (65535)
按键2: ADC ≈ VCC × R1/(R1+R2)
按键3: ADC ≈ VCC × R1/(R1+R2+R3)
按键4: ADC ≈ VCC × R1/(R1+R2+R3+R4)
按键5: ADC ≈ VCC × R1/(R1+R2+R3+R4+R5)
6.6.3 AD 按键检测代码
'''
实验:五路 AD 按键
接线:模块 S 端连接 GP26 (ADC0)
'''
from machine import ADC
import time
ad_key = ADC(26)
# ADC 阈值表
KEY_THRESHOLDS = {
'NONE': (0, 6000),
'SW5': (6000, 20000),
'SW4': (20000, 32000),
'SW3': (32000, 45000),
'SW2': (45000, 59000),
'SW1': (59000, 65536),
}
def get_key():
"""识别按下的按键"""
value = ad_key.read_u16()
for key, (low, high) in KEY_THRESHOLDS.items():
if low <= value < high:
return key, value
return 'NONE', value
while True:
key, value = get_key()
if key != 'NONE':
print(f"按键: {key}, ADC值: {value}")
time.sleep(0.1)
6.6.4 AD 按键菜单系统
'''
实验:AD 按键菜单控制
'''
from machine import ADC, Pin
import time
ad_key = ADC(26)
led = Pin(0, Pin.OUT)
menu_index = 0
menu_items = ['亮度低', '亮度中', '亮度高', '闪烁', '关闭']
def get_key():
value = ad_key.read_u16()
if value < 6000:
return None
elif value < 20000:
return 'DOWN'
elif value < 32000:
return 'UP'
elif value < 45000:
return 'LEFT'
elif value < 59000:
return 'RIGHT'
else:
return 'OK'
def execute_menu(index):
if index == 0:
led.value(1)
elif index == 1:
led.value(1)
elif index == 2:
led.value(1)
elif index == 3:
for _ in range(3):
led.toggle()
time.sleep(0.2)
else:
led.value(0)
while True:
key = get_key()
if key == 'UP':
menu_index = (menu_index - 1) % len(menu_items)
print(f"→ {menu_items[menu_index]}")
elif key == 'DOWN':
menu_index = (menu_index + 1) % len(menu_items)
print(f"→ {menu_items[menu_index]}")
elif key == 'OK':
print(f"执行: {menu_items[menu_index]}")
execute_menu(menu_index)
if key:
time.sleep(0.3) # 防止连续触发
else:
time.sleep(0.05)
6.7 本章小结
本章介绍了数字输入传感器的使用:
- 按键模块:上拉电阻设计,按下为低电平
- 触摸模块:基于 TTP223,触摸为高电平
- 防抖处理:软件延时或状态机消抖
- AD 按键:用电阻分压实现多按键识别
- 编码方式:数字按键是最简单的 1-bit 编码
下一章将学习红外与光电传感器。