💡 划重点

  • 主控采用 RP2040,搭配 SPI OLED、震动电机与实体按键,在办公桌上提供无侵入的番茄钟与久坐提醒。
  • 方案聚焦“低成本、高可靠、易复刻”,全部物料含开发板在 55 元以内。
  • 双按键交互配合 OLED 图形化界面,避免频繁看手机,保持心流状态。
  • 通过震动电机直接提醒站立,比声音提醒更友好,避免干扰同事。
  • 代码骨架基于 MicroPython,可快速修改工歇时长与震动模式。

需求洞察

目标用户

长期在电脑前工作的程序员、设计师、文字工作者,以及注重精力和脊椎健康的远程办公者。

真实痛点

  1. 番茄钟依赖手机 App,但手机本身就是干扰源,通知一来容易分心。
  2. 多数桌面提醒器只有屏幕闪烁或蜂鸣声,蜂鸣在开放工位会打扰同事,只闪屏又容易被忽略。
  3. 久坐对腰椎、颈椎的损害已被大量医学研究证实,但工作投入时很难自觉起身活动。

为什么值得做

办公桌场景天然适合放置一个小型硬件终端。物理按键提供确定感,振动反馈不依赖视觉或听觉,能在不打断同事的前提下完成提醒。将番茄钟与站姿提醒合并,用极低的成本形成“专注+健康”双闭环,既有个人效率价值,也有健康管理价值,适合长期使用。

方案设计

本项目以 RP2040 为中心,从四层结构出发构建:

感知层

控制层

执行层

日志/联网层(基础+预留扩展)

物料清单

物料名称 数量 用途 单价(元) 小计(元)
WeAct RP2040 核心板 1 主控 19.9 19.9
0.96寸 OLED 模块 (SPI, SSD1306) 1 显示界面 13.5 13.5
微型震动电机模块 1 站立提醒 3.8 3.8
6x6 轻触按键 2 交互控制 0.3 0.6
10KΩ 电阻(按键上拉备用) 2 稳定电平 0.1 0.2
面包板 + 杜邦线 1套 电路搭建 8.0 8.0
迷你 USB 数据线 1 供电与编程 3.0 3.0
合计 49.0

合计 49 元,预留 6 元缓冲,完全满足 55 元内目标。若已有面包板和线材,实际成本可进一步压低至 41 元。

接线与结构

使用给定 GPIO 并微调:OLED 采用 SPI 接口,CS 接 GP13,DC 接 GP14,SCLK 接 GP10,MOSI 接 GP11;震动电机接 GP15;按键使用内部弱上拉,接 GP6(启动/暂停)和 GP7(重置)。

微调理由:原给定 OLED 接线中未指定 SCLK 和 MOSI,这里选用 RP2040 的硬件 SPI0,稳定且刷新快。两个按键直接占用 GP6、GP7,不冲突任何已分配 SPI 引脚,软件中启用内部上拉可省略外部上拉电阻(物料清单仍保留以防抖动,实际焊接可取舍)。

结构:所有模块固定在面包板上,OLED 置于顶部倾斜面朝使用者,按键在右侧便于惯用手操作,震动电机粘贴于面包板背面,通过桌面传递振动。使用 3D 打印外壳可固定形态,但并非必需。

核心代码

以下为 MicroPython 骨架,实现番茄钟启动/暂停、倒计时显示与站立震动提醒。


import ssd1306
import time

# OLED 初始化
spi = SPI(0, baudrate=4000000, polarity=0, phase=0, sck=Pin(10), mosi=Pin(11))
cs = Pin(13, Pin.OUT)
dc = Pin(14, Pin.OUT)
rst = Pin(12, Pin.OUT)  # 若 OLED 有 RST
oled = ssd1306.SSD1306_SPI(128, 64, spi, dc, rst, cs)

# 电机与按键
motor = Pin(15, Pin.OUT)
btn_start = Pin(6, Pin.IN, Pin.PULL_UP)
btn_reset = Pin(7, Pin.IN, Pin.PULL_UP)

