进阶翻斗式雨量计:Arduino 集成 + 3D 打印 + SD 记录
元器件与物料
| 元器件 | 数量 | 备注 |
|---|---|---|
| Arduino Nano R3 | 1 | 主控 |
| Tiny RTC I2C DS1307 模块 | 1 | 带纽扣电池掉电走时 |
| SD 卡模块 (LC Studio) | 1 | SPI 接口,存储逐笔翻斗事件 |
| 7-12V DC 电源适配器 | 1 | 室内显示单元供电 |
| 1602 LCD (白字蓝屏, I2C/并口均可) | 1 | 本项目用 3 线移位寄存器驱动 |
| 74HC595 移位寄存器 | 1 | 节省 Arduino 引脚驱动 LCD |
| 1kΩ 电阻 | 2 | 按钮上拉/限流 |
| 330Ω 电阻 | 2 | LCD 背光限流 |
| 100nF 电容 | 1 | 电源去耦 |
| 10kΩ 单圈电位器 | 1 | LCD 对比度调节 |
| PCB 轻触按钮 | 1 | 菜单切换 |
| 干簧管 SPST-NO | 1 | 翻斗倾斜触发,安装在室外桶体 |
| 磁铁 (7mm OD × 7mm) | 1 | 粘贴于翻斗臂,触发干簧管 |
| 5×10cm 单面万用板 | 1 | 主控板焊接 |
所需工具
- 3D 打印机 (PETG 材料)
- 电烙铁
原理与功能
专业气象站同款翻斗结构:集雨漏斗面积 16.605 in²,双斗各容约 2 ml。雨水注入一斗,重力翻转,另一斗接续承接。每次翻斗干簧管闭合一次,Arduino 外部中断计数。换算系数 0.00854 英寸/次 (可按实测标定修正)。
室内显示单元提供四档菜单:本小时/上小时/本日/昨日 累计雨量。每次翻斗在 SD 卡写入时间戳事件 (test.txt),可导入 Excel 分析制图。
制作步骤
室外桶体 3D 打印 (PETG, 30% 填充)
- 打印底座、盖体、漏斗、滤网、子座、翻斗、转轴套。滤网需关闭上下表面层形成多孔结构。
- 漏斗顶植入 24 根 2″ 镀锌铁丝防鸟栖息。

室内显示单元电路制作
- 面板板:LCD 未焊接先定位钻四个安装孔,再焊接 74HC595、按钮、电阻,预留 6″ 排线连主板。
- 主板:Arduino Nano 定位 (D12 对应 R27 孔),焊电容、电阻、预布线,再插入 SD 与 RTC 模块焊接。
- 外壳开线孔,穿入室外干簧管双线与电源线,主板滑入固定,面板螺丝锁紧。





室外翻斗组装
- 干簧管扎带固定于子座,磁铁粘贴翻斗臂端部。
- 翻斗轴用 1/8″ 黄铜管 (约 2″),孔壁打磨顺滑,外侧加垫片调整侧隙。
- 底座用 1″ 铝角码固定,子座 M3 螺丝锁底板。
- 漏斗装入滤网,盖体 M3×6 螺丝锁紧。


