基于ESP32与盖革计数器的桌面辐射监测摆件DIY全攻略
1. 项目缘起:从专业工具到桌面艺术
几年前,我在一个电子爱好者论坛上看到有人分享用盖革计数器模块监测环境辐射的帖子,当时就觉得这玩意儿挺酷的。盖革计数器,这个听起来有点“硬核”甚至带点科幻色彩的设备,通常出现在实验室、核电站或者探险家的背包里,用来探测看不见摸不着的电离辐射。但它的核心——盖革-米勒管(GM Tube)和配套的驱动电路——其实已经模块化、平民化了。一个念头就冒了出来:能不能把它从冷冰冰的测量仪器,变成一个既有实用监测功能,又具备科技美感的桌面摆件?就像把天气预报站、时钟摆件那样,让它融入日常环境,用一种更直观、更艺术化的方式,提醒我们关注身边无形的世界。
这个想法一直搁置着,直到ESP32这类功能强大又易用的物联网开发板普及开来。ESP32不仅提供了丰富的GPIO、ADC和网络功能,其双核处理器和低功耗特性,更是为实时数据采集、处理和显示提供了完美的平台。它让复杂的信号处理、网络通信和用户交互变得简单。于是,“利用盖革计数器模块自制一款桌面辐射探测摆件”这个项目就清晰了:核心是利用盖革计数器模块作为传感器,ESP32作为大脑进行数据处理和系统控制,再结合一个设计过的外壳与显示单元,最终呈现为一个持续工作、数据可视、甚至能联网报警的桌面艺术品。
它解决的不仅仅是“有没有辐射”的简单问题,而是将一种专业的、略带距离感的监测行为,转化为一种持续的、温和的、可视化的环境感知体验。适合谁来玩呢?首先是电子DIY爱好者,特别是对物联网、传感器融合感兴趣的朋友;其次是创客和科技艺术从业者,可以将其作为交互装置的原型;甚至是对生活科技有好奇心的普通人,也能通过这个项目,亲手触摸到物理世界与数字世界的交界处。
2. 核心设计思路与方案选型
做一个辐射探测摆件,听起来简单,但拆开来看,需要统筹考虑传感器、主控、供电、显示、外壳和软件逻辑等多个环节。我的设计目标是:稳定、直观、美观、可扩展。稳定是基础,毕竟涉及辐射测量,数据可信度是第一位的;直观要求显示界面一目了然;美观决定了它能否真正成为“摆件”;可扩展则为未来添加比如历史数据记录、云端同步、多传感器融合等功能留出空间。
2.1 传感器选型:盖革计数器模块详解
市面上常见的盖革计数器模块主要有两种接口:一种是直接输出脉冲信号(TTL电平),另一种是模拟电压输出。对于DIY项目,强烈推荐脉冲输出型。原因很简单:辐射粒子进入盖革管引起一次放电,就产生一个电脉冲。这种“数脉冲”的方式是最直接、最准确的测量方法,其计数率(Counts Per Minute, CPM)与辐射强度成正比。模拟电压输出通常是模块内部已经做了积分处理,虽然接线简单,但损失了原始脉冲信息,灵活性和准确性稍逊。
我选用的是常见的J305βγ型盖革管模块。它探测的是β和γ射线,对日常环境中的天然本底辐射(主要来自宇宙射线和土壤中的微量放射性物质)有足够的灵敏度。模块通常有3-5根线:VCC(供电,一般是400V左右的高压,由模块自带的升压电路产生)、GND、以及信号输出线。信号线在无事件时为高电平,每当探测到一次辐射事件,就会产生一个低电平脉冲(持续时间约几十到几百微秒)。ESP32的任务就是精确地捕获这些脉冲。
注意:安全第一。虽然模块工作电压高,但电流极小,属于“高电压、低电流”情况,正常操作没有触电风险。但切忌用万用表直接测量高压输出点,以免损坏仪表或模块。处理模块时,避免触碰盖革管本身的金属网(通常是接地的),防止静电击穿。
2.2 主控芯片选型:为什么是ESP32?
ESP32几乎是这个项目的“天选之子”。对比传统的Arduino UNO(ATmega328P)或STM32,ESP32的优势是全方位的:
- 双核处理:我们可以将核心任务分离。例如,Core 0专门用于高速、精确的脉冲计数(这是一个需要实时响应的任务),Core 1则负责管理显示刷新、网络通信、用户按键交互等,互不干扰,系统响应更流畅。
- 丰富的接口与内存:足够的GPIO、ADC、DAC、SPI、I2C、UART等,轻松驱动各种显示屏(SPI/I2C接口的OLED、TFT)和其他传感器(如温湿度传感器用于数据补偿)。较大的SRAM和Flash空间,可以存储更复杂的程序、网页界面或历史数据。
- 内置Wi-Fi与蓝牙:这是实现“智能摆件”的关键。通过Wi-Fi,我们可以将实时数据上传到私有服务器或开源物联网平台(如Home Assistant、ThingsBoard),实现远程查看、历史曲线绘制和阈值报警。蓝牙则可以用于近距离的手机APP配置。
- 低功耗模式:虽然作为桌面摆件常供电,但ESP32支持深度睡眠,如果未来想做成电池供电的便携版本,也有很好的基础。
- 成熟的生态:无论是官方的ESP-IDF框架,还是基于Arduino Core for ESP32的库,都有海量的资源和社区支持,开发效率极高。
因此,选择ESP32,不是随大流,而是基于项目对实时性、连接性和扩展性的综合需求做出的最优解。
2.3 显示与交互方案
作为桌面摆件,显示部分是门面。我放弃了简单的数码管,选择了1.3英寸的SPI接口IPS TFT液晶屏。理由如下:色彩丰富,可视角度广,能显示更生动的信息(如数值、单位、动态图标、历史趋势迷你图);SPI接口占用引脚少,刷新速度快;尺寸适中,适合桌面摆放。
交互方面,为了保持外观简洁,我只设计了两个实体按键:一个用于切换显示模式(如CPM、μSv/h、历史图表),另一个用于手动触发Wi-Fi配网或重置。复杂的配置(如连接Wi-Fi、设置报警阈值)计划通过蓝牙或Wi-Fi Web服务器(在ESP32上内置一个配置页面)来完成,这样就不用在外壳上开很多孔,外观更完整。
2.4 供电与外壳设计
供电采用标准的5V USB接口,这是最通用的方案。内部使用一枚AMS1117-3.3V线性稳压芯片为ESP32和TFT屏的逻辑部分提供3.3V电源。盖革计数器模块的高压部分通常由模块自身的电路从输入的3.3V或5V升压产生,需查阅具体模块手册。
外壳设计是“摆件感”的灵魂。我使用Fusion 360进行3D建模,然后3D打印制作。设计时考虑了以下几点:
- 结构稳固:内部有明确的PCB(或洞洞板)安装柱,以及屏幕、按键的固定卡槽。
- 散热:在ESP32芯片和稳压芯片对应的外壳位置设计隐蔽的通风孔。
- 美学:采用圆角矩形设计,表面处理(打印后打磨、喷漆)追求类似消费电子产品的质感。前面板为屏幕和按键开孔,背面预留USB孔和复位孔。
- 传感器开窗:为了让盖革管能有效探测辐射,需要在正对管体的外壳部位开一个窗口。这里不能用金属材料遮挡,我使用了一小片亚克力板,既能透射β和γ射线,又能保护内部的盖革管。
3. 硬件电路设计与连接要点
整个系统的硬件连接并不复杂,但有几个关键点需要特别注意,否则会影响计数准确性或系统稳定性。
3.1 核心电路连接图(逻辑示意)
[5V USB输入] -> [AMS1117-3.3V] -> [3.3V系统电源轨] | +----> [ESP32 3.3V Vin] +----> [TFT屏 VCC] +----> [盖革模块 VCC (通常为3.3V或5V,依模块而定)] | [盖革模块 Signal] -------------------> [ESP32 GPIO4 (配置为输入,带内部上拉)] | [ESP32 GPIO18] ----------------------> [TFT屏 SCK] [ESP32 GPIO23] ----------------------> [TFT屏 MOSI] [ESP32 GPIO5] -----------------------> [TFT屏 DC] [ESP32 GPIO4] -----------------------> [TFT屏 CS] (注意:此GPIO4与脉冲输入引脚冲突,需另选) [ESP32 GPIO2] -----------------------> [TFT屏 RST] | [按键1] -----------------------------> [ESP32 GPIO32] [按键2] -----------------------------> [ESP32 GPIO33]3.2 脉冲信号采集的硬件要点
盖革模块输出的脉冲信号,是整机数据准确性的源头。这里有两个硬件上的关键处理:
- 信号整形与去抖:理论上,盖革管的脉冲很干净。但实际环境中,尤其是用面包板或飞线连接时,可能会引入一些毛刺。虽然ESP32的中断处理程序可以设置去抖时间,但在硬件上增加一个简单的RC低通滤波(例如,一个1kΩ电阻串联在信号线上,对地接一个100pF电容)会更加稳健。这可以滤除高频噪声,避免误计数。
- 电平匹配与保护:确保盖革模块的输出电平与ESP32的GPIO输入电平兼容。大部分模块输出的是3.3V TTL电平,可以直接连接。如果不确定,最好用示波器看一下,或者在信号线上串联一个330Ω的限流电阻作为保护。绝对不要将高于3.6V的信号直接接入ESP32的GPIO,会损坏芯片。
- 供电隔离:盖革模块内部的高压电路在工作时可能会产生轻微的电源噪声。如果条件允许,可以给盖革模块的电源输入端加一个磁珠或π型滤波电路。更简单的办法是,使用一个独立的LDO(如MIC5205)从5V降压到3.3V单独给盖革模块供电,与数字系统的电源做一定隔离。
3.3 PCB布局与电源完整性
如果最终决定制作PCB,而不是使用洞洞板,那么布局就很重要:
- 模拟与数字分区:将盖革模块及其滤波电路视为“模拟前端”,尽量远离ESP32的晶振、开关电源电路等高速数字噪声源。
- 电源走线:3.3V电源走线要尽量宽,并在ESP32和TFT屏的电源引脚附近放置足够容量(如10μF)的电解电容和多个0.1μF的陶瓷去耦电容,确保电源稳定,尤其在屏幕刷新瞬间电流较大时。
- 信号线:脉冲信号线尽量短,并远离时钟线和高速数据线(如SPI的SCK),以减少耦合干扰。
4. 软件固件开发:从脉冲到可视信息
软件是项目的灵魂,负责将原始的脉冲信号转化为有意义的辐射剂量信息,并驱动显示和网络功能。我选择使用Arduino Core for ESP32框架进行开发,因为它对新手友好,库生态丰富,足以满足本项目需求。
4.1 脉冲计数:中断与滤波算法
核心任务是准确计数。最可靠的方法是使用硬件中断。ESP32的每个GPIO都支持中断,我们将脉冲信号线连接的GPIO(例如GPIO4)配置为FALLING边缘触发中断,因为大部分模块是低电平有效脉冲。
const int geigerPin = 4; // 盖革脉冲信号引脚 volatile unsigned long count = 0; // 计数变量,必须用volatile修饰 portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; // 用于多核/中断安全的互斥锁 void IRAM_ATTR geigerPulse() { // 此中断服务程序(ISR)必须简短快速,且放在IRAM中运行 portENTER_CRITICAL_ISR(&mux); count++; portEXIT_CRITICAL_ISR(&mux); } void setup() { pinMode(geigerPin, INPUT_PULLUP); // 启用内部上拉,确保无脉冲时为高电平 attachInterrupt(digitalPinToInterrupt(geigerPin), geigerPulse, FALLING); // ... 其他初始化代码 }但是,直接这样计数会有问题。机械振动、电源噪声都可能造成误触发。因此必须加入软件去抖。一种有效的方法是在中断服务程序中不直接计数,而是记录下事件发生的时间戳,在主循环中判断时间间隔。
volatile unsigned long lastPulseTime = 0; const unsigned long DEBOUNCE_TIME = 200; // 去抖时间,单位微秒(μs),根据脉冲宽度调整 void IRAM_ATTR geigerPulse() { unsigned long now = micros(); portENTER_CRITICAL_ISR(&mux); if ((now - lastPulseTime) > DEBOUNCE_TIME) { count++; lastPulseTime = now; } portEXIT_CRITICAL_ISR(&mux); }这样,只有在两次脉冲间隔大于200微秒时,才被认为是有效事件,可以有效滤除窄毛刺。
4.2 剂量率计算:从CPM到μSv/h
盖革计数器测量的是计数率(CPM)。要转换成更通用的辐射剂量率单位微西弗每小时(μSv/h),需要一个转换系数(CF)。公式很简单:剂量率 (μSv/h) = CPM / CF。
这个系数CF因盖革管型号而异,通常需要校准。对于J305βγ管,一个常见的参考系数在0.0065到0.0081 μSv/h per CPM之间。这意味着,如果本底辐射大约是20 CPM,那么对应的剂量率大约是 20 * 0.007 ≈ 0.14 μSv/h。这是一个非常安全的水平(作为参考,乘坐一次跨洋航班受到的辐射剂量大约在30-50 μSv)。
在代码中,我们每隔一定时间(比如60秒)计算一次平均CPM,然后进行转换:
unsigned long lastCalcTime = 0; const unsigned long CALC_INTERVAL = 60000; // 计算间隔,60秒 float conversionFactor = 0.0073; // 假设的转换系数,需要根据实际校准调整 float doseRate_uSv_h = 0.0; void loop() { unsigned long now = millis(); if (now - lastCalcTime >= CALC_INTERVAL) { portENTER_CRITICAL(&mux); // 进入临界区,安全地读取count unsigned long counts = count; count = 0; // 重置计数器 portEXIT_CRITICAL(&mux); float cpm = (counts / (CALC_INTERVAL / 60000.0)); // 计算CPM doseRate_uSv_h = cpm * conversionFactor; lastCalcTime = now; // 更新显示和网络上传... } // ... 处理其他任务 }4.3 多任务处理与显示驱动
为了不阻塞脉冲计数和实现流畅的UI,我们需要利用ESP32的双核和FreeRTOS任务。一个典型的任务划分如下:
- 任务一(运行在Core 0,高优先级):主要负责脉冲计数中断的管理、剂量率的定时计算。这个任务大部分时间在休眠,等待计算间隔到达。
- 任务二(运行在Core 1,中优先级):负责TFT屏幕的刷新。使用TFT_eSPI这样的库,以1-2Hz的频率刷新屏幕,显示当前的CPM、μSv/h值,以及一个模拟仪表盘或历史趋势小图。
- 任务三(运行在Core 1,低优先级):负责Wi-Fi连接和MQTT/HTTP数据上传。每计算出一个新的剂量率,就通过MQTT发布到一个主题(如
home/geiger/doserate),或者通过HTTP POST到自定义的API。
使用xTaskCreatePinnedToCore函数可以创建绑定到特定核心的任务。关键是要处理好任务间的通信和数据共享。对于count、doseRate_uSv_h这类共享变量,必须使用互斥锁(Mutex)或临界区进行保护,防止数据错乱。
4.4 网络功能与数据上云
网络功能让摆件从“本地显示器”升级为“物联网节点”。我选择MQTT协议进行数据上传,因为它轻量、高效,非常适合传感器数据流。
- Wi-Fi连接与智能配网:首次启动时,如果无法连接已知Wi-Fi,ESP32会进入配网模式,自身作为一个AP(访问点),手机连接后可以打开一个网页配置Wi-Fi的SSID和密码。可以使用库如
WiFiManager来轻松实现此功能。 - MQTT客户端:使用
PubSubClient库连接一个MQTT代理服务器(可以是本地搭建的Mosquitto,也可以是云服务如EMQX Cloud)。定时发布JSON格式的数据:{"cpm": 25.6, "usv_h": 0.187, "timestamp": 1646123456}。 - 数据可视化:在服务器端,数据可以被订阅并存入数据库(如InfluxDB),然后通过Grafana绘制出精美的实时曲线和历史图表。你也可以写一个简单的Python Flask程序,自己做一个数据显示网页。
这样,你不仅能在桌面上看到实时数据,在办公室或外出时,也能随时打开手机APP或网页,查看家里的辐射水平是否正常。
5. 校准、测试与性能优化
一个测量设备,校准是保证其读数有意义的根本。对于盖革计数器,我们无法获得一个精确的放射源,但可以利用环境本底辐射进行相对校准。
5.1 利用环境本底进行相对校准
环境本底辐射在全球范围内是相对稳定的,通常在0.08 ~ 0.15 μSv/h之间(室内)。我们可以:
- 长时间测量:将制作好的摆件放在室内远离明显辐射源(如花岗岩、某些含铀的旧瓷器)的地方,连续运行24-48小时。
- 记录平均CPM:通过串口或网络日志,记录下这段时间内的平均CPM值。假设测得平均CPM为22。
- 反推转换系数:取一个公认的本底辐射中值,例如0.12 μSv/h。那么转换系数 CF = CPM / 剂量率 = 22 / 0.12 ≈ 183.33 CPM per μSv/h,或者换算成之前的形式:0.00545 μSv/h per CPM (即 1/183.33)。
- 更新代码:将这个计算出的系数替换掉代码中假设的系数。
虽然这不是绝对精确的校准,但能确保你的设备读数处在一个合理的、可理解的范围内。如果你想更精确,可以购买一个经过校准的商用盖革计数器作为参考,进行对比测量。
5.2 性能测试与噪声排查
组装完成后,需要进行系统测试:
- 静态计数测试:用铅盒或远离辐射源的环境,观察长时间(如10分钟)内的计数是否偶尔有且稳定在极低值(可能不是0,因为宇宙射线无法屏蔽)。这可以测试电路本身的噪声水平。
- 动态测试:可以使用一个微弱的放射源进行测试(注意:操作任何放射源都必须遵守当地法律法规,并采取充分的安全防护措施。对于普通爱好者,强烈不建议自行购买或处理放射源!)。一个合法且安全的替代方法是使用老式含钍的煤气灯罩丝或某些含铀的旧陶瓷釉(同样需谨慎,并了解其放射性很弱),在距离传感器一定距离外缓慢移动,观察计数率是否有显著变化。
- 电源噪声测试:在ESP32全速运行、屏幕刷新时,用示波器探头测量盖革模块的电源线和信号线,观察是否有明显的毛刺或电压跌落。如有,加强电源滤波。
5.3 软件层面的优化技巧
- 中断优化:中断服务程序(ISR)一定要短小。除了简单的增加计数和时间戳记录,不要在里面做浮点运算、调用复杂函数或进行串口打印。
- 任务优先级管理:确保脉冲计数相关任务的优先级高于显示和网络任务,防止因UI刷新阻塞导致脉冲丢失。
- 看门狗定时器:启用硬件看门狗(WDT),防止程序跑飞导致设备死机。在
loop()函数或主要任务循环中定期喂狗。 - 非易失存储:使用
Preferences库将Wi-Fi配置、校准系数等关键参数保存到ESP32的NVS(非易失性存储)中,掉电不丢失。
6. 外壳制作与总装艺术
硬件和软件调试完毕后,最后一步是赋予它“摆件”的形态。
- 3D打印与后处理:使用PLA材料打印外壳。打印完成后,进行支撑拆除、打磨(从粗到细的砂纸),然后用补土填补层纹,再次打磨至光滑。最后喷涂底漆和面漆(如哑光黑或科技白),质感立刻提升。
- 内部布局与走线:将ESP32开发板、TFT屏、盖革模块固定在壳体内设计好的位置。连接线尽量使用排线或硅胶线,并用电工胶带或扎带固定整齐,避免松动和短路。盖革管要正对外壳的开窗。
- 屏幕与按键安装:TFT屏通常通过排针焊接在PCB或转接板上,然后卡进外壳的屏幕槽。在屏幕与外壳之间可以加一层薄海绵垫,既能缓冲又能防尘。按键可以使用贴片微动开关,配合3D打印的按钮帽。
- 最终测试与密封:总装完成后,通电进行最后的功能测试。一切正常后,可以用少量螺丝或卡扣固定底盖。如果追求极致,可以在接缝处贴上装饰性的防尘条。
7. 常见问题与排查实录
在实际制作过程中,我踩过不少坑,这里总结一下最常见的问题和解决方法。
7.1 脉冲计数不准或完全无计数
这是最可能遇到的问题。
- 症状:串口输出的CPM始终为0,或者数值明显低于/高于预期。
- 排查步骤:
- 检查硬件连接:首先用万用表确认盖革模块供电正常(VCC电压是否正确)。然后,用示波器是最直接的:将探头接在信号引脚和地之间,你应该能看到一个清晰的、周期不定的负脉冲(下降沿)。如果没有脉冲,可能是盖革管损坏或高压电路故障。
- 检查软件配置:确认代码中中断引脚编号与实际连接一致。确认中断触发模式(
FALLING)正确。尝试在中断服务程序里翻转一个LED灯(如果有多余GPIO),看是否有反应,以验证中断是否被触发。 - 去抖时间设置:如果去抖时间(
DEBOUNCE_TIME)设置得过长(比如大于实际脉冲宽度),可能会滤掉所有真实脉冲。尝试逐步减小这个值,比如从1000μs调到100μs试试。 - 电源噪声干扰:如果计数偶尔有但非常不稳定,可能是电源噪声导致误触发。尝试用电池单独给盖革模块供电,看是否改善。或者在模块电源入口处并联一个大电容(如100μF电解电容)。
7.2 Wi-Fi连接不稳定或经常断开
- 症状:设备频繁重启,或者MQTT经常断开重连。
- 排查步骤:
- 电源问题:这是最常见的原因。ESP32在Wi-Fi发射时峰值电流可达几百mA,劣质USB线或电源适配器会导致电压跌落,引发复位。确保使用高质量的5V 2A以上的电源和较粗的USB线。
- 信号强度:通过串口打印Wi-Fi的RSSI(信号强度)。如果低于-70dBm,连接就会不稳定。考虑调整摆件位置或使用Wi-Fi中继器。
- 软件看门狗:复杂的任务或网络操作可能阻塞主循环太久,导致看门狗超时复位。优化代码逻辑,将耗时操作(如文件读写)放入单独的低优先级任务,或使用
yield()、delay()让出控制权。 - 路由器设置:有些路由器的“节能模式”或过于激进的无线设置可能导致兼容性问题。尝试关闭路由器的WMM、Short GI等功能,或为ESP32设置静态IP。
7.3 TFT屏幕显示花屏、闪烁或不亮
- 症状:屏幕显示乱码、部分区域不刷新、或者背光亮但无内容。
- 排查步骤:
- 接线错误:SPI接口的SCK、MOSI、DC、CS、RST这几根线,务必对照屏幕驱动芯片(如ST7789)的数据手册和TFT_eSPI库的用户配置,一根一根检查。接错一根就可能导致异常。
- 电源与地线:确保屏幕的VCC和GND连接牢固,且电压是稳定的3.3V。屏幕背光可能需要单独的供电(有些屏幕背光需要接3.3V,有些需要接5V,务必查清)。
- 库配置错误:
TFT_eSPI库需要用户手动修改一个配置文件(User_Setup.h),来定义你使用的屏幕型号、驱动芯片、分辨率、引脚连接等。这里配置错误是导致显示问题的首要原因。务必仔细核对。 - SPI频率过高:尝试在初始化代码中降低SPI时钟频率,比如
tft.init(240, 240, SPI_MODE0, 27000000);将27000000(27MHz)降低到20000000(20MHz)。过高的频率在长线或干扰环境下可能导致数据错误。
7.4 剂量率读数异常偏高
- 症状:计算出的μSv/h值远高于正常环境本底(例如,持续大于1 μSv/h)。
- 排查步骤:
- 检查转换系数:首先确认代码中使用的转换系数是否正确。不同型号的盖革管系数差异很大。
- 电磁干扰:将盖革计数器模块远离电脑主机、手机充电器、路由器等强电磁干扰源。这些设备产生的电磁噪声可能被误识别为辐射脉冲。可以尝试用电池供电,并移到房间角落测试。
- 传感器附近有辐射源:检查摆件周围是否有意外的辐射源,如某些含放射性元素的矿石标本、老式夜光表、烟雾探测器(内含镅-241)等。
- 盖革管本身问题:极少数情况下,盖革管可能因老化或制造缺陷而产生“自激放电”,导致本底计数异常高。这通常需要更换模块来验证。
制作这样一个融合了硬件、软件和工业设计的项目,最大的成就感不在于最终读数有多精确,而在于你将一个抽象的科学概念,通过自己的双手,变成了一个具体、可见、可交互的实体。它静静地立在桌角,闪烁的数值是数字世界与物理世界的一次次对话。当你向朋友介绍它时,你不仅是在展示一个作品,更是在分享一种观察世界的独特视角。