WORK_MIN = 25
SHORT_BREAK = 5
LONG_BREAK = 15
SIT_LIMIT = 45  # 久坐提醒阈值(分钟)

# 状态变量
running = False
paused = False
current_timer = WORK_MIN * 60
phase = 'work'  # work, short_break, long_break
sit_counter = 0
pomodoro_count = 0

def vibrate(pattern):
    for _ in range(pattern):
        motor.on()
        time.sleep_ms(150)
        motor.off()
        time.sleep_ms(100)

    oled.fill(0)
    mins, secs = divmod(remaining_sec, 60)
    oled.text(f"{phase} {mins:02d}:{secs:02d}", 0, 0)
    sit_bar = int((sit_counter / (SIT_LIMIT*60)) * 60)
    oled.text(f"Pomo:{pomodoro_count}", 0, 30)
    oled.show()

def tick(timer):
    if not running or paused:
        return
    sit_counter += 1
    current_timer -= 1
    if current_timer <= 0:
        vibrate(2)  # 结束提醒
        running = False
        if phase == 'work':
            pomodoro_count += 1
            if pomodoro_count % 4 == 0:
                phase = 'long_break'
                current_timer = LONG_BREAK * 60
            else:
                phase = 'short_break'
                current_timer = SHORT_BREAK * 60
        else:
            phase = 'work'
            current_timer = WORK_MIN * 60
    # 久坐提醒(仅工作阶段且未暂停)
    if phase == 'work' and sit_counter >= SIT_LIMIT * 60:
        vibrate(2)
        sit_counter = 0
    update_display(current_timer)

timer = Timer()
timer.init(period=1000, mode=Timer.PERIODIC, callback=tick)

def check_buttons():
    if not btn_start.value():
        time.sleep_ms(50)
        if not btn_start.value():
            if not running:
                running = True
                paused = False
                current_timer = WORK_MIN * 60 if phase == 'work' else current_timer
                sit_counter = 0
                vibrate(1)
            else:
                paused = not paused
            while not btn_start.value():
                pass
    if not btn_reset.value():
        time.sleep_ms(50)
        if not btn_reset.value():
            global phase, pomodoro_count
            running = False
            paused = False
            phase = 'work'
            current_timer = WORK_MIN * 60
            pomodoro_count = 0
            sit_counter = 0
            update_display(current_timer)
            while not btn_reset.value():
                pass

# 主循环
while True:
    check_buttons()
    time.sleep_ms(100)

代码需配合 ssd1306.py 库使用,可通过 Thonny 或 rshell 上传至 RP2040。定时器每秒更新一次,按键检测置于主循环,实现基本的番茄钟逻辑与久坐站立震动提醒。

调试步骤

  1. 硬件上电检查:USB 连接电脑,RP2040 板载 LED 闪烁,OLED 亮起并显示初始界面。
  2. 固件烧录:按住 BOOTSEL 插入 USB,将 MicroPython 固件拖入 RPI-RP2 磁盘。
  3. 上传依赖:将 ssd1306.py 及主程序上传至设备。
  4. 功能验证:短按 GP6,OLED 开始 25 分钟倒计时,电机短震一次;计时归零时震动两次并自动进入休息阶段。长按或点按 GP7 重置所有状态。
  5. 久坐联调:为测试可将 SIT_LIMIT 临时改为 1 分钟,验证站立震动提醒。
  6. 串口日志观察:可在主循环中添加 print() 输出当前阶段与时间戳,通过串口监视器查看数据。
  7. 整体集成:确认无误后,将模块用热熔胶或壳体固定,即可放置于工位长期使用。

设计图

番茄钟工位站姿提醒结构flow
1
感知输入(双按键、内部RTC定时)
2
控制处理(RP2040 MicroPython 番茄钟状态机、久坐逻辑)
3
执行反馈(OLED图形倒计时、震动电机提醒站立)
4
数据上报(USB串口日志、预留蓝牙/WiFi上行)