调试与标定
- 上传 RTC 校时程序 (串口 19200),设定当前时间。
- 上传主程序,插 SD 卡,短接干簧管引线验证计数与 SD 写入。
- 室外机安装水平,引线接室内机。
- 通电实测:缓慢注入 1 杯水 (14.44 in³),理论雨量 0.87″,对比显示值修正
conversion_factor。
核心代码
RTC 校时程序
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68
byte decToBcd(byte v){ return (v/10*16)+(v%10); }
void setDateDs1307(){
byte second=0, minute=11, hour=12, dayOfWeek=5, dayOfMonth=24, month=7, year=20;
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(decToBcd(0)); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour)); Wire.write(decToBcd(dayOfWeek)); Wire.write(decToBcd(dayOfMonth));
Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.endTransmission();
}
void setup(){ Wire.begin(); Serial.begin(19200); setDateDs1307(); }
void loop(){ delay(2000); /* 读回验证 */ }
主程序 (需安装 RTClib、LiquidCrystal_SR 等库)
/* Tipping Bucket Rain Gauge by Bob Torrence */
#include <SPI.h> #include <SD.h> #include <Wire.h> #include "RTClib.h" #include <LiquidCrystal_SR.h>
LiquidCrystal_SR lcd(6,5,9); // SER=6, SCLK=5, RCLK=9
RTC_DS3231 rtc;
int backlight=7; const byte INT_BUCKET=3, INT_MENU=2;
volatile int Bucket_Tip=0, Menu_Sel=0;
float tip_hour=0, tip_prev_hour=0, tip_day=0, tip_prev_day=0;
int cur_min, loop_min, cur_hour, loop_hour, cur_day, loop_day, tip_cnt=0;
float conv = 0.00854; // 英寸/次
unsigned long bl_off=0, bl_on=30000;
String print_time(DateTime t){
char buf[20]; sprintf(buf,"%02d:%02d:%02d %02d/%02d",t.hour(),t.minute(),t.second(),t.month(),t.day());
return String(buf);
}
File myFile;
void setup(){
lcd.begin(16,2); lcd.home(); rtc.begin();
pinMode(10,OUTPUT); pinMode(backlight,OUTPUT); digitalWrite(backlight,HIGH);
bl_off = millis()+bl_on;
if(!SD.begin(4)){ lcd.print("insert SD Card"); return; }
pinMode(INT_BUCKET,INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(INT_BUCKET),count,FALLING);
pinMode(INT_MENU,INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(INT_MENU),menu,RISING);
myFile=SD.open("test.txt",FILE_WRITE); if(myFile){ myFile.println("Rain Gauge Ready"); myFile.close(); }
DateTime now=rtc.now(); cur_min=loop_min=now.minute(); cur_hour=loop_hour=now.hour(); cur_day=loop_day=now.day();
lcd.setCursor(0,0); lcd.print(print_time(now)); lcd.setCursor(1,1); lcd.print("Rain Gauge");
}
void loop(){
DateTime now=rtc.now(); cur_min=now.minute(); loop_min=now.minute(); cur_hour=now.hour(); loop_hour=now.hour(); cur_day=now.day(); loop_day=now.day();
while(loop_day - cur_day == 0){
while(loop_hour - cur_hour == 0){
if(millis() > bl_off) digitalWrite(backlight,LOW);
if(Bucket_Tip){
Bucket_Tip=0; tip_cnt++;
now=rtc.now();
myFile=SD.open("test.txt",FILE_WRITE);
myFile.print("Event "); myFile.print(now.year()); myFile.print('/'); myFile.print(now.month()); myFile.print('/'); myFile.print(now.day());
myFile.print(' '); myFile.print(now.hour()); myFile.print(':'); myFile.print(now.minute()); myFile.print(':'); myFile.print(now.second());
myFile.print(' '); myFile.print(conv,5); myFile.println(); myFile.close(); delay(200);
}else{ now=rtc.now(); loop_hour=now.hour(); }
switch(Menu_Sel){
case 1: lcd.clear(); lcd.setCursor(0,0); lcd.print("Current Hour"); lcd.setCursor(0,1); lcd.print(tip_cnt*conv); delay(500); break;
case 2: lcd.clear(); lcd.setCursor(0,0); lcd.print("Previous Hour"); lcd.setCursor(0,1); lcd.print(tip_prev_hour); delay(500); break;
case 3: lcd.clear(); lcd.setCursor(0,0); lcd.print("Current Day"); lcd.setCursor(0,1); lcd.print(tip_day+tip_cnt*conv); delay(500); break;
case 4: lcd.clear(); lcd.setCursor(0,0); lcd.print("Previous Day"); lcd.setCursor(0,1); lcd.print(tip_prev_day); delay(500); break;
}
}
now=rtc.now(); cur_hour=now.hour(); loop_day=now.day(); loop_hour=now.hour();
tip_prev_hour = tip_cnt*conv; tip_day += tip_prev_hour; tip_cnt=0;
}
tip_prev_day = tip_day; tip_day=0; tip_prev_hour=0; tip_cnt=0;
}
void count(){ static ulong last=0; ulong now=millis(); if(now-last>300){ Bucket_Tip=1; } last=now; }
void menu(){ static ulong last=0; ulong now=millis(); if(now-last>300){ if(digitalRead(backlight)==LOW) digitalWrite(backlight,HIGH); else{ Menu_Sel++; if(Menu_Sel>4) Menu_Sel=1; } bl_off=now+bl_on; last=now; } }
3D 打印文件清单
- 室外底座、盖体、漏斗、滤网 (无上下壳)、子座、翻斗、室内外壳、面板、LCD 垫片、按钮帽
- Fusion 360 源模型 (.f3d/.f3z) 与 STEP 通用格式均提供
原理图
Fritzing 文件 rain_gauge_NtjqXF6QEw.fzz 包含完整接线:Arduino Nano、74HC595 驱动 LCD、SD 卡 SPI、DS1307 I2C、干簧管中断、菜单按钮中断、背光控制、电源输入。
制造工艺
- 工业与安全应用精密压力表
- 智能窗帘:基于Arduino与太阳能的自动光控系统
- 意大利语单词时钟:Arduino Nano + NeoPixel 144 灯珠 + LCD + RTC 打造
- 基于Arduino MKR Fox 1200构建可靠Sigfox千瓦时电表
- 蓝牙温度监测仪:Arduino Nano + NTC 热敏电阻 + HC-06 无线传输
- 数显高度计:精准测量与质量控制的专业解决方案
- 螺旋测微器(螺旋测微计)百科:原理、结构、历史与实操
- 压力表工作原理、类型选型、安装维护与故障诊断全指南
- 应变片深度解析:将机械应力精准转化为电信号的核心技术
- 皮拉尼真空计详解:工作原理、应用与优势
- 隔膜压力表详解:精准可靠的压力测量方案
- 波登管压力表详解:设计原理、功能与应用