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 主控芯片选型为什么是ESP32ESP32几乎是这个项目的“天选之子”。对比传统的Arduino UNOATmega328P或STM32ESP32的优势是全方位的双核处理我们可以将核心任务分离。例如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-FiESP32会进入配网模式自身作为一个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);将2700000027MHz降低到2000000020MHz。过高的频率在长线或干扰环境下可能导致数据错误。7.4 剂量率读数异常偏高症状计算出的μSv/h值远高于正常环境本底例如持续大于1 μSv/h。排查步骤检查转换系数首先确认代码中使用的转换系数是否正确。不同型号的盖革管系数差异很大。电磁干扰将盖革计数器模块远离电脑主机、手机充电器、路由器等强电磁干扰源。这些设备产生的电磁噪声可能被误识别为辐射脉冲。可以尝试用电池供电并移到房间角落测试。传感器附近有辐射源检查摆件周围是否有意外的辐射源如某些含放射性元素的矿石标本、老式夜光表、烟雾探测器内含镅-241等。盖革管本身问题极少数情况下盖革管可能因老化或制造缺陷而产生“自激放电”导致本底计数异常高。这通常需要更换模块来验证。制作这样一个融合了硬件、软件和工业设计的项目最大的成就感不在于最终读数有多精确而在于你将一个抽象的科学概念通过自己的双手变成了一个具体、可见、可交互的实体。它静静地立在桌角闪烁的数值是数字世界与物理世界的一次次对话。当你向朋友介绍它时你不仅是在展示一个作品更是在分享一种观察世界的独特视角。