基于Arduino的智能泡茶机DIY:从硬件选型到状态机编程全解析
1. 项目概述与设计思路
泡茶这事儿,讲究起来挺麻烦的。水温、时间、茶叶量,哪个环节差了点儿,味道就天差地别。尤其是冲泡时间,说好三分钟,一转身接个电话就忘了,回来茶汤又苦又涩,白白浪费了好茶叶。市面上倒是有一些定时泡茶器,但要么功能单一,要么价格不菲,最关键的是,它们往往不够“听话”——没法灵活调整高度适应不同的杯具,或者中途想改变冲泡时间也无能为力。
于是,我琢磨着自己动手做一个。我的核心需求很明确:第一,它得足够“聪明”,能精确计时并自动完成茶叶的浸泡与分离;第二,它要足够“灵活”,能轻松适配从马克杯到小茶壶的各种容器;第三,操作必须“直观简单”,最好一只手就能完成所有设置,另一只手还能空出来加水、拿茶叶。这就是“Teatimer 2.0”智能泡茶机项目的由来。它不是一个花架子,而是为了真正解决日常饮茶中的痛点,通过Arduino这个开源硬件平台,将机械控制、人机交互和一点小小的自动化逻辑结合起来,打造一个既实用又有趣的DIY智能家居小装置。
整个项目的核心思路,是构建一个以用户交互为起点、以机械执行为终点的闭环控制系统。用户通过旋转编码器这个“指挥官”输入指令(设置高度、时间),Arduino作为“大脑”处理这些指令,并驱动伺服电机这个“手臂”执行升降动作,同时通过LCD显示屏这个“嘴巴”实时反馈系统状态。如果需要,还可以加上MP3模块这个“广播员”进行语音提示。这个流程清晰地将嵌入式系统的几个关键模块——输入、处理、输出、执行——串联了起来,非常适合作为学习物联网和智能设备开发的入门实践项目。
2. 核心组件选型与功能解析
2.1 控制核心:Arduino开发板
为什么选择Arduino Leonardo?在这个项目中,主控板需要具备几个关键能力:足够的数字I/O引脚连接多个外设、稳定的5V输出为传感器供电、以及可靠的PWM(脉冲宽度调制)信号输出以精确控制伺服电机。Arduino Leonardo完全满足这些要求。它基于ATmega32u4微控制器,原生支持USB通信,这使得它在连接电脑上传程序时更为稳定。相较于经典的Uno,Leonardo的USB芯片直接集成在主控芯片内,省去了额外的USB转串口芯片,在需要用到硬件串口(Serial1)与MP3模块通信时,避免了软件模拟串口可能带来的时序冲突和不稳定问题。
注意:如果手头只有Arduino Uno,项目也能完成,但连接DFPlayer Mini MP3模块时,必须使用
SoftwareSerial库来模拟串口,因为Uno的唯一硬件串口(RX/TX)通常被用于程序上传和监控。这可能会在同时驱动伺服电机和刷新LCD时引入轻微的时序延迟或冲突,需要更仔细的代码调试。
2.2 人机交互界面:旋转编码器与LCD屏
旋转编码器(KY-040)是本项目交互的灵魂。它集成了旋转和按压两种操作。旋转用于无级调整数值(高度、时间),按压(按下轴)用于确认选择或进入下一菜单。这种交互逻辑非常符合直觉,类似于老式收音机的调谐旋钮,单手即可流畅操作。KY-040内部是两个机械触点,旋转时会产生两路相位差90度的方波信号(CLK和DT)。通过检测这两路信号的先后顺序,就能判断是顺时针还是逆时针旋转,实现数值的增减。
LCD 1602 I2C显示屏负责状态反馈。选择I2C接口版本是至关重要的简化步骤。传统的1602屏需要连接多达6根线(RS, RW, E, D4-D7),而I2C版本仅需4根线(VCC, GND, SDA, SCL),通过一个背面的小转接板与Arduino通信。这极大地节省了宝贵的I/O口,并简化了布线。显示屏会清晰展示欢迎语、当前设置的高度、倒计时时间等信息,让整个操作过程一目了然。
2.3 执行机构:伺服电机
MG995伺服电机担任了“机械臂”的角色。伺服电机与普通直流电机的最大区别在于,它可以接收PWM信号,并精确地转动到指定的角度(如0-180度)。我们正是利用这一特性,通过编程让电机转动特定角度,从而带动连接在其轴上的“茶漏臂”升降到预设的高度。选择180度型号(而非360度连续旋转型号)是因为我们需要的是精确的位置控制,而不是速度控制。MG995扭矩大(约13kg/cm),足以轻松提起装有茶叶和水的茶漏。
关键参数调校:伺服电机的控制信号是周期为20ms(50Hz)的PWM波,其中高电平的脉宽在0.5ms到2.5ms之间变化,对应着0度到180度的位置。在Arduino中,我们可以使用内置的Servo库,用servo.write(angle)命令轻松控制,库函数会自动生成对应的PWM信号。但需要注意的是,不同品牌、甚至同品牌不同批次的伺服电机,其脉宽与角度的对应关系可能存在微小偏差。这就是为什么在项目后期需要进行MIN_HEIGHT和MAX_HEIGHT参数校准,以确保机械臂的升降范围既满足使用需求,又不会因过度转动而撞击外壳导致损坏。
2.4 可选模块:DFPlayer Mini MP3模块
这是一个提升体验感的加分项。DFPlayer Mini是一个小巧而强大的MP3解码模块,可以直接读取SD卡或TF卡中的音频文件,并通过一个简单的串口指令集进行控制。我们用它来播放两段音频:开机问候语和泡茶完成提示音。它的加入,让这个DIY设备有了一丝“智能产品”的亲和力。接线时需特别注意,其RX引脚(接收端)不能直接连接Arduino的TX引脚(5V电平),必须串联一个1kΩ的电阻进行限流,以保护模块的输入引脚。
3. 电路系统搭建与接线详解
电路连接是整个项目的“神经系统”,确保信号和电力准确无误地传递。虽然原理图看起来简单,但实际动手时,清晰的接线表和一丝不苟的操作能避免很多后续的调试麻烦。
3.1 电源方案设计与避坑
电源是首先要考虑清楚的问题。最初我尝试使用常见的9V方块电池或适配器为Arduino供电,但遇到了显示异常的问题。LCD屏幕会闪烁甚至熄灭。经过排查和测量发现,当伺服电机动作,尤其是从静止状态启动时,会产生一个较大的瞬时电流。Arduino板载的5V稳压芯片(如AMS1117)输出电流能力有限(通常约800mA-1A),这个电流冲击可能导致其输出电压瞬间被拉低,造成连接在同一5V总线上的LCD显示屏因供电不足而复位或关闭。
解决方案:放弃从Arduino的VIN或电源接口输入高压再降压的方案,改为直接使用5V/2A的USB电源适配器,通过Arduino的Micro-USB口供电。这种方式的优势在于,USB适配器本身提供了稳定且足额的5V输出,Arduino板在此模式下更像一个“直通”的分配器,其板载稳压电路不工作,从而避免了电流瓶颈。实测证明,这种方式非常稳定。你也可以选择使用一个外部的5V/3A开关电源,同时为Arduino和伺服电机供电(需共地),但USB方案最为简便安全。
3.2 分步接线实操与验证
建议在将所有元件装入木盒之前,先在面包板上完成所有连接并做初步测试。这能确保每个模块都是好的,代码基本功能正常,避免封装好后发现问题再拆解的尴尬。
第一步:连接旋转编码器将KY-040模块插入面包板。其五个引脚分别为:CLK(时钟)、DT(数据)、SW(开关)、+(VCC)、GND(地)。
CLK-> Arduino数字引脚11DT-> Arduino数字引脚10SW-> Arduino数字引脚3(注意:该引脚需要在代码中启用内部上拉电阻)+-> Arduino5VGND-> ArduinoGND
第二步:连接LCD I2C显示屏找到显示屏背面的I2C转接板(通常是一个蓝色或黑色的小板),它只有4个引脚:
GND-> ArduinoGNDVCC-> Arduino5VSDA-> ArduinoSDA(在Leonardo上,这是物理引脚2)SCL-> ArduinoSCL(在Leonardo上,这是物理引脚3) 连接后通电,屏幕可能会亮起但无字符。这时需要找到转接板上一个很小的电位器(通常用十字螺丝刀调节),缓慢旋转它,直到屏幕出现一排黑色方块或清晰的字符。这个电位器调节的是LCD的对比度电压。
第三步:连接伺服电机伺服电机通常有三根线,颜色标准为棕色(GND)、红色(VCC)、橙色(信号)。
棕色(GND)-> ArduinoGND红色(VCC)-> Arduino5V橙色(Signal)-> Arduino数字引脚8
第四步:(可选)连接DFPlayer Mini MP3模块这是接线中最需要小心的一步。将模块插入面包板,确保引脚没有短路。
VCC-> Arduino5VGND-> ArduinoGNDRX-> 串联一个1kΩ电阻后,连接到Arduino的TX(引脚1)TX-> Arduino的RX(引脚0)SPK1和SPK2-> 连接到一个4Ω或8Ω的小扬声器两端。
重要提示:在连接MP3模块的RX线时,务必串联那个1kΩ电阻!DFPlayer Mini的RX引脚逻辑电平是3.3V,而Arduino的TX输出是5V。直接连接长期使用可能会损坏模块。这个电阻起到了限流和分压的作用,是必要的保护措施。
完成所有接线后,检查一遍是否有松动或短路。然后就可以通过USB线将Arduino连接到电脑,准备上传程序了。
4. 机械结构设计与组装工艺
电路是项目的灵魂,机械结构则是其骨骼和肌肉。一个稳固、精准的机械结构,是泡茶机可靠运行的基础。我选择了木材作为主要材料,因为它易于加工、成本低,且外观有温暖的质感。
4.1 木制外壳的加工与组装
材料清单中给出了具体的木板尺寸,你可以根据手头材料微调。核心是制作一个六面体的盒子,前面板需要开多个孔洞。
开孔规划与切割:在前面板(150mm x 200mm的板子)上,用铅笔精确标记出所有开孔位置。
- LCD方孔:根据你的LCD屏实际尺寸(通常是80mm x 36mm左右)画框,然后用线锯或曲线锯小心切割。孔可以比屏幕略小,这样屏幕可以从背后安装并卡住。
- 机械臂竖槽:这是一个关键孔。它需要允许连接茶漏的臂上下自由运动。画一个宽约10mm,高约120mm的竖长条形孔。这个孔的位置要居中偏上,为下方的伺服电机留出空间。
- 编码器圆孔:在面板右下角(便于右手操作)钻一个直径约8mm的孔,用于固定编码器的旋转轴。
- 扬声器音孔:在面板侧面或背面,钻一系列小孔阵列组成音孔,用于透出提示音。
箱体组装:使用直角夹辅助,将底板、两个侧板、前面板对齐。先用细钻头(如2mm)在所有连接处预钻导引孔,这能防止木头开裂。然后使用提供的4.5mm x 30mm自攻螺丝进行固定。先组装底板和两个侧板,再固定前面板。热熔胶在这里可以作为辅助固定和密封缝隙的好帮手,在螺丝固定前,在接合处涂上热熔胶,能增加强度并减少晃动。
4.2 伺服电机支架与机械臂制作
这是机械部分的核心,目标是让伺服电机牢固地安装在箱体内,并能平稳地带动机械臂升降。
制作电机安装板:切割一块PVC硬泡沫板(或薄木板)作为电机座板。将MG995伺服电机用附送的小螺丝固定在这块板上。然后,切割四块小木块(约15mm立方体),作为电机座板与箱体之间的支撑柱。用热熔胶将这四块小木块粘在座板的四个角下方。
安装与定位:将组装好的电机座板放入箱内,使其位于机械臂竖槽的正后方。通过竖槽观察,调整座板位置,确保未来伺服电机转轴的中心对准竖槽的中心线。位置确定后,用热熔胶将四个支撑柱的下方粘在箱体底板上。为了更牢固,可以在木块侧面也打上少量热熔胶,使其与侧板粘连。
制作与安装机械臂:取一根5mm x 15mm x 230mm的木条作为主臂。在一端钻一个小孔,用于悬挂茶漏钩;在距离该端约30mm处,钻一个与伺服电机舵盘固定螺丝匹配的孔(通常是M2规格)。关键步骤来了:先不要将臂装上电机。给系统通电,Arduino程序初始化后,伺服电机会自动归中(转动到90度位置)。在这个位置,将伺服电机的舵盘(那个白色的塑料圆盘)安装到电机轴上,然后将木臂通过螺丝固定到舵盘上。此时,臂杆的方向就是系统的“中间位置”。这样做的目的是让我们在软件中校准
MIN_HEIGHT和MAX_HEIGHT时,有一个明确的物理参考点,避免机械臂在极限位置卡死。最终固定:将连接好臂杆的伺服电机组件,通过座板上的安装孔,用3mm x 15mm的螺丝最终紧固在之前粘好的支撑柱上。确保所有螺丝拧紧,但注意不要过度用力导致塑料舵盘开裂。
5. 软件程序解析与关键代码逻辑
硬件搭建完毕,接下来就是赋予它“智慧”的软件部分。项目的核心代码逻辑清晰,主要分为初始化、状态机循环、中断处理三大部分。
5.1 核心状态机设计
整个泡茶机的工作流程,是通过一个“状态机”来管理的。状态机就像一个有多个档位的开关,机器在任何时刻只处于一个特定状态,并根据输入(编码器动作)切换到下一个状态。
// 定义状态枚举 enum State { WELCOME, // 欢迎状态,显示欢迎语 SET_HEIGHT, // 设置高度状态 SET_TIME, // 设置时间状态 BREWING, // 冲泡倒计时状态 TEA_READY // 完成状态 }; State currentState = WELCOME;程序主循环loop()中,通过一个switch-case语句来根据currentState执行不同的操作:
WELCOME状态:显示欢迎信息,播放欢迎音(如果启用),等待用户按下编码器。SET_HEIGHT状态:显示当前臂杆高度值。旋转编码器可以增加/减少高度值(该值会映射到伺服电机角度),LCD实时更新。按下编码器确认高度,并切换到SET_TIME状态,同时伺服电机转动到指定高度。SET_TIME状态:显示当前设置的冲泡时间(秒)。旋转编码器调整时间。按下编码器开始冲泡,进入BREWING状态。BREWING状态:开始倒计时。LCD显示剩余时间。此时依然可以旋转编码器来增加或减少剩余时间,这是一个非常实用的功能,让你可以灵活调整冲泡强度。如果减少到0,则立即停止。倒计时归零后,伺服电机缓慢抬起臂杆(防止水花四溅),播放完成提示音,进入TEA_READY状态。TEA_READY状态:显示“Tea is Ready!”。按下编码器返回WELCOME状态。
5.2 旋转编码器中断处理
为了实现流畅、无延迟的旋转检测,我们必须使用中断。中断可以让Arduino在干其他事(如更新显示)时,立即响应编码器的转动事件。
// 引脚定义 #define ENCODER_CLK 11 #define ENCODER_DT 10 #define ENCODER_SW 3 // 变量声明 volatile int lastEncoded = 0; // 必须用volatile,因为在中断中修改 long encoderValue = 0; void setup() { ... pinMode(ENCODER_CLK, INPUT_PULLUP); pinMode(ENCODER_DT, INPUT_PULLUP); // 为CLK和DT引脚附加中断,当引脚电平变化时触发updateEncoder函数 attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), updateEncoder, CHANGE); attachInterrupt(digitalPinToInterrupt(ENCODER_DT), updateEncoder, CHANGE); ... } void updateEncoder() { // 读取两个引脚当前状态,组合成一个2位二进制数 int MSB = digitalRead(ENCODER_CLK); int LSB = digitalRead(ENCODER_DT); int encoded = (MSB << 1) | LSB; // 与上一次状态组合成一个4位索引,查表判断方向 int sum = (lastEncoded << 2) | encoded; if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue++; if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue--; lastEncoded = encoded; }这段代码是编码器解码的核心。它利用了KY-040旋转时CLK和DT输出波形相位差的关系,通过一个状态查表法,非常高效且去抖地判断出旋转方向,并更新encoderValue变量。主循环中只需要读取这个变量的变化,就能知道用户调整了多少“格”。
5.3 伺服电机控制与高度校准
伺服电机控制本身很简单,但校准过程是保证机械可靠性的关键。
#include <Servo.h> Servo myServo; #define MIN_HEIGHT 20 // 对应伺服电机角度下限(臂杆最低位置) #define MAX_HEIGHT 85 // 对应伺服电机角度上限(臂杆最高位置) #define START_HEIGHT 20 // 开机初始高度 int currentHeight = START_HEIGHT; void setArmHeight(int height) { // 将高度值(0-100)映射到伺服电机角度(MIN_HEIGHT - MAX_HEIGHT) int angle = map(height, 0, 100, MIN_HEIGHT, MAX_HEIGHT); // 限制角度在安全范围内 angle = constrain(angle, MIN_HEIGHT, MAX_HEIGHT); myServo.write(angle); delay(15); // 给伺服电机一点时间转动到位 }校准流程实操:
- 在代码中,先将
MIN_HEIGHT和MAX_HEIGHT都设置为一个中间值,例如60。 - 上传程序,通电。伺服电机会转到90度位置(因为
map函数将高度50映射到角度60,接近90)。 - 通过编码器进入
SET_HEIGHT状态,尝试增加高度值。观察机械臂向上转动。当臂杆即将碰到外壳顶部或感觉电机堵转(发出滋滋声)时,停止增加。记下此时LCD显示的高度值,假设为85。 - 尝试减少高度值,直到臂杆到达最低的、不会碰到茶壶或杯底的安全位置,记下此时高度值,假设为20。
- 将这两个值
85和20,分别更新到代码的MAX_HEIGHT和MIN_HEIGHT宏定义中。START_HEIGHT可以设为MIN_HEIGHT,这样开机时臂杆处于收起状态。 - 重新上传程序。现在,高度调整的范围就被安全地限制在了机械结构的物理极限内。
5.4 低功耗待机功能
为了让设备更省电、更安全,我加入了一个简单的待机功能。当设备在WELCOME状态无操作超过15分钟(可通过#define INTERVALL_SHUTDOWN调整),或者用户长按编码器2秒,系统会进入“半待机”模式。
void enterSleepMode() { lcd.noDisplay(); // 关闭LCD背光(对于I2C LCD,可能是lcd.noBacklight()) myServo.detach(); // 断开伺服电机信号线,使其停止供电并释放扭矩 // 注意:Arduino本身仍在运行,但功耗显著降低 } void wakeUp() { lcd.display(); // 开启LCD myServo.attach(SERVO_PIN); // 重新附着伺服电机 currentState = WELCOME; }这个实现并非真正的单片机深度睡眠,因为旋转编码器的中断检测需要MCU保持运行。但关闭显示器和伺服电机这两个“耗电大户”,已经能让待机电流从约150mA下降到50mA以下,对于长期插电使用的设备来说,既实用又简单。
6. 系统集成、调试与问题排查
当所有硬件和软件模块准备就绪,最后的集成与调试是项目成功的关键。这个过程就像组装一台精密钟表,需要耐心和细致。
6.1 分模块测试与联调
不要急于把所有东西塞进盒子。遵循以下步骤:
- 基础系统测试:仅连接Arduino、编码器、LCD。上传一个简单的测试程序,确保编码器旋转能改变LCD上显示的数字,按下编码器能切换模式。这验证了核心交互逻辑。
- 伺服电机测试:接上伺服电机。上传一个让伺服电机随编码器旋转而摆动的程序。观察运动是否平滑,有无异响。同时用手轻轻捏住舵盘,感受其扭矩是否足够(MG995应该很有力)。
- MP3模块测试(可选):接上MP3模块和扬声器。使用一个简单的串口测试程序,发送指令让其播放SD卡中的特定文件。确保音频能正常播放,音量适中。
- 整体功能联调:将所有模块连接好,上传完整的“Teatimer 2.0”固件。按照设计流程操作一遍:开机欢迎、设置高度(观察臂杆是否跟随移动)、设置时间、开始冲泡(观察倒计时显示)、完成冲泡(观察臂杆是否自动抬起)。检查每个环节是否顺畅。
6.2 常见问题与解决方案速查表
在实际组装和调试中,你可能会遇到以下问题。这里提供一个快速排查指南:
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| LCD屏幕不显示或显示乱码 | 1. 电源接触不良或电压不足。 2. I2C地址不对。 3. 对比度未调节。 | 1. 检查5V和GND连接,用万用表测量电压是否稳定在5V左右。 2. 扫描I2C地址(使用 Wire库示例程序),并在代码lcd.init()中更正。3.最重要:调节LCD背面I2C转接板上的蓝色电位器,直到字符清晰。 |
| 旋转编码器操作无反应或跳变 | 1. 接线错误,特别是CLK和DT接反。 2. 中断引脚冲突或未启用内部上拉。 3. 机械编码器接触不良。 | 1. 对照接线表检查CLK、DT引脚是否接对。 2. 在 setup()中确认引脚模式设置为INPUT_PULLUP。3. 尝试更换一个编码器模块。KY-040质量参差不齐。 |
| 伺服电机不转动或抖动 | 1. 电源功率不足。 2. 信号线接触不良。 3. 机械负载过重或卡死。 | 1.最常见原因:确保使用5V/2A以上的USB电源适配器供电,避免使用电脑USB口或弱电源。 2. 检查信号线(橙色)是否连接牢固。 3. 断开机械臂,空载测试电机是否正常转动。检查机械结构是否有阻碍。 |
| 伺服电机转动角度不准确 | 1.MIN_HEIGHT/MAX_HEIGHT参数未校准。2. 舵盘安装的物理零点不对。 | 1. 严格按照第5.3节的校准流程重新校准极限角度。 2. 断电,手动将臂杆放到理想的最低位置,然后装上舵盘,确保此时在代码中 write(MIN_HEIGHT)对应这个物理位置。 |
| MP3模块无声音 | 1. RX引脚未串电阻,或电阻损坏。 2. 音频文件格式或命名错误。 3. 音量设置为0或扬声器损坏。 | 1.务必检查:DFPlayer Mini的RX和Arduino的TX之间是否串联了1kΩ电阻。 2. 确保SD卡为FAT32格式,音频文件为MP3或WAV格式,并命名为0001.mp3, 0002.mp3等。 3. 在代码中调整 MP3_VOLUME值(范围0-30),尝试直接短接扬声器到手机音频口测试扬声器。 |
| 系统运行一段时间后复位 | 1. 电源不稳定,伺服电机动作时电压跌落。 2. 代码中有内存泄漏或死循环。 | 1. 再次确认并更换为更强大的5V电源(如手机快充头)。 2. 检查中断服务函数 updateEncoder()是否过于复杂或执行时间过长,确保其中没有delay()或打印语句。 |
| 机械臂运动不顺畅、有噪音 | 1. 木制部件摩擦过大。 2. 伺服电机轴与舵盘不同心。 3. 螺丝拧得过紧导致部件变形。 | 1. 在机械臂与外壳开槽的接触边缘涂抹一点蜡烛蜡或润滑脂。 2. 重新安装舵盘,确保安装平整,螺丝不要一次拧死,稍微留点活动余量再慢慢紧固。 3. 检查所有木制结构是否因螺丝过紧而扭曲,适当松解。 |
6.3 最终装配与美化
调试无误后,就可以进行最后的装配了。将面包板上的电路,用热熔胶或尼龙扎带妥善固定在箱体底部。USB电源线从后板预留的孔穿出。确保所有线缆都有一定的松弛度,不会因为机械臂的运动而被拉扯。
你可以根据自己的喜好对木盒进行打磨、上漆或涂木蜡油,让它看起来更精致。在茶漏臂的末端,可以安装一个小钩子或3D打印一个夹子,用于悬挂不同样式的茶漏或茶包。
完成所有这些,你的智能泡茶机就正式诞生了。把它放在厨房或办公桌上,享受一杯时间刚刚好的茶,这份满足感远超茶汤本身。这个项目带给你的,不仅仅是一个工具,更是一次对嵌入式系统从感知、决策到执行完整链条的深度实践。
