基于ATTiny85的智能刷牙计时器:从硬件选型到低功耗设计的完整实践
1. 项目概述:一个被低估的日常效率工具
每天早上和晚上,我们都会拿起牙刷,开始一天中看似最微不足道却又必不可少的仪式。但有多少人能自信地说,自己每次刷牙都刷够了牙医推荐的两分钟?我猜,大多数人都是凭感觉,刷个几十秒就草草了事。我自己以前也是这样,直到一次洗牙时,牙医指着牙菌斑显示剂染色的区域对我说:“这里、这里,还有这里,都是你平时没刷到位的地方,时间肯定不够。”那一刻我才意识到,一个简单的“两分钟”原则,执行起来竟如此困难。
于是,我萌生了一个想法:为什么不做一个专属于刷牙的计时器?不是手机里那些功能繁杂、广告横行的App,也不是厨房里滴答作响的机械计时器,而是一个极简、专注、甚至能带来一点仪式感的物理设备。这就是#TBT (Tooth Brush Timer)项目的由来。它本质上是一个软硬件结合的小型计时器,核心目标只有一个:确保你每次刷牙都刷满两分钟,并通过简单的交互和反馈,帮助你养成更科学的刷牙习惯。
这个项目适合所有关注个人健康、有轻微“技术控”倾向、并乐于动手改善生活细节的朋友。它不要求你有深厚的电子工程背景,但需要你对手工制作、基础电路和编程有基本的兴趣和耐心。通过完成它,你不仅能收获一个实用的健康小工具,更能深入理解如何将一个日常痛点,转化为一个可触摸、可交互的解决方案的全过程。
2. 项目整体设计与思路拆解
2.1 核心需求与功能定义
在动手之前,我们必须明确 #TBT 要解决的核心问题是什么,以及它应该具备哪些功能。这决定了我们后续的硬件选型和软件逻辑。
首先,核心痛点是“刷牙时间不足且无法量化”。因此,最核心的功能就是精准的两分钟倒计时。但这还不够,一个好的用户体验需要考虑整个使用流程:
- 启动便捷:开始刷牙时,如何一键启动计时?最好能模拟“挤牙膏”或“拿起牙刷”这个动作。
- 过程反馈:刷牙的两分钟里,用户需要知道进度。是无声地等待,还是需要有阶段性的提示?比如每30秒提醒换一个区域刷。
- 结束提醒:时间到,必须以明确无误的方式告知用户。是蜂鸣器响,还是灯光变化?
- 省电与待机:这是一个每天只用两次的设备,绝大部分时间处于闲置状态,必须极低功耗。
基于以上,我定义了 #TBT 的MVP(最小可行产品)功能清单:
- 输入:一个物理按钮,用于启动计时。
- 输出:
- 视觉反馈:一个多色LED(如RGB LED),用于显示状态(如待机、计时中、结束)。
- 听觉反馈:一个蜂鸣器或微型扬声器,用于播放阶段提示音和结束提示音。
- 核心逻辑:微控制器执行两分钟倒计时,并在第30秒、60秒、90秒、120秒(结束)时触发相应的灯光和声音提示,将口腔分为四个象限进行分区计时。
- 供电:使用纽扣电池或小型锂电池,确保数周甚至数月的待机时间。
2.2 硬件方案选型与考量
硬件是项目的骨架。我的选型原则是:在满足功能的前提下,尽可能选择常见、易得、易焊接的元件,并优先考虑低功耗。
1. 微控制器(大脑)这是最关键的决策。常见的选择有 Arduino Uno、ESP8266/ESP32、ATTiny85 等。
- Arduino Uno:功能强大,但体积大、功耗高,不适合做小型便携设备。否决。
- ESP系列:自带Wi-Fi/蓝牙,性能强,但功耗相对较高,且对于纯计时任务来说杀鸡用牛刀。否决。
- ATTiny85:AVR架构的8位微控制器,仅有8个引脚,体积小巧,功耗极低(睡眠模式下微安级),且可以通过Arduino IDE进行编程,生态友好。它是本项目的最佳选择。其有限的IO口(5个可用)刚好满足我们的需求:1个按钮输入,1个LED输出,1个蜂鸣器输出,还剩2个备用。
2. 电源管理为了便携和长待机,我选择了CR2032 纽扣电池(3V)。其优点是电压合适、体积小、易更换。但需要注意,ATTiny85的工作电压范围是1.8-5.5V,3V供电完全没问题,但直接驱动LED和蜂鸣器可能会因为电压不足而亮度/响度不够。因此,我们需要为LED和蜂鸣器设计独立的驱动电路,或者选择低压驱动的元件。
3. 反馈元件
- LED:选用一个共阳极RGB LED。为什么是RGB?因为我们可以用不同颜色表示不同状态:红色常亮表示电量低,蓝色呼吸表示待机,绿色闪烁表示计时开始,然后依次切换颜色(如蓝->绿->黄->红)来指示四个30秒区间,最后快速闪烁表示结束。一个元件实现多种状态,节省IO口。
- 蜂鸣器:选用无源蜂鸣器。有源蜂鸣器通电就响,只能发一种声音;无源蜂鸣器需要不同频率的方波驱动,可以演奏简单的旋律,可玩性更高。我们可以为“阶段提示”和“结束提示”设计不同的短促音效。
4. 交互元件一个6x6mm 轻触开关足矣。考虑防水需求(毕竟在卫生间使用),可以选用带硅胶帽的密封按键,或者在成品外壳上做好防水处理。
5. 电路设计思路整体电路非常简单。ATTiny85为核心,按钮接一个IO口并启用内部上拉电阻。RGB LED的三个阴极通过三个限流电阻(约220欧姆)分别接到三个IO口,阳极接VCC(3V)。无源蜂鸣器一端接另一个IO口,另一端接地。这里有一个关键点:为了在3V电压下让蜂鸣器足够响,可以考虑用一个三极管(如S8050)进行放大驱动。
注意:在纽扣电池供电系统中,所有元件的静态功耗都必须仔细考量。ATTiny85要设置为在待机时进入深度睡眠模式,仅靠按钮中断唤醒。RGB LED在待机时应完全熄灭,不能有任何漏电流。
2.3 软件逻辑与状态机设计
软件是项目的灵魂。我们需要用一个清晰的状态机来管理设备的所有行为。
设备主要有以下几个状态:
- 深度睡眠状态:主循环停止,仅保留外部中断唤醒功能。RGB LED熄灭,蜂鸣器静音。功耗极低。
- 待机唤醒状态:按下按钮后,芯片被唤醒,进入待机模式。RGB LED呈现缓慢呼吸灯效果(比如蓝色),表示设备已就绪,等待启动计时。
- 刷牙计时状态:在待机状态下再次按下按钮,进入此状态。这是一个持续120秒的倒计时子状态机。它内部又分为4个30秒的子阶段。每个子阶段,LED显示一种颜色,并在阶段切换时(每30秒)让蜂鸣器发出一个短促提示音(如“嘀”一声),提示用户更换刷牙区域。
- 计时完成状态:120秒倒计时结束。LED快速闪烁(比如红绿交替),蜂鸣器播放一段完成的旋律(如“嘀嘀嘀-嘀”)。持续5-10秒后,自动跳转回深度睡眠状态。
此外,还需要一个低电量检测状态。可以利用ATTiny85的内部基准电压和ADC功能,定期(比如每次唤醒时)检测电池电压。当电压低于阈值(如2.7V)时,无论处于何种状态,都让LED显示红色常亮,提醒更换电池。
3. 核心细节解析与实操要点
3.1 ATTiny85的深度睡眠与中断唤醒配置
实现超长待机的关键在于让MCU在不工作时“睡死”。对于ATTiny85,我们可以使用avr/sleep.h库。
#include <avr/sleep.h> #include <avr/power.h> #include <avr/wdt.h> // 设置睡眠模式为最省电的 POWER_DOWN set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); // 配置引脚中断(假设按钮接在引脚2,即PB3) pinMode(buttonPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(buttonPin), wakeUp, FALLING); // 下降沿触发 // 进入睡眠 sleep_cpu(); // 唤醒后执行的函数 void wakeUp() { // 首先禁用中断,防止误触发 detachInterrupt(digitalPinToInterrupt(buttonPin)); // 其他唤醒初始化代码... }实操要点:
- 去抖动:机械按钮在按下时会产生一段时间的电平抖动,可能误触发多次中断。必须在中断服务程序(ISR)或主循环中做软件去抖动,通常延时20-50毫秒再检测引脚状态。
- 关闭未用模块:在进入睡眠前,使用
power_all_disable()关闭ADC、定时器等所有外设以省电。 - 看门狗定时器:如果需要有定时唤醒功能(如定时检查电量),可以配置看门狗定时器(WDT)中断唤醒。但本项目完全由用户按钮触发,无需使用。
3.2 多色LED的状态指示与PWM控制
我们用单个RGB LED传达丰富信息,这就需要精确控制其亮灭和颜色。由于使用了共阳极LED(阳极接VCC),我们需要通过将阴极引脚拉低(输出LOW)来点亮对应颜色的LED。
颜色混合:要显示黄色,需要同时点亮红色和绿色。要显示白色,则同时点亮红、绿、蓝。但ATTiny85的引脚输出是数字信号(HIGH/LOW),要实现呼吸灯效果或调节亮度,必须使用PWM(脉冲宽度调制)。
// 定义引脚 const int redPin = 0; // PB0 const int greenPin = 1; // PB1 const int bluePin = 4; // PB4 // 设置引脚为输出 pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT); // 显示纯绿色(仅绿色阴极拉低) digitalWrite(redPin, HIGH); // 关闭红 analogWrite(greenPin, 0); // PWM值0,相当于持续拉低,最亮 digitalWrite(bluePin, HIGH); // 关闭蓝 // 显示橙色(红亮+绿半亮) analogWrite(redPin, 50); // 红色中等亮度(PWM值小,亮度高) analogWrite(greenPin, 150); // 绿色较低亮度 digitalWrite(bluePin, HIGH); // 实现呼吸灯效果(以蓝色为例) for (int brightness = 0; brightness <= 255; brightness++) { analogWrite(bluePin, 255 - brightness); // 注意:共阳极是反相PWM delay(10); } for (int brightness = 255; brightness >= 0; brightness--) { analogWrite(bluePin, 255 - brightness); delay(10); }注意:ATTiny85并非所有引脚都支持硬件PWM。通常PB0和PB1支持,PB4可能不支持。如果PB4不支持硬件PWM,又想用它做呼吸灯,就需要用软件模拟,这会占用大量CPU时间且效果不佳。因此,在PCB布局时,务必把需要PWM控制的颜色接到支持硬件PWM的引脚上。
3.3 无源蜂鸣器的驱动与简单旋律编程
无源蜂鸣器就像一个小型扬声器,需要输入不同频率的方波才能发出不同音调。我们可以利用tone()函数来驱动,但ATTiny85的核心库可能不直接支持tone(),或者该函数可能与中断、睡眠产生冲突。更可靠的方法是使用一个硬件定时器来生成特定频率的PWM信号。
一个更简单实用的方法是:既然我们的音效很简单(只有几个提示音),我们可以预先计算好音调对应的频率和延时,然后用digitalWrite快速翻转引脚来模拟方波。
// 简单发出一个1KHz声音,持续200ms void beep(int pin, int frequency, long duration) { long period = 1000000L / frequency; // 计算周期(微秒) long elapsedTime = 0; while (elapsedTime < duration * 1000L) { digitalWrite(pin, HIGH); delayMicroseconds(period / 2); digitalWrite(pin, LOW); delayMicroseconds(period / 2); elapsedTime += period; } } // 播放“完成”旋律(例如:中音Do, Re, Mi) void playFinishMelody(int pin) { beep(pin, 523, 200); // Do delay(50); beep(pin, 587, 200); // Re delay(50); beep(pin, 659, 300); // Mi }实操心得:这种digitalWrite加delayMicroseconds的方式在播放声音时会阻塞整个程序。这意味着在蜂鸣器响的几百毫秒内,LED动画会暂停,计时也可能不准确。对于 #TBT 这种简单应用,短暂的阻塞可以接受。如果要求严格,则需要用定时器中断来驱动蜂鸣器,但这会大大增加代码复杂度。
4. 实操过程与核心环节实现
4.1 原型搭建与面包板测试
在焊接正式电路板之前,必须在面包板上完成功能验证。这是排查逻辑错误和硬件连接问题最安全的阶段。
所需材料清单:
- ATTiny85 芯片一枚
- CR2032 电池座一个
- 共阳极RGB LED 一个
- 220欧姆电阻 三个(用于LED限流)
- 无源蜂鸣器(5V) 一个
- NPN三极管 S8050 一个(用于驱动蜂鸣器)
- 1k欧姆电阻 一个(用于三极管基极限流)
- 轻触开关 一个
- 面包板、杜邦线若干
接线步骤:
- 供电:将CR2032电池座的正极(+)接面包板正极轨,负极(-)接负极轨。
- MCU:将ATTiny85插入面包板。其引脚1(~RESET)接正极(通过一个10k上拉电阻会更稳定)。引脚8(VCC)接正极,引脚4(GND)接负极。
- RGB LED:将LED的共阳极(最长脚)接正极。红色阴极通过220欧电阻接PB0,绿色接PB1,蓝色接PB4。
- 蜂鸣器驱动:蜂鸣器正极接三极管S8050的集电极(C),蜂鸣器负极接GND。三极管发射极(E)接GND。基极(B)通过1k电阻接ATTiny85的某个IO口(如PB3)。
- 按钮:按钮一端接GND,另一端接ATTiny85的PB2引脚,并在PB2与VCC之间连接一个10k上拉电阻(或者启用芯片内部上拉)。
连接好后,使用USBasp或Arduino Uno作为编程器,将测试程序烧录进ATTiny85。测试程序应依次验证:按钮按下唤醒、LED颜色变化、蜂鸣器发声、低功耗睡眠。
4.2 PCB设计与焊接要点
面包板验证无误后,就可以设计一个专属的PCB了,这能让作品更小巧、稳固和专业。我使用立创EDA进行设计。
设计要点:
- 布局紧凑:围绕ATTiny85布局,将按钮、LED、蜂鸣器驱动电路放在芯片周围,缩短走线。
- 电源路径清晰:电池座输入处放置一个10uF的电解电容进行电源滤波,防止瞬间电流导致电压跌落复位。
- 预留调试接口:留出ATTiny85的SPI编程接口(MOSI, MISO, SCK, RESET)的焊盘,方便后续烧录和调试。
- 考虑装配:电池座、按钮、LED的位置要考虑到最终外壳的开孔。LED最好加上导光柱,让光线更柔和分散。
焊接顺序与技巧:
- 先贴片,后直插:先焊接电阻、三极管等小的贴片元件,再焊接芯片座(建议使用IC座,便于更换芯片),最后焊接电池座、按钮等直插元件。
- 焊接ATTiny85:如果直接焊芯片,务必使用尖头烙铁,控制好温度和时间,防止静电和过热损坏。焊完后用放大镜检查有无桥连。
- 测试供电:焊接完电源部分后,先别焊芯片,用万用表测量VCC和GND之间的电压是否为3V左右,且无短路。
4.3 软件代码框架与核心函数
以下是 #TBT 主程序的核心框架,体现了之前提到的状态机思想。
// 引脚定义 const int buttonPin = 3; // PB3 (物理引脚2) const int redPin = 0; // PB0 const int greenPin = 1; // PB1 const int bluePin = 4; // PB4 const int buzzerPin = 2; // PB2 (驱动三极管基极) // 状态定义 enum DeviceState { SLEEP_MODE, STANDBY, BRUSHING, FINISHED, LOW_BATTERY }; DeviceState currentState = SLEEP_MODE; // 计时相关变量 unsigned long brushStartTime = 0; const unsigned long brushDuration = 120000; // 2分钟,单位毫秒 const int segmentDuration = 30000; // 30秒 void setup() { // 初始化引脚 pinMode(buttonPin, INPUT_PULLUP); pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT); pinMode(buzzerPin, OUTPUT); digitalWrite(buzzerPin, LOW); // 初始状态:进入睡眠 enterSleepMode(); } void loop() { // 主循环根据当前状态执行不同任务 switch (currentState) { case STANDBY: handleStandbyState(); break; case BRUSHING: handleBrushingState(); break; case FINISHED: handleFinishedState(); break; case LOW_BATTERY: handleLowBatteryState(); break; // SLEEP_MODE 状态下,loop() 不会被执行 default: break; } // 在每个状态处理函数中,都会检查是否需要进行状态转换 } // 唤醒中断服务程序 void wakeUp() { // 此函数内尽量只做标志位修改,避免耗时操作 detachInterrupt(digitalPinToInterrupt(buttonPin)); currentState = STANDBY; } void enterSleepMode() { setColor(0, 0, 0); // 关闭LED digitalWrite(buzzerPin, LOW); // 配置睡眠和中断 set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); attachInterrupt(digitalPinToInterrupt(buttonPin), wakeUp, FALLING); sleep_cpu(); // 程序在此挂起,直到中断唤醒 sleep_disable(); // 唤醒后继续执行 } void handleStandbyState() { // 显示呼吸灯效果 breatheLED(0, 0, 255); // 蓝色呼吸 // 检查按钮是否被按下(开始刷牙) if (isButtonPressed()) { brushStartTime = millis(); currentState = BRUSHING; playStartTone(); setColor(0, 255, 0); // 绿色,表示第一个区域开始 } // 可以在这里加入检查电池电量的逻辑 } void handleBrushingState() { unsigned long currentTime = millis(); unsigned long elapsed = currentTime - brushStartTime; if (elapsed >= brushDuration) { currentState = FINISHED; return; } // 判断当前处于哪个30秒区间 int currentSegment = elapsed / segmentDuration; // 0, 1, 2, 3 // 根据区间更新LED颜色 switch (currentSegment) { case 0: setColor(0, 255, 0); break; // 绿 case 1: setColor(255, 255, 0); break; // 黄 case 2: setColor(255, 165, 0); break; // 橙 case 3: setColor(255, 0, 0); break; // 红 } // 检查是否刚到新区间(每30秒提示一次) static int lastSegment = -1; if (currentSegment != lastSegment) { lastSegment = currentSegment; playSegmentTone(); // 播放“嘀”一声提示音 } // 短暂延时,防止loop跑太快 delay(100); } // handleFinishedState 和 handleLowBatteryState 函数省略...5. 外壳设计与制作心得
电路和代码完成后,#TBT 还需要一个“家”。外壳不仅提供保护,更是提升用户体验和美观度的关键。
设计考量:
- 防水防潮:卫生间环境潮湿。外壳应尽可能密封。按钮处采用硅胶防水帽,LED和蜂鸣器出声孔要小而密,或使用防水透声膜。
- 固定方式:如何放置在洗手台?可以考虑背面贴3M无痕胶,或者设计一个支架。我选择设计一个带倾斜角度的底座,让它能自然地立在台面上。
- 人机交互:按钮要足够大,手感清晰。LED光线不能太刺眼,最好通过磨砂亚克力或导光材料进行柔化。
- 电池更换:设计可拆卸的后盖,方便更换CR2032电池。
制作方法:
- 3D打印:这是最灵活的方式。使用FDM打印机(如Creality Ender系列)打印PLA材质的外壳。设计时要注意壁厚(建议1.2-2mm)、预留螺丝柱和卡扣。打印完成后,可以进行打磨、喷涂上色。
- 亚克力激光切割:适合制作结构简单的层叠式外壳。将设计好的面板(顶板、底板、中间隔层)用激光切割出来,再用螺丝或胶水组装。优点是外观精致,透光性好。
- 现成盒子改造:找一个尺寸合适的防水接线盒,在盒子上开孔安装按钮和LED。这是最快但美观度最差的方法。
我的选择与心得:我采用了3D打印。首先在Fusion 360里建模,将PCB、电池座、按钮的3D模型导入,根据它们精确设计内部卡槽和支柱。顶部为LED和蜂鸣器开了密集的小孔阵列,既保证透光和出声,又能一定程度上防止水溅入。按钮孔上方预留了放置硅胶帽的凹槽。打印时使用0.1mm层高以获得更光滑的表面。完成后,我用细砂纸打磨,并喷了两层白色底漆和一层哑光清漆,最终效果非常令人满意。
踩坑记录:第一次设计时,忽略了按钮的行程和复位空间,导致外壳装上后按钮被顶死,一直处于按下状态。修改模型时,必须在按钮顶部和外壳内壁之间留出至少0.5mm的间隙。另外,如果使用内部上拉电阻,务必在软件中启用(
INPUT_PULLUP),否则飞线焊接外部上拉电阻在狭小空间内非常麻烦。
6. 功耗测试与优化实录
对于电池供电设备,功耗直接决定了用户体验(更换电池的频率)。我们必须对成品进行严格的功耗测试。
测试工具:万用表(电流档),最好是有数据记录功能的万用表或专用的功耗分析仪。
测试步骤与结果:
- 深度睡眠模式:将设备置于睡眠状态,测量电流。理想情况下,ATTiny85在POWER_DOWN模式下电流可低于1μA。但实际电路中,其他元件可能有漏电。我的初版实测约为5μA。经检查,是因为RGB LED的限流电阻直接接到了VCC,即使IO口输出高电平,仍有极微小的漏电流通路。解决方法是在软件中,将控制LED的引脚在睡眠前设置为
INPUT模式(高阻态),彻底断开路径。优化后睡眠电流降至0.8μA。 - 待机唤醒状态:此时MCU全速运行,LED呼吸灯闪烁。实测平均电流约为3-5mA。这个状态持续时间很短(等待用户第二次按键),功耗可以接受。
- 刷牙计时状态:LED常亮,蜂鸣器间歇发声。LED电流最大,约10-15mA(取决于颜色和亮度)。这是功耗最高的阶段,但每天总计只持续4分钟。
- 完成提示状态:LED闪烁,蜂鸣器响。电流在5-20mA间波动。
电池寿命估算: 以CR2032电池典型容量220mAh计算。
- 每天睡眠23小时56分钟,电流0.8μA,耗能:23.93h * 0.0008mA ≈ 0.019 mAh
- 每天待机+操作(计4.5分钟),平均电流按8mA估算,耗能:0.075h * 8mA ≈ 0.6 mAh
- 日总耗能 ≈ 0.619 mAh
- 理论续航 = 220 mAh / 0.619 mAh/天 ≈ 355天
这个估算表明,优化后的一颗CR2032电池可以使用近一年,完全满足实用需求。这个优化过程让我深刻体会到,低功耗设计的关键在于关注每一个可能漏电的细节,尤其是IO口的状态和外围电路的静态电流。
7. 常见问题与排查技巧实录
在制作和调试 #TBT 的过程中,我遇到了不少典型问题。这里将它们整理成表,希望能帮你避开这些坑。
| 问题现象 | 可能原因 | 排查方法与解决方案 |
|---|---|---|
| 设备完全无反应,LED不亮 | 1. 电池没电或装反。 2. 电源线断路或虚焊。 3. ATTiny85未烧录程序或烧录失败。 4. 芯片损坏。 | 1. 用万用表测电池电压,确认>2.8V。 2. 仔细检查VCC和GND走线,重新焊接可疑焊点。 3. 用编程器尝试重新烧录一个简单的“点灯”测试程序。 4. 更换一片新的ATTiny85。 |
| 按钮按下无反应,无法唤醒 | 1. 按钮接线错误或损坏。 2. 中断引脚配置错误。 3. 睡眠模式设置不正确。 4. 软件中去抖动逻辑过于严格或错误。 | 1. 用万用表通断档检查按钮按下时是否导通。 2. 确认 digitalPinToInterrupt()使用的引脚号正确。3. 检查 set_sleep_mode()和sleep_enable()是否被正确调用。4. 简化程序,先去掉去抖动逻辑,看中断能否触发。 |
| LED颜色显示不正常或很暗 | 1. RGB LED共阴/共阳极接错。 2. 限流电阻阻值过大。 3. PWM输出引脚不对或代码逻辑反了。 4. 电池电压不足。 | 1. 确认是共阳LED,阳极接VCC。用万用表二极管档测试LED各引脚。 2. 对于3V供电,220欧电阻亮度足够。可尝试减小到100欧观察。 3. 共阳LED是低电平点亮。确认 analogWrite(pin, 0)最亮,255最暗。4. 换新电池测试。 |
| 蜂鸣器不响或声音小 | 1. 是无源蜂鸣器但用了tone()函数?或者代码未驱动。2. 三极管驱动电路接错(C/E极接反)。 3. 蜂鸣器本身损坏。 4. IO口驱动能力不足。 | 1. 确认代码中buzzerPin有输出频率方波。用示波器或另一个蜂鸣器并联测试。2. 检查S8050三极管:基极(B)通过电阻接IO,集电极(C)接蜂鸣器正极,发射极(E)接GND。 3. 直接给蜂鸣器两端加3V直流电,看是否微响(无源蜂鸣器会轻微“嗒”一声)。 4. 尝试减小基极限流电阻(如从1k降到500欧),增大基极电流。 |
| 计时不准,时间忽快忽慢 | 1. 使用了delay()函数,且被中断或其他阻塞操作干扰。2. 依赖于 millis()但发生了溢出(约50天后)。3. 芯片内部时钟校准不准。 | 1. 确保计时主循环 (handleBrushingState) 中除了简短的delay(100)外,没有其他长延时。2. 对于两分钟计时, millis()溢出无需考虑。但好的习惯是用(currentTime - startTime) >= duration的比较方式,可防溢出。3. ATTiny85内部8MHz时钟可能有偏差。可通过烧录器的“芯片编程”功能校准内部振荡器。 |
| 耗电极快,几天就没电 | 1. 睡眠模式未成功进入或电流未降下来。 2. LED或外围电路在睡眠时仍在耗电。 3. 电池质量差或负载瞬间电流大导致电压骤降。 | 1. 用万用表uA档实测睡眠电流,应<10μA。检查sleep_cpu()前后是否有代码阻止睡眠。2. 将所有未使用的IO口设置为 INPUT_PULLUP或OUTPUT并置低。断开LED、蜂鸣器与VCC的直接连接。3. 在电池端并联一个100uF以上的电解电容,缓冲蜂鸣器响瞬间的大电流。 |
最后的个人体会:制作 #TBT 的过程,远不止是焊接一块电路板和写几行代码。它是一次完整的“产品思维”训练:从定义问题、设计解决方案,到考虑用户体验、功耗、结构,最后进行测试和优化。当我把这个不起眼的小盒子粘在浴室镜旁,并真的依靠它养成了刷满两分钟的习惯时,那种通过自己双手解决一个真实小问题的满足感,是无可替代的。它提醒我,技术不只是酷炫的算法和复杂的系统,更是让日常生活变得更好一点点的朴素力量。如果你也感兴趣,不妨动手做一个,从点亮第一颗LED开始,感受创造的乐趣。
