第15章:压力与摇杆传感器
本章介绍薄膜压力传感器、摇杆模块的工作原理与应用案例。
15.1 薄膜压力传感器
15.1.1 工作原理
薄膜压力传感器是一种可变电阻式传感器:
无压力: 高阻抗 (>1MΩ)
有压力: 阻值降低 (几KΩ~几十KΩ)
阻值与压力呈反比关系。
15.1.2 电路设计
VCC
│
[R1 10K] 分压电阻
│
├───────── ADC
│
[压力传感器]
│
GND
15.1.3 检测代码
'''
实验:薄膜压力传感器
接线:S 端连接 GP26
'''
from machine import ADC
import time
pressure = ADC(26)
def read_pressure():
"""读取压力值(0-100%)"""
raw = pressure.read_u16()
# 反转:压力越大,电阻越小,电压越低
inverted = 65535 - raw
percent = inverted / 65535 * 100
return raw, percent
while True:
raw, percent = read_pressure()
bar = '█' * int(percent / 5)
print(f"ADC: {raw:5d} 压力: {percent:5.1f}% |{bar}")
time.sleep(0.1)
15.1.4 力度检测等级
'''
实验:压力等级判断
'''
def pressure_level(raw):
"""判断压力等级"""
if raw > 60000:
return "无压力", 0
elif raw > 50000:
return "轻触", 1
elif raw > 35000:
return "按压", 2
elif raw > 20000:
return "用力", 3
else:
return "重压", 4
while True:
raw = pressure.read_u16()
level, grade = pressure_level(raw)
print(f"ADC: {raw} 等级: {level} ({grade})")
time.sleep(0.2)
15.2 摇杆模块
15.2.1 模块介绍
PS2 摇杆模块包含:
- X 轴电位器
- Y 轴电位器
- Z 轴按键
15.2.2 数据编码
| 状态 | X 轴 ADC | Y 轴 ADC |
|---|---|---|
| 中心 | ~32000 | ~32000 |
| 左 | ~0 | ~32000 |
| 右 | ~65535 | ~32000 |
| 上 | ~32000 | ~0 |
| 下 | ~32000 | ~65535 |
按键:按下=高电平,松开=低电平
15.2.3 基础读取
'''
实验:摇杆模块读取
接线:X→GP26, Y→GP27, B→GP22
'''
from machine import ADC, Pin
import time
joystick_x = ADC(26)
joystick_y = ADC(27)
joystick_btn = Pin(22, Pin.IN)
while True:
x = joystick_x.read_u16()
y = joystick_y.read_u16()
btn = joystick_btn.value()
print(f"X: {x:5d} Y: {y:5d} 按键: {btn}")
time.sleep(0.1)
15.2.4 方向判断
'''
实验:摇杆方向判断
'''
from machine import ADC, Pin
import time
x_adc = ADC(26)
y_adc = ADC(27)
btn = Pin(22, Pin.IN)
# 中心值和死区
CENTER = 32768
DEADZONE = 10000
def get_direction():
"""获取摇杆方向"""
x = x_adc.read_u16()
y = y_adc.read_u16()
dx = x - CENTER
dy = y - CENTER
# 死区判断
if abs(dx) < DEADZONE and abs(dy) < DEADZONE:
return "CENTER", 0, 0
# 判断主方向
if abs(dx) > abs(dy):
if dx > 0:
return "RIGHT", dx, dy
else:
return "LEFT", dx, dy
else:
if dy > 0:
return "DOWN", dx, dy
else:
return "UP", dx, dy
while True:
direction, dx, dy = get_direction()
pressed = "按下" if btn.value() == 1 else ""
print(f"方向: {direction:6s} 偏移: ({dx:+6d}, {dy:+6d}) {pressed}")
time.sleep(0.1)
15.2.5 模拟量转角度
'''
实验:摇杆角度计算
'''
import math
def joystick_to_angle():
"""计算摇杆角度和力度"""
x = x_adc.read_u16() - CENTER
y = y_adc.read_u16() - CENTER
# 计算角度(弧度转角度)
angle = math.atan2(y, x) * 180 / math.pi
# 计算力度(0-100%)
magnitude = min(100, math.sqrt(x*x + y*y) / CENTER * 100)
return angle, magnitude
while True:
angle, magnitude = joystick_to_angle()
if magnitude > 10: # 死区
print(f"角度: {angle:+6.1f}° 力度: {magnitude:5.1f}%")
else:
print("摇杆居中")
time.sleep(0.1)
15.3 摇杆控制应用
15.3.1 控制 LED 亮度
'''
实验:摇杆控制 LED 亮度和闪烁
X 轴: 亮度
Y 轴: 闪烁速度
'''
from machine import ADC, Pin, PWM
import time
x_adc = ADC(26)
y_adc = ADC(27)
led = PWM(Pin(0))
led.freq(1000)
while True:
x = x_adc.read_u16()
y = y_adc.read_u16()
# X 轴控制亮度
led.duty_u16(x)
# Y 轴控制闪烁(值越大越快)
blink_delay = max(0.05, (65535 - y) / 65535)
time.sleep(blink_delay)
15.3.2 摇杆控制舵机
'''
实验:摇杆控制舵机
X 轴: 水平舵机
Y 轴: 垂直舵机
'''
from machine import ADC, Pin, PWM
import time
x_adc = ADC(26)
y_adc = ADC(27)
servo_h = PWM(Pin(16))
servo_v = PWM(Pin(17))
servo_h.freq(50)
servo_v.freq(50)
def set_servo_angle(servo, angle):
"""设置舵机角度 (0-180)"""
# 脉宽: 0.5ms (0°) ~ 2.5ms (180°)
# 周期: 20ms (50Hz)
duty = int((angle / 180 * 2 + 0.5) / 20 * 65535)
servo.duty_u16(duty)
def joystick_to_angle(adc_value):
"""ADC 值转角度"""
return adc_value / 65535 * 180
while True:
x = x_adc.read_u16()
y = y_adc.read_u16()
angle_h = joystick_to_angle(x)
angle_v = joystick_to_angle(y)
set_servo_angle(servo_h, angle_h)
set_servo_angle(servo_v, angle_v)
print(f"水平: {angle_h:.0f}° 垂直: {angle_v:.0f}°")
time.sleep(0.05)
15.3.3 游戏控制器
'''
实验:摇杆游戏控制器类
'''
from machine import ADC, Pin
import time
class Joystick:
"""摇杆控制器类"""
def __init__(self, x_pin, y_pin, btn_pin, deadzone=0.15):
self.x_adc = ADC(x_pin)
self.y_adc = ADC(y_pin)
self.btn = Pin(btn_pin, Pin.IN)
self.deadzone = deadzone
# 校准中心值
self.center_x = 32768
self.center_y = 32768
def calibrate(self):
"""校准中心值"""
samples = 50
x_sum = sum(self.x_adc.read_u16() for _ in range(samples))
y_sum = sum(self.y_adc.read_u16() for _ in range(samples))
self.center_x = x_sum // samples
self.center_y = y_sum // samples
print(f"校准完成: 中心=({self.center_x}, {self.center_y})")
def read_normalized(self):
"""读取归一化值 (-1.0 ~ 1.0)"""
x = (self.x_adc.read_u16() - self.center_x) / 32768
y = (self.y_adc.read_u16() - self.center_y) / 32768
# 应用死区
if abs(x) < self.deadzone:
x = 0
if abs(y) < self.deadzone:
y = 0
return x, y, self.btn.value()
def get_dpad(self):
"""获取方向键状态"""
x, y, btn = self.read_normalized()
left = x < -0.5
right = x > 0.5
up = y < -0.5
down = y > 0.5
return {
'left': left,
'right': right,
'up': up,
'down': down,
'btn': btn == 1
}
# 使用
joy = Joystick(26, 27, 22)
joy.calibrate()
while True:
dpad = joy.get_dpad()
if any([dpad['left'], dpad['right'], dpad['up'], dpad['down']]):
directions = []
if dpad['up']: directions.append('↑')
if dpad['down']: directions.append('↓')
if dpad['left']: directions.append('←')
if dpad['right']: directions.append('→')
print(f"方向: {''.join(directions)}")
if dpad['btn']:
print("按键!")
time.sleep(0.05)
15.4 旋转编码器
15.4.1 工作原理
旋转编码器通过正交编码检测旋转方向和角度:
顺时针:
A: ──┐ ┌──┐ ┌──
└──┘ └──┘
B: ─┐ ┌──┐ ┌──┐
└──┘ └──┘ └─
逆时针:
B: ──┐ ┌──┐ ┌──
└──┘ └──┘
A: ─┐ ┌──┐ ┌──┐
└──┘ └──┘ └─
15.4.2 编码器解码
'''
实验:旋转编码器
接线:CLK→GP16, DT→GP17, SW→GP18
'''
from machine import Pin
import time
clk = Pin(16, Pin.IN, Pin.PULL_UP)
dt = Pin(17, Pin.IN, Pin.PULL_UP)
sw = Pin(18, Pin.IN, Pin.PULL_UP)
position = 0
last_clk = clk.value()
def encoder_callback(pin):
global position, last_clk
current_clk = clk.value()
if current_clk != last_clk:
if dt.value() != current_clk:
position += 1
else:
position -= 1
print(f"位置: {position}")
last_clk = current_clk
clk.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=encoder_callback)
while True:
if sw.value() == 0:
position = 0
print("位置重置!")
time.sleep(0.3)
time.sleep(0.01)
15.5 本章小结
本章介绍了压力与摇杆传感器:
- 薄膜压力传感器:
- 阻值随压力变化
- 适用于力度检测
- 摇杆模块:
- 双轴电位器 + 按键
- 输出两路模拟量 + 一路数字量
- 数据编码:
- ADC 范围 0-65535
- 中心值约 32768
- 应用场景:
- 游戏控制
- 云台控制
- 交互界面
下一章将学习 PWM 脉宽调制技术。