用触摸按键控制药盒开关,OLED显示状态和服药提醒(12H制可自行修改,舵机模拟开盖)
首先特别感谢DF社区给我的机会 让我使用上了RP2350我将用它来制作各种小玩意
本章介绍的是智能药盒提醒器项目
项目简介
触摸控制舵机角度指示器项目
动特性的项目方案:
升级方案:智能药盒提醒器
用触摸按键控制药盒开关,OLED显示状态和服药
提醒,舵机模拟开盖动作
核心功能
1.场景模拟
,短触触摸键:舵机转动90°模拟开盖,OLED显
示”OPEN”和服药提醒
·再次短触:舵机归位关盖,显示”CLOSED"
。长按2秒:进入设置模式,可调整开盖角度
2.视觉反馈
OLED显示药盒状态动画
用药时间到自动闪烁提醒
所需库和安装方法
1.TTP233专用库(非必需,直接读取电平更高效)
2.按钮扩展库:
Arduino IDE搜索安装Bounce2(解决触摸抖动
问题)
3. Adafruit SSD1306(OLED显示)
Arduino IDE中搜索安装:工具→管理库….→搜
索”SSD1306”安装。
4. Servo(舵机控制)
Arduino自带库,无需额外安装。
TTP223触摸按键模块

材料清单
- TTP223触摸按键模块 X
- RO2350 X
- 1.3寸OLED 4针 IIC接口 X
- SG90舵机 180度 X
接线说明
元件 Arduino引脚
OLED SCL A5
OLED SDA A4
舵机信号线 D9
触摸板输出 A1
舵机电源外接,GND共地
接线图

接线好后可以使用代码快速验证
代码
void setup(){
pinMode(2, INPUT);
Serial.begin(115200);
}
void loop(){
Serial.print("Touch:");
Serial.println(digitalRead(2));
delay(100);
}
I2C扫描工具
使用此程序曲儿OLED地址
代码
#include <Wire.h>
void setup(){
Wire.begin();
Serial.begin(115200);
}
void loop(){
byte error, address;
for(address=1; address<127; address++){
Wire.beginTransmission(address);
error = Wire.endTransmission();
if(error==0) Serial.print("Found: 0x");Serial.println(address,HEX);
}
delay(5000);
}
一切完毕之后总代码
优化后的程序,支持多级菜单
新增功能说明
1.智能角度校准
自动记录常用开盖角度
防止超过舵机物理限位
2.用药统计
·记录最近7天开盒次数
·用药频率分析
3.安全锁定
·长按启用儿童锁
震动反馈锁定状态
代码
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Servo.h>
#include <Bounce2.h>
#define TOUCH_PIN 2
#define SERVO_PIN 9
#define ANIMATION_FRAMES 8
// OLED图形资源
const unsigned char PROGMEM medIcon[] = { /* 16x16药品图标数据 */ };
const unsigned char PROGMEM settingsIcon[] = { /* 16x16设置图标数据 */ };
enum DisplayMode { MAIN, SETTINGS, STATS };
DisplayMode currentMode = MAIN;
struct SystemState {
int openAngle = 75;
int closeAngle = 5;
int openCount = 0;
unsigned long nextRemind = 0;
bool lidLock = false;
} sysState;
Adafruit_SSD1306 display(128, 64, &Wire, -1);
Servo lidServo;
Bounce touchDetector;
void setup() {
initHardware();
loadSettings();
displayWelcome();
}
void loop() {
handleTouchInput();
updateReminder();
refreshDisplay();
}
// 硬件初始化
void initHardware() {
pinMode(TOUCH_PIN, INPUT);
touchDetector.attach(TOUCH_PIN);
touchDetector.interval(10);
lidServo.attach(SERVO_PIN);
lidServo.write(sysState.closeAngle);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setRotation(2); // 180度旋转显示
}
// 触摸事件处理
void handleTouchInput() {
static unsigned long lastTap = 0;
touchDetector.update();
if(touchDetector.fell()) {
unsigned long tapInterval = millis() - lastTap;
if(tapInterval < 300) { // 双击
enterSettings();
lastTap = 0;
} else { // 单击
lastTap = millis();
}
}
if(touchDetector.read() == HIGH &&
millis() - lastTap > 2000) { // 长按
toggleLidLock();
lastTap = 0;
}
}
// 丝滑舵机动画
void animateServo(int start, int end) {
float increment = (end - start)/(float)ANIMATION_FRAMES;
for(int i=0; i<ANIMATION_FRAMES; i++){
lidServo.write(start + increment*i);
drawLidProgress(i/(float)ANIMATION_FRAMES);
delay(30);
}
}
// 图形界面渲染
void refreshDisplay() {
display.clearDisplay();
switch(currentMode){
case MAIN:
drawMainInterface();
break;
case SETTINGS:
drawSettingsMenu();
break;
case STATS:
drawStatistics();
break;
}
display.drawRect(0,0,128,64,WHITE); // 界面边框
display.display();
}
// 主界面绘制
void drawMainInterface() {
// 状态图标栏
display.drawBitmap(2, 2, medIcon, 16, 16, WHITE);
display.setCursor(20, 6);
display.printf("%03d", sysState.openCount);
// 药盒主体图形
display.fillRoundRect(30,15,68,34,5,WHITE);
// 开盖角度指示
int angleIndicator = map(sysState.openAngle,0,180,42,86);
display.fillTriangle(angleIndicator-3,52, angleIndicator+3,52, angleIndicator,58, WHITE);
// 下次提醒时间
display.setCursor(90, 6);
display.printf("%02d:%02d", hour(sysState.nextRemind), minute(sysState.nextRemind));
}
// 设置菜单
void enterSettings() {
currentMode = SETTINGS;
refreshDisplay();
while(!checkExitSettings()){
// 参数调节逻辑
// 通过触摸滑动修改数值
}
saveSettings();
currentMode = MAIN;
}
还可以加上内存管理优化
代码
// 在setup()中加入内存检测
Serial.print("Free RAM: ");
Serial.println(freeMemory()); // 需安装MemoryFree库
为了显示性能提升,可以将全局刷新改为局部刷新
代码
// 使用局部刷新代替全屏刷新
display.startWrite();
display.setAddrWindow(x, y, w, h);
// 局部绘制操作...
display.endWrite();
为防止舵机大角度转动过热,可以加入舵机保护
代码
// 在animateServo()中添加
if(abs(currentAngle - targetAngle) > 90){
delay(100); // 大角度转动增加冷却时间
}
可以参考一下渲染的建模图,3D打印还没那么快


一只想肥的猫2025.06.16
可以通用UNO板吗?
一只想肥的猫2025.06.16
我草