1. 项目概述与核心价值最近在捣鼓一个挺实用的小玩意儿一个放在房间里的温湿度监测仪。起因很简单我住的地方夏天温度变化挺大有时候在屋里待着明明觉得闷热一看空调遥控器上的温度显示又觉得“还行”但体感就是不舒服。后来琢磨了一下发现湿度对体感温度的影响非常大光知道温度是不够的。于是就想能不能自己做一个既能看温度又能看湿度的小设备实时了解一下房间的“气候”状况。这个想法听起来简单但背后涉及的技术点其实挺有意思的。它本质上是一个典型的嵌入式数据采集与显示系统核心流程是传感器感知物理世界温湿度→ 微控制器读取并处理数据 → 显示屏将数据可视化。我选择了Arduino Nano作为大脑AHT10作为感知器官SSD1306 OLED作为输出窗口。这套组合拳打下来成本不高但精度和实用性都足够。对于想入门嵌入式开发、物联网或者环境监测的朋友来说这是一个绝佳的练手项目。它能让你一次性接触到I2C通信、传感器驱动、OLED显示控制这几个关键技能点而且最终成果是一个看得见摸得着的实用工具成就感直接拉满。2. 核心硬件选型与设计思路2.1 为什么是Arduino Nano AHT10 SSD1306做项目选型是第一步也是最考验经验的一步。为什么是这三件套我来拆开讲讲我的考量。首先看主控Arduino Nano。在众多Arduino板子里Nano以小巧的尺寸和完整的ATmega328P核心功能脱颖而出。它拥有足够的GPIO、模拟输入和PWM输出对于这个只需要处理I2C通信和驱动显示的项目来说绰绰有余。更重要的是它的开发环境Arduino IDE生态极其成熟库资源丰富能极大降低开发门槛。相比于更基础的UnoNano更省空间相比于更强大的ESP32Nano在简单数据采集任务上功耗更低且没有Wi-Fi/蓝牙带来的复杂度让项目焦点更纯粹。其次是传感器AHT10。市面上温湿度传感器很多像DHT11/DHT22、SHT30等。选择AHT10主要看中三点一是精度其温度精度±0.3°C湿度精度±2% RH对于室内环境监测完全够用甚至有些“性能过剩”二是通信接口它采用标准的I2C接口只需要两根线SDA, SCL就能完成通信比DHT系列的单总线协议在代码编写和稳定性上更友好三是它的工作电压范围宽1.6V-6V这意味着它既能配合5V的Arduino Nano也能兼容未来可能使用的3.3V低功耗MCU如SAMD21为项目升级留足了空间。最后是显示屏SSD1306 OLED。选择它而不是LCD屏原因很直接好看、省电、接口简单。OLED是自发光显示黑色时像素点不工作对比度高在暗环境下观看体验极佳而且功耗比需要背光的LCD低得多。SSD1306同样采用I2C接口这意味着它可以和AHT10共用同一组I2C总线极大简化了硬件连接。128x64的分辨率足以清晰显示温度、湿度数值和一些简单的图标或单位。这套组合的核心设计思路就是“标准化与简化”。全部采用I2C设备使得硬件连线从可能的十几根减少到4根VCC, GND, SDA, SCL布线清晰出错率低。软件上三大组件都有非常成熟的Arduino库支持我们不需要从零编写底层驱动可以把精力集中在应用逻辑和数据处理上。2.2 物料清单与采购建议一份清晰的物料清单是项目成功的一半。以下是构建这个原型系统所需的所有硬件主控模块Arduino Nano开发板 x1传感模块AHT10数字温湿度传感器模块 x1显示模块0.96英寸 I2C接口 SSD1306 OLED显示屏 x1辅助工具面包板 x1用于快速搭建原型连接线材公对公杜邦线若干建议准备10根左右供电设备5V USB电源适配器或移动电源 x1关于采购这里有个小经验。像Arduino Nano和AHT10这类通用模块市面上版本众多质量参差不齐。我个人的习惯是对于核心控制器和传感器尽量选择口碑好的店铺或平台哪怕价格稍贵一点。这次我用到的Nano和AHT10就是从专业的PCB制造服务商那里获得的这类平台提供的元器件通常经过筛选品质和兼容性更有保障。对于初学者如果不想在淘宝上大海捞针也可以关注一些开源硬件商城它们提供的套件通常兼容性已经过测试。注意购买SSD1306 OLED时请务必确认是I2C接口版本。还有一种SPI接口的版本引脚定义和驱动方式完全不同买错了就无法使用本文的接线图和代码。3. 硬件连接与电路搭建详解硬件连接是让想法变成实体的第一步。这个项目的接线之所以简单核心秘诀就在于I2C总线共享。3.1 I2C总线原理与共享机制I2CInter-Integrated Circuit是一种同步、多主从、串行通信总线。它只需要两根线SDASerial Data Line数据线用于双向数据传输。SCLSerial Clock Line时钟线由主设备这里是Arduino产生用于同步数据。每个连接到I2C总线上的设备都有一个唯一的7位地址。主设备通过发送地址来选中需要通信的从设备。在这个项目中Arduino Nano是主设备AHT10和SSD1306都是从设备。幸运的是这两个设备的默认I2C地址通常不同AHT10常见地址为0x38SSD1306常见地址为0x3C因此它们可以和谐地挂载在同一组SDA和SCL线上互不干扰。这就实现了“一线多用”。3.2 分步接线指南与原理图解读下面我们开始动手连接。请对照以下步骤在面包板上完成所有接线供电先行将面包板两侧的电源轨连接好通常红色为正极蓝色或黑色为负极。然后用杜邦线将Arduino Nano的5V引脚连接到面包板的正极电源轨将GND引脚连接到面包板的负极电源轨。这样我们就建立了一个稳定的5V电源网络。连接AHT10传感器VCC- 面包板正极电源轨5VGND- 面包板负极电源轨GNDSDA- Arduino Nano的A4引脚这是Nano上作为I2C数据线的模拟引脚SCL- Arduino Nano的A5引脚这是Nano上作为I2C时钟线的模拟引脚连接SSD1306 OLED显示屏VCC- 面包板正极电源轨5VGND- 面包板负极电源轨GNDSDA-与AHT10的SDA线并联共同连接到Arduino Nano的A4引脚。SCL-与AHT10的SCL线并联共同连接到Arduino Nano的A5引脚。最终检查此时你的接线应该呈现出一种“星型”拓扑Arduino Nano的5V和GND像树干一样延伸到电源轨而AHT10和SSD1306则像树枝一样从电源轨获取电力同时它们的SDA和SCL线又分别汇聚到Nano的A4和A5引脚。实操心得在面包板上进行多设备并联时最容易出错的地方是接触不良。建议使用质量较好的杜邦线并确保每个插脚都牢固地插入面包板孔中。接线完成后可以轻轻晃动一下面包板观察OLED屏幕是否出现闪烁或复位以此初步判断电源和信号连接是否稳定。4. 软件开发环境配置与库安装硬件准备就绪接下来就是让大脑Arduino运转起来的软件部分。4.1 Arduino IDE基础设置首先确保你已安装最新版的Arduino IDE。打开IDE后我们需要进行两步关键设置选择开发板在工具-开发板菜单中选择Arduino Nano。选择处理器继续在工具-处理器菜单中根据你手头Nano的版本选择最常见的是ATmega328P旧Bootloader或ATmega328P。如果不确定可以逐个尝试直到能成功上传代码。选择端口用USB线将Nano连接到电脑在工具-端口菜单中选择新出现的串口在Windows上通常是COMx在Mac/Linux上是/dev/cu.usbmodemxxx。4.2 核心库的安装与说明这个项目依赖于三个第三方库它们封装了与AHT10和SSD1306通信的复杂细节。AHTxx库用于驱动AHT10传感器。在Arduino IDE中点击项目-加载库-管理库...打开库管理器。在搜索框中输入“AHTxx”找到由“Thinary”或类似作者维护的库进行安装。这个库提供了简洁的API来读取温湿度数据。Adafruit SSD1306库与Adafruit GFX库这两个是驱动OLED显示的核心。同样在库管理器中搜索“Adafruit SSD1306”进行安装。在安装过程中IDE通常会提示“此库依赖于Adafruit GFX Library”选择“安装所有”即可。Adafruit GFX库是一个强大的图形底层库SSD1306库则在其基础上实现了针对这块屏幕的具体驱动。注意事项安装库时务必注意库的兼容性和示例代码。安装完成后可以通过文件-示例菜单找到对应库的示例程序这是学习和调试的宝贵资源。例如运行一下Adafruit SSD1306库中的示例可以快速验证你的OLED屏幕是否接线正确、能否正常点亮。5. 代码逐行解析与编程逻辑代码是项目的灵魂。下面我将提供的代码进行拆解、优化并加入详细注释让你不仅知道怎么写更明白为什么这么写。5.1 库引入与全局定义#include Wire.h // Arduino内置的I2C通信库 #include AHTxx.h // AHT10传感器驱动库 #include Adafruit_SSD1306.h // SSD1306 OLED驱动库 #include Adafruit_GFX.h // Adafruit图形库SSD1306依赖它 // 定义OLED屏幕的尺寸像素 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 // 定义OLED屏幕的I2C地址最常见的地址是0x3C #define OLED_ADDR 0x3C // 创建SSD1306显示对象参数为宽度、高度、I2C地址后两个参数通常省略 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT); // 用于存储从AHT10读取到的温湿度值浮点数 float sensorValue; // 创建AHT10传感器对象 // 参数1: 传感器I2C地址AHT10常见地址为0x38 // 参数2: 传感器类型AHT10对应AHT1x_SENSOR AHTxx ahtSensor(AHTXX_ADDRESS_X38, AHT1x_SENSOR);关键点解析Wire.h是核心没有它Arduino就无法通过I2C协议与传感器和屏幕“对话”。定义屏幕尺寸和地址是为了让驱动库知道它在操作一个什么样的硬件。创建全局对象 (display,ahtSensor) 是面向对象编程的常见做法方便在setup()和loop()函数中调用。5.2 初始化函数setup()setup()函数只在设备上电或复位后运行一次用于初始化各种设置。void setup() { // 初始化串口通信设置波特率为115200用于调试输出 Serial.begin(115200); Serial.println(F(System Initializing...)); // F()宏将字符串存储在Flash中节省RAM // 初始化OLED显示屏 // SSD1306_SWITCHCAPVCC 表示使用芯片内部电荷泵生成显示所需的高电压 if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { Serial.println(F(SSD1306 allocation failed!)); for(;;); // 如果初始化失败程序将卡死在这里这是一个简单的错误处理 } Serial.println(F(OLED Display OK)); display.clearDisplay(); // 清空屏幕 display.display(); // 将清空操作更新到屏幕Adafruit库需要显式调用display()才能生效 // 初始化AHT10传感器 // begin()函数会尝试与传感器通信并加载校准系数 while (!ahtSensor.begin()) { Serial.println(F(AHT10 not found or calibration failed. Check wiring!)); delay(2000); // 等待2秒后重试避免刷屏 } Serial.println(F(AHT10 Sensor OK)); // 可选提高I2C通信速度默认100kHz可提升至400kHz // Wire.setClock(400000); // 注意提高速度可能增加通信错误风险如果出现数据读取不稳定请注释掉此行。 }编程逻辑与技巧错误处理对display.begin()和ahtSensor.begin()的返回值进行判断是良好的编程习惯。它能帮助你在硬件连接错误时快速定位问题而不是面对一个毫无反应的设备干着急。F()宏在串口打印提示信息时使用F()宏可以将这些字符串常量存储在Arduino的Flash程序存储区而非RAM中。对于内存紧张的ATmega328P只有2KB RAM来说这是一个重要的优化技巧。I2C速度Wire.setClock(400000)将I2C总线速度从默认的100kHz提升到400kHz可以加快数据读取速度。但高速通信对线路质量线长、干扰要求更高如果出现数据偶尔出错首先应该尝试注释掉这行代码恢复为标准速度。5.3 主循环函数loop()与数据显示逻辑loop()函数会周而复始地运行我们的主要逻辑就在这里。void loop() { // 第一部分读取并显示温度 sensorValue ahtSensor.readTemperature(); // 读取温度单位摄氏度 // 准备在OLED上显示温度 display.clearDisplay(); // 清除上一帧画面 display.setTextSize(2); // 设置字体大小为2较大清晰 display.setTextColor(SSD1306_WHITE); // 设置字体颜色为白色OLED单色 display.setCursor(0, 0); // 设置光标起始位置为(0, 0)即左上角 display.print(F(Temp: )); // 打印标签 display.setCursor(0, 25); // 将光标移动到第二行起始位置 display.setTextSize(3); // 调大数值的字体 // 判断读取是否成功 if (sensorValue ! AHTXX_ERROR) { // AHTXX_ERROR 通常定义为255 display.print(sensorValue, 1); // 显示温度值保留1位小数 display.setTextSize(2); display.print(F( C)); // 显示单位 Serial.print(F(Temperature: )); Serial.print(sensorValue, 1); Serial.println(F( C)); } else { // 读取失败显示错误信息 display.print(F(Error)); Serial.println(F(Failed to read temperature!)); printSensorStatus(); // 调用自定义函数打印详细错误状态 } display.display(); // 将缓冲区内容一次性刷新到OLED屏幕 delay(1500); // 保持温度显示1.5秒 // 第二部分读取并显示湿度 sensorValue ahtSensor.readHumidity(); // 读取湿度单位百分比RH // 准备在OLED上显示湿度 display.clearDisplay(); display.setTextSize(2); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); display.print(F(Humid: )); display.setCursor(0, 25); display.setTextSize(3); if (sensorValue ! AHTXX_ERROR) { display.print(sensorValue, 1); // 显示湿度值保留1位小数 display.setTextSize(2); display.print(F( %)); Serial.print(F(Humidity: )); Serial.print(sensorValue, 1); Serial.println(F( %)); } else { display.print(F(Error)); Serial.println(F(Failed to read humidity!)); printSensorStatus(); } display.display(); delay(1500); // 保持湿度显示1.5秒 // 建议两次完整测量之间增加一个较长的间隔 // AHT10数据手册建议测量频率不要高于每秒一次以防传感器自热影响精度 // delay(8000); // 可以在此处增加一个总间隔使循环周期约10秒 }逻辑优化与深度解析交替显示代码采用了温度、湿度交替显示的模式。这样做的好处是在小小的0.96英寸屏幕上可以以更大的字体显示单个数据提高可读性。如果你想同时显示需要将字体调小并精心排版。错误处理机制ahtSensor.readTemperature()和readHumidity()函数在通信失败时会返回一个预定义的错误值通常是255。通过判断返回值是否等于AHTXX_ERROR我们可以知道读取是否成功并在OLED和串口监视器上给出明确提示而不是显示一个荒谬的数字如255°C。显示流程Adafruit GFX库采用“双缓冲”机制。所有display.print()或display.drawXXX()操作都是在内存中的一个图形缓冲区进行的。只有调用display.display()时缓冲区的内容才会被一次性发送到OLED屏幕并显示出来。这避免了屏幕刷新过程中的闪烁。延时控制delay(1500)让每个读数在屏幕上停留1.5秒方便观察。但请注意AHT10传感器内部在测量时会有微小的发热过于频繁的测量如每秒多次可能导致后续读数轻微偏高。数据手册建议的测量间隔通常在2秒到30秒之间。本代码中一次温度一次湿度测量总耗时约3秒加上可能的额外延时是合理的。5.4 高级功能状态诊断函数printSensorStatus()当读取失败时仅仅打印“Error”是不够的。我们需要知道具体哪里出了问题。printSensorStatus()函数就是干这个的。void printSensorStatus() { uint8_t status ahtSensor.getStatus(); // 获取传感器内部状态寄存器值 Serial.print(F(Sensor Status: 0x)); Serial.println(status, HEX); // 以十六进制打印状态码 // 根据状态码判断可能的原因 switch (status) { case AHTXX_NO_ERROR: Serial.println(F(- No error. Check wiring or power.)); break; case AHTXX_BUSY_ERROR: Serial.println(F(- Sensor is busy. Try increasing the delay between measurements.)); break; case AHTXX_ACK_ERROR: Serial.println(F(- Sensor did not acknowledge (ACK).)); Serial.println(F( Possible causes: Wrong I2C address, device not connected, broken, or I2C bus locked.)); Serial.println(F( Try: 1) Check device address. 2) Reduce I2C speed (comment out Wire.setClock). 3) Check pull-up resistors.)); break; case AHTXX_DATA_ERROR: Serial.println(F(- Received incomplete data.)); Serial.println(F( Possible causes: Long wires causing signal integrity issues, or bus contention.)); Serial.println(F( Try: 1) Shorten wires. 2) Reduce I2C speed. 3) Ensure only one master on the bus.)); break; // AHT10不支持CRC8校验此状态码通常用于AHT20/21 // case AHTXX_CRC8_ERROR: // Serial.println(F(CRC8 mismatch. Data corrupted during transmission.)); // break; default: Serial.println(F(- Unknown status code.)); break; } }为什么需要这个函数嵌入式开发中80%的时间都在调试。这个函数将底层晦涩的状态码转换成了人类可读的、带有排查建议的提示信息。例如如果看到“ACK Error”你立刻就知道问题可能出在I2C地址不对、线没接好或者总线冲突上而不是盲目地重新插拔所有线。6. 系统调试、优化与问题排查实录代码写完上传硬件接好通电但屏幕不亮或者数据全是0别急这是嵌入式开发的常态。下面是我在调试这个项目时遇到的一些典型问题及解决方法希望能帮你快速排雷。6.1 上电无任何反应屏幕不亮问题现象连接USB后OLED屏幕没有任何显示甚至背光如果有也不亮。排查步骤检查电源用万用表测量面包板电源轨的电压是否为5V左右。最可能的原因是杜邦线接触不良或Arduino Nano的5V引脚没有输出。检查OLED接线确认OLED的VCC和GND是否接反。虽然反接通常不会立刻烧毁但屏幕肯定不工作。再确认SDA、SCL是否分别接到了A4和A5。检查I2C地址SSD1306的I2C地址可能是0x3C或0x3D。在代码#define OLED_ADDR 0x3C处尝试改为0x3D。你可以运行一个I2C扫描程序Arduino IDE示例Wire-scanner来发现总线上所有设备的地址。检查库确认Adafruit SSD1306库已正确安装并且初始化代码display.begin(...)的参数与你的屏幕型号匹配例如有些128x32的屏幕需要不同的初始化参数。6.2 屏幕亮但无数据显示或显示乱码问题现象OLED屏幕点亮出现微光或闪一下但看不到“Temp:”等文字或者显示的是奇怪的方块。排查步骤检查代码上传确保代码已成功上传到Arduino Nano。观察上传时IDE下方的进度条和“上传成功”提示。检查清屏与刷新确认代码中在打印新内容前调用了display.clearDisplay()并且在打印完成后调用了display.display()。缺少后者是导致屏幕无显示的常见原因。检查字体和光标确保setTextSize()和setCursor()设置的参数在屏幕物理尺寸范围内0-127, 0-63。过大的字体或错误的光标位置可能导致文字画在屏幕外。查看串口监视器打开Arduino IDE的串口监视器波特率设为115200。如果能看到“System Initializing...”、“OLED Display OK”、“AHT10 Sensor OK”等提示说明程序在运行且传感器初始化成功。问题可能集中在显示部分。6.3 串口显示传感器初始化失败或读数错误问题现象串口监视器显示“AHT10 not found”或持续打印“Error”温度湿度值为255或0。排查步骤运行I2C扫描这是诊断I2C设备问题的首选工具。上传I2C扫描程序查看是否能扫描到地址0x38AHT10和0x3C/0x3DOLED。如果都扫不到检查总线连接SDA, SCL如果只扫到一个检查另一个设备的接线和电源。检查上拉电阻I2C总线需要上拉电阻通常4.7kΩ或10kΩ将SDA和SCL线拉到高电平。幸运的是Arduino Nano的内部上拉电阻可以通过软件启用。在setup()函数中Wire.begin()之后添加两行代码pinMode(A4, INPUT_PULLUP); pinMode(A5, INPUT_PULLUP);这可以解决因总线电平不明确导致的通信不稳定问题。如果加了上拉后问题依旧可以考虑在SDA和SCL线上外接4.7kΩ电阻到5V。 3.降低I2C速度如果使用了Wire.setClock(400000)请将其注释掉使用默认的100kHz速度。长导线或干扰环境可能导致高速通信失败。 4.检查电源质量使用移动电源或电脑USB口供电时如果连接线过长或质量差可能导致电压跌落影响传感器工作。尝试用更短的USB线或直接插在电脑主板USB口上供电。 5.检查库函数调用确保ahtSensor.begin()在Wire.begin()之后调用。有些AHT10库的begin()函数可能需要指定具体的I2C引脚如ahtSensor.begin(0, 2)针对ESP8266对于Arduino Nano通常不需要。6.4 读数不稳定或明显不准问题现象数值跳动过大或者与已知准确的温湿度计对比存在较大偏差。排查步骤避免传感器自热确保代码中两次完整测量之间有足够的延时如8-10秒。不要以高于1Hz的频率连续读取。热源隔离将AHT10传感器远离Arduino Nano、移动电源等可能发热的元件。最好用杜邦线将其引出放置在被测环境中。校准与参考AHT10出厂已校准但可能存在个体差异。如果你有高精度的参考仪表可以在一个稳定的环境中如密闭房间同时测量记录下系统误差。如果需要可以在代码中对读取值进行简单的偏移补偿例如correctedTemp sensorValue 0.5;。供电稳定性为整个系统提供稳定、干净的5V电源。使用廉价的手机充电器可能引入纹波干扰。6.5 功耗优化与长期运行考虑原型在面包板上跑通了但如果你想把它做成一个靠电池长期运行的壁挂设备功耗就成了关键。降低显示功耗OLED本身功耗很低但你可以让它在大部分时间关闭。修改代码只在读取数据后点亮屏幕显示几秒然后调用display.ssd1306_command(SSD1306_DISPLAYOFF);关闭显示。让Arduino休眠Arduino Nano在运行loop循环时功耗仍有几十毫安。可以使用LowPower库让MCU在测量间隔进入深度睡眠Sleep模式此时功耗可降至微安级。醒来后读取传感器、刷新显示然后继续睡眠。优化供电架构考虑使用3.3V系统。AHT10和SSD1306都支持3.3V。将Arduino Nano更换为3.3V工作的板子如Seeed Xiao SAMD21或使用低压差稳压器LDO从电池获取3.3V可以显著延长电池寿命。7. 项目进阶与扩展思路这个温湿度监测原型系统就像一块乐高底板你可以在此基础上添加更多模块构建更复杂的应用。7.1 数据记录与离线存储当前系统只能实时查看数据关机即失。添加一个SD卡模块就可以将带有时间戳的温湿度数据记录到txt或CSV文件中。你需要学习SPI通信协议SD卡常用以及文件系统的操作。结合DS3231等高精度RTC实时时钟模块就能获得准确的时间信息。7.2 无线传输与云端监控让数据“飞”起来。将Arduino Nano替换为ESP8266如NodeMCU或ESP32开发板利用其Wi-Fi功能可以将数据发送到本地服务器如运行在树莓派上的Home Assistant、Node-RED实现本地智能家居联动。公有云平台如ThingsBoard、Blynk、阿里云物联网平台实现手机App远程查看和历史数据图表分析。私有云通过MQTT协议将数据发布到自建的Mosquitto服务器再由其他应用订阅处理。7.3 声光报警与本地联动为系统增加“感官”和“反应”。连接一个蜂鸣器和一个RGB LED灯。逻辑实现在代码中设置温湿度的阈值例如温度高于30°C或湿度高于80%。触发动作当读数超过阈值时让蜂鸣器响起LED灯变为红色当读数恢复正常时LED变为绿色。这就实现了一个简单的本地环境超限报警器。7.4 迈向产品化从面包板到PCB正如我在项目初衷里提到的面包板只是起点。最终我希望它是一个可以挂在墙上的独立设备。这需要核心最小化用更小的MCU如ATmega328P-AU贴片芯片或ARM Cortex-M0核心的SAMD21替代Arduino Nano整板。设计PCB使用EDA工具如EasyEDA, KiCad将Arduino Nano、AHT10、SSD1306以及必要的电源电路、连接器集成到一块定制电路板上。这能极大提高可靠性缩小体积。电源管理在PCB上集成锂电池充电管理芯片如TP4056和升压电路实现充放电一体化。结构设计使用3D建模软件如Fusion 360设计一个外壳并3D打印出来。外壳上要预留传感器的通风孔和显示屏的视窗。从一堆散乱的元件到一个握在掌心、稳定工作的成品这个跨越带来的满足感远超让面包板上的灯闪烁几下。这个温湿度监测项目就是一个完美的起点它涉及的硬件连接、软件编程、调试排错、系统优化乃至后续的产品化思维正是嵌入式开发从入门到精通的完整缩影。
基于Arduino Nano与AHT10的温湿度监测仪:I2C总线应用实践
1. 项目概述与核心价值最近在捣鼓一个挺实用的小玩意儿一个放在房间里的温湿度监测仪。起因很简单我住的地方夏天温度变化挺大有时候在屋里待着明明觉得闷热一看空调遥控器上的温度显示又觉得“还行”但体感就是不舒服。后来琢磨了一下发现湿度对体感温度的影响非常大光知道温度是不够的。于是就想能不能自己做一个既能看温度又能看湿度的小设备实时了解一下房间的“气候”状况。这个想法听起来简单但背后涉及的技术点其实挺有意思的。它本质上是一个典型的嵌入式数据采集与显示系统核心流程是传感器感知物理世界温湿度→ 微控制器读取并处理数据 → 显示屏将数据可视化。我选择了Arduino Nano作为大脑AHT10作为感知器官SSD1306 OLED作为输出窗口。这套组合拳打下来成本不高但精度和实用性都足够。对于想入门嵌入式开发、物联网或者环境监测的朋友来说这是一个绝佳的练手项目。它能让你一次性接触到I2C通信、传感器驱动、OLED显示控制这几个关键技能点而且最终成果是一个看得见摸得着的实用工具成就感直接拉满。2. 核心硬件选型与设计思路2.1 为什么是Arduino Nano AHT10 SSD1306做项目选型是第一步也是最考验经验的一步。为什么是这三件套我来拆开讲讲我的考量。首先看主控Arduino Nano。在众多Arduino板子里Nano以小巧的尺寸和完整的ATmega328P核心功能脱颖而出。它拥有足够的GPIO、模拟输入和PWM输出对于这个只需要处理I2C通信和驱动显示的项目来说绰绰有余。更重要的是它的开发环境Arduino IDE生态极其成熟库资源丰富能极大降低开发门槛。相比于更基础的UnoNano更省空间相比于更强大的ESP32Nano在简单数据采集任务上功耗更低且没有Wi-Fi/蓝牙带来的复杂度让项目焦点更纯粹。其次是传感器AHT10。市面上温湿度传感器很多像DHT11/DHT22、SHT30等。选择AHT10主要看中三点一是精度其温度精度±0.3°C湿度精度±2% RH对于室内环境监测完全够用甚至有些“性能过剩”二是通信接口它采用标准的I2C接口只需要两根线SDA, SCL就能完成通信比DHT系列的单总线协议在代码编写和稳定性上更友好三是它的工作电压范围宽1.6V-6V这意味着它既能配合5V的Arduino Nano也能兼容未来可能使用的3.3V低功耗MCU如SAMD21为项目升级留足了空间。最后是显示屏SSD1306 OLED。选择它而不是LCD屏原因很直接好看、省电、接口简单。OLED是自发光显示黑色时像素点不工作对比度高在暗环境下观看体验极佳而且功耗比需要背光的LCD低得多。SSD1306同样采用I2C接口这意味着它可以和AHT10共用同一组I2C总线极大简化了硬件连接。128x64的分辨率足以清晰显示温度、湿度数值和一些简单的图标或单位。这套组合的核心设计思路就是“标准化与简化”。全部采用I2C设备使得硬件连线从可能的十几根减少到4根VCC, GND, SDA, SCL布线清晰出错率低。软件上三大组件都有非常成熟的Arduino库支持我们不需要从零编写底层驱动可以把精力集中在应用逻辑和数据处理上。2.2 物料清单与采购建议一份清晰的物料清单是项目成功的一半。以下是构建这个原型系统所需的所有硬件主控模块Arduino Nano开发板 x1传感模块AHT10数字温湿度传感器模块 x1显示模块0.96英寸 I2C接口 SSD1306 OLED显示屏 x1辅助工具面包板 x1用于快速搭建原型连接线材公对公杜邦线若干建议准备10根左右供电设备5V USB电源适配器或移动电源 x1关于采购这里有个小经验。像Arduino Nano和AHT10这类通用模块市面上版本众多质量参差不齐。我个人的习惯是对于核心控制器和传感器尽量选择口碑好的店铺或平台哪怕价格稍贵一点。这次我用到的Nano和AHT10就是从专业的PCB制造服务商那里获得的这类平台提供的元器件通常经过筛选品质和兼容性更有保障。对于初学者如果不想在淘宝上大海捞针也可以关注一些开源硬件商城它们提供的套件通常兼容性已经过测试。注意购买SSD1306 OLED时请务必确认是I2C接口版本。还有一种SPI接口的版本引脚定义和驱动方式完全不同买错了就无法使用本文的接线图和代码。3. 硬件连接与电路搭建详解硬件连接是让想法变成实体的第一步。这个项目的接线之所以简单核心秘诀就在于I2C总线共享。3.1 I2C总线原理与共享机制I2CInter-Integrated Circuit是一种同步、多主从、串行通信总线。它只需要两根线SDASerial Data Line数据线用于双向数据传输。SCLSerial Clock Line时钟线由主设备这里是Arduino产生用于同步数据。每个连接到I2C总线上的设备都有一个唯一的7位地址。主设备通过发送地址来选中需要通信的从设备。在这个项目中Arduino Nano是主设备AHT10和SSD1306都是从设备。幸运的是这两个设备的默认I2C地址通常不同AHT10常见地址为0x38SSD1306常见地址为0x3C因此它们可以和谐地挂载在同一组SDA和SCL线上互不干扰。这就实现了“一线多用”。3.2 分步接线指南与原理图解读下面我们开始动手连接。请对照以下步骤在面包板上完成所有接线供电先行将面包板两侧的电源轨连接好通常红色为正极蓝色或黑色为负极。然后用杜邦线将Arduino Nano的5V引脚连接到面包板的正极电源轨将GND引脚连接到面包板的负极电源轨。这样我们就建立了一个稳定的5V电源网络。连接AHT10传感器VCC- 面包板正极电源轨5VGND- 面包板负极电源轨GNDSDA- Arduino Nano的A4引脚这是Nano上作为I2C数据线的模拟引脚SCL- Arduino Nano的A5引脚这是Nano上作为I2C时钟线的模拟引脚连接SSD1306 OLED显示屏VCC- 面包板正极电源轨5VGND- 面包板负极电源轨GNDSDA-与AHT10的SDA线并联共同连接到Arduino Nano的A4引脚。SCL-与AHT10的SCL线并联共同连接到Arduino Nano的A5引脚。最终检查此时你的接线应该呈现出一种“星型”拓扑Arduino Nano的5V和GND像树干一样延伸到电源轨而AHT10和SSD1306则像树枝一样从电源轨获取电力同时它们的SDA和SCL线又分别汇聚到Nano的A4和A5引脚。实操心得在面包板上进行多设备并联时最容易出错的地方是接触不良。建议使用质量较好的杜邦线并确保每个插脚都牢固地插入面包板孔中。接线完成后可以轻轻晃动一下面包板观察OLED屏幕是否出现闪烁或复位以此初步判断电源和信号连接是否稳定。4. 软件开发环境配置与库安装硬件准备就绪接下来就是让大脑Arduino运转起来的软件部分。4.1 Arduino IDE基础设置首先确保你已安装最新版的Arduino IDE。打开IDE后我们需要进行两步关键设置选择开发板在工具-开发板菜单中选择Arduino Nano。选择处理器继续在工具-处理器菜单中根据你手头Nano的版本选择最常见的是ATmega328P旧Bootloader或ATmega328P。如果不确定可以逐个尝试直到能成功上传代码。选择端口用USB线将Nano连接到电脑在工具-端口菜单中选择新出现的串口在Windows上通常是COMx在Mac/Linux上是/dev/cu.usbmodemxxx。4.2 核心库的安装与说明这个项目依赖于三个第三方库它们封装了与AHT10和SSD1306通信的复杂细节。AHTxx库用于驱动AHT10传感器。在Arduino IDE中点击项目-加载库-管理库...打开库管理器。在搜索框中输入“AHTxx”找到由“Thinary”或类似作者维护的库进行安装。这个库提供了简洁的API来读取温湿度数据。Adafruit SSD1306库与Adafruit GFX库这两个是驱动OLED显示的核心。同样在库管理器中搜索“Adafruit SSD1306”进行安装。在安装过程中IDE通常会提示“此库依赖于Adafruit GFX Library”选择“安装所有”即可。Adafruit GFX库是一个强大的图形底层库SSD1306库则在其基础上实现了针对这块屏幕的具体驱动。注意事项安装库时务必注意库的兼容性和示例代码。安装完成后可以通过文件-示例菜单找到对应库的示例程序这是学习和调试的宝贵资源。例如运行一下Adafruit SSD1306库中的示例可以快速验证你的OLED屏幕是否接线正确、能否正常点亮。5. 代码逐行解析与编程逻辑代码是项目的灵魂。下面我将提供的代码进行拆解、优化并加入详细注释让你不仅知道怎么写更明白为什么这么写。5.1 库引入与全局定义#include Wire.h // Arduino内置的I2C通信库 #include AHTxx.h // AHT10传感器驱动库 #include Adafruit_SSD1306.h // SSD1306 OLED驱动库 #include Adafruit_GFX.h // Adafruit图形库SSD1306依赖它 // 定义OLED屏幕的尺寸像素 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 // 定义OLED屏幕的I2C地址最常见的地址是0x3C #define OLED_ADDR 0x3C // 创建SSD1306显示对象参数为宽度、高度、I2C地址后两个参数通常省略 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT); // 用于存储从AHT10读取到的温湿度值浮点数 float sensorValue; // 创建AHT10传感器对象 // 参数1: 传感器I2C地址AHT10常见地址为0x38 // 参数2: 传感器类型AHT10对应AHT1x_SENSOR AHTxx ahtSensor(AHTXX_ADDRESS_X38, AHT1x_SENSOR);关键点解析Wire.h是核心没有它Arduino就无法通过I2C协议与传感器和屏幕“对话”。定义屏幕尺寸和地址是为了让驱动库知道它在操作一个什么样的硬件。创建全局对象 (display,ahtSensor) 是面向对象编程的常见做法方便在setup()和loop()函数中调用。5.2 初始化函数setup()setup()函数只在设备上电或复位后运行一次用于初始化各种设置。void setup() { // 初始化串口通信设置波特率为115200用于调试输出 Serial.begin(115200); Serial.println(F(System Initializing...)); // F()宏将字符串存储在Flash中节省RAM // 初始化OLED显示屏 // SSD1306_SWITCHCAPVCC 表示使用芯片内部电荷泵生成显示所需的高电压 if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { Serial.println(F(SSD1306 allocation failed!)); for(;;); // 如果初始化失败程序将卡死在这里这是一个简单的错误处理 } Serial.println(F(OLED Display OK)); display.clearDisplay(); // 清空屏幕 display.display(); // 将清空操作更新到屏幕Adafruit库需要显式调用display()才能生效 // 初始化AHT10传感器 // begin()函数会尝试与传感器通信并加载校准系数 while (!ahtSensor.begin()) { Serial.println(F(AHT10 not found or calibration failed. Check wiring!)); delay(2000); // 等待2秒后重试避免刷屏 } Serial.println(F(AHT10 Sensor OK)); // 可选提高I2C通信速度默认100kHz可提升至400kHz // Wire.setClock(400000); // 注意提高速度可能增加通信错误风险如果出现数据读取不稳定请注释掉此行。 }编程逻辑与技巧错误处理对display.begin()和ahtSensor.begin()的返回值进行判断是良好的编程习惯。它能帮助你在硬件连接错误时快速定位问题而不是面对一个毫无反应的设备干着急。F()宏在串口打印提示信息时使用F()宏可以将这些字符串常量存储在Arduino的Flash程序存储区而非RAM中。对于内存紧张的ATmega328P只有2KB RAM来说这是一个重要的优化技巧。I2C速度Wire.setClock(400000)将I2C总线速度从默认的100kHz提升到400kHz可以加快数据读取速度。但高速通信对线路质量线长、干扰要求更高如果出现数据偶尔出错首先应该尝试注释掉这行代码恢复为标准速度。5.3 主循环函数loop()与数据显示逻辑loop()函数会周而复始地运行我们的主要逻辑就在这里。void loop() { // 第一部分读取并显示温度 sensorValue ahtSensor.readTemperature(); // 读取温度单位摄氏度 // 准备在OLED上显示温度 display.clearDisplay(); // 清除上一帧画面 display.setTextSize(2); // 设置字体大小为2较大清晰 display.setTextColor(SSD1306_WHITE); // 设置字体颜色为白色OLED单色 display.setCursor(0, 0); // 设置光标起始位置为(0, 0)即左上角 display.print(F(Temp: )); // 打印标签 display.setCursor(0, 25); // 将光标移动到第二行起始位置 display.setTextSize(3); // 调大数值的字体 // 判断读取是否成功 if (sensorValue ! AHTXX_ERROR) { // AHTXX_ERROR 通常定义为255 display.print(sensorValue, 1); // 显示温度值保留1位小数 display.setTextSize(2); display.print(F( C)); // 显示单位 Serial.print(F(Temperature: )); Serial.print(sensorValue, 1); Serial.println(F( C)); } else { // 读取失败显示错误信息 display.print(F(Error)); Serial.println(F(Failed to read temperature!)); printSensorStatus(); // 调用自定义函数打印详细错误状态 } display.display(); // 将缓冲区内容一次性刷新到OLED屏幕 delay(1500); // 保持温度显示1.5秒 // 第二部分读取并显示湿度 sensorValue ahtSensor.readHumidity(); // 读取湿度单位百分比RH // 准备在OLED上显示湿度 display.clearDisplay(); display.setTextSize(2); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); display.print(F(Humid: )); display.setCursor(0, 25); display.setTextSize(3); if (sensorValue ! AHTXX_ERROR) { display.print(sensorValue, 1); // 显示湿度值保留1位小数 display.setTextSize(2); display.print(F( %)); Serial.print(F(Humidity: )); Serial.print(sensorValue, 1); Serial.println(F( %)); } else { display.print(F(Error)); Serial.println(F(Failed to read humidity!)); printSensorStatus(); } display.display(); delay(1500); // 保持湿度显示1.5秒 // 建议两次完整测量之间增加一个较长的间隔 // AHT10数据手册建议测量频率不要高于每秒一次以防传感器自热影响精度 // delay(8000); // 可以在此处增加一个总间隔使循环周期约10秒 }逻辑优化与深度解析交替显示代码采用了温度、湿度交替显示的模式。这样做的好处是在小小的0.96英寸屏幕上可以以更大的字体显示单个数据提高可读性。如果你想同时显示需要将字体调小并精心排版。错误处理机制ahtSensor.readTemperature()和readHumidity()函数在通信失败时会返回一个预定义的错误值通常是255。通过判断返回值是否等于AHTXX_ERROR我们可以知道读取是否成功并在OLED和串口监视器上给出明确提示而不是显示一个荒谬的数字如255°C。显示流程Adafruit GFX库采用“双缓冲”机制。所有display.print()或display.drawXXX()操作都是在内存中的一个图形缓冲区进行的。只有调用display.display()时缓冲区的内容才会被一次性发送到OLED屏幕并显示出来。这避免了屏幕刷新过程中的闪烁。延时控制delay(1500)让每个读数在屏幕上停留1.5秒方便观察。但请注意AHT10传感器内部在测量时会有微小的发热过于频繁的测量如每秒多次可能导致后续读数轻微偏高。数据手册建议的测量间隔通常在2秒到30秒之间。本代码中一次温度一次湿度测量总耗时约3秒加上可能的额外延时是合理的。5.4 高级功能状态诊断函数printSensorStatus()当读取失败时仅仅打印“Error”是不够的。我们需要知道具体哪里出了问题。printSensorStatus()函数就是干这个的。void printSensorStatus() { uint8_t status ahtSensor.getStatus(); // 获取传感器内部状态寄存器值 Serial.print(F(Sensor Status: 0x)); Serial.println(status, HEX); // 以十六进制打印状态码 // 根据状态码判断可能的原因 switch (status) { case AHTXX_NO_ERROR: Serial.println(F(- No error. Check wiring or power.)); break; case AHTXX_BUSY_ERROR: Serial.println(F(- Sensor is busy. Try increasing the delay between measurements.)); break; case AHTXX_ACK_ERROR: Serial.println(F(- Sensor did not acknowledge (ACK).)); Serial.println(F( Possible causes: Wrong I2C address, device not connected, broken, or I2C bus locked.)); Serial.println(F( Try: 1) Check device address. 2) Reduce I2C speed (comment out Wire.setClock). 3) Check pull-up resistors.)); break; case AHTXX_DATA_ERROR: Serial.println(F(- Received incomplete data.)); Serial.println(F( Possible causes: Long wires causing signal integrity issues, or bus contention.)); Serial.println(F( Try: 1) Shorten wires. 2) Reduce I2C speed. 3) Ensure only one master on the bus.)); break; // AHT10不支持CRC8校验此状态码通常用于AHT20/21 // case AHTXX_CRC8_ERROR: // Serial.println(F(CRC8 mismatch. Data corrupted during transmission.)); // break; default: Serial.println(F(- Unknown status code.)); break; } }为什么需要这个函数嵌入式开发中80%的时间都在调试。这个函数将底层晦涩的状态码转换成了人类可读的、带有排查建议的提示信息。例如如果看到“ACK Error”你立刻就知道问题可能出在I2C地址不对、线没接好或者总线冲突上而不是盲目地重新插拔所有线。6. 系统调试、优化与问题排查实录代码写完上传硬件接好通电但屏幕不亮或者数据全是0别急这是嵌入式开发的常态。下面是我在调试这个项目时遇到的一些典型问题及解决方法希望能帮你快速排雷。6.1 上电无任何反应屏幕不亮问题现象连接USB后OLED屏幕没有任何显示甚至背光如果有也不亮。排查步骤检查电源用万用表测量面包板电源轨的电压是否为5V左右。最可能的原因是杜邦线接触不良或Arduino Nano的5V引脚没有输出。检查OLED接线确认OLED的VCC和GND是否接反。虽然反接通常不会立刻烧毁但屏幕肯定不工作。再确认SDA、SCL是否分别接到了A4和A5。检查I2C地址SSD1306的I2C地址可能是0x3C或0x3D。在代码#define OLED_ADDR 0x3C处尝试改为0x3D。你可以运行一个I2C扫描程序Arduino IDE示例Wire-scanner来发现总线上所有设备的地址。检查库确认Adafruit SSD1306库已正确安装并且初始化代码display.begin(...)的参数与你的屏幕型号匹配例如有些128x32的屏幕需要不同的初始化参数。6.2 屏幕亮但无数据显示或显示乱码问题现象OLED屏幕点亮出现微光或闪一下但看不到“Temp:”等文字或者显示的是奇怪的方块。排查步骤检查代码上传确保代码已成功上传到Arduino Nano。观察上传时IDE下方的进度条和“上传成功”提示。检查清屏与刷新确认代码中在打印新内容前调用了display.clearDisplay()并且在打印完成后调用了display.display()。缺少后者是导致屏幕无显示的常见原因。检查字体和光标确保setTextSize()和setCursor()设置的参数在屏幕物理尺寸范围内0-127, 0-63。过大的字体或错误的光标位置可能导致文字画在屏幕外。查看串口监视器打开Arduino IDE的串口监视器波特率设为115200。如果能看到“System Initializing...”、“OLED Display OK”、“AHT10 Sensor OK”等提示说明程序在运行且传感器初始化成功。问题可能集中在显示部分。6.3 串口显示传感器初始化失败或读数错误问题现象串口监视器显示“AHT10 not found”或持续打印“Error”温度湿度值为255或0。排查步骤运行I2C扫描这是诊断I2C设备问题的首选工具。上传I2C扫描程序查看是否能扫描到地址0x38AHT10和0x3C/0x3DOLED。如果都扫不到检查总线连接SDA, SCL如果只扫到一个检查另一个设备的接线和电源。检查上拉电阻I2C总线需要上拉电阻通常4.7kΩ或10kΩ将SDA和SCL线拉到高电平。幸运的是Arduino Nano的内部上拉电阻可以通过软件启用。在setup()函数中Wire.begin()之后添加两行代码pinMode(A4, INPUT_PULLUP); pinMode(A5, INPUT_PULLUP);这可以解决因总线电平不明确导致的通信不稳定问题。如果加了上拉后问题依旧可以考虑在SDA和SCL线上外接4.7kΩ电阻到5V。 3.降低I2C速度如果使用了Wire.setClock(400000)请将其注释掉使用默认的100kHz速度。长导线或干扰环境可能导致高速通信失败。 4.检查电源质量使用移动电源或电脑USB口供电时如果连接线过长或质量差可能导致电压跌落影响传感器工作。尝试用更短的USB线或直接插在电脑主板USB口上供电。 5.检查库函数调用确保ahtSensor.begin()在Wire.begin()之后调用。有些AHT10库的begin()函数可能需要指定具体的I2C引脚如ahtSensor.begin(0, 2)针对ESP8266对于Arduino Nano通常不需要。6.4 读数不稳定或明显不准问题现象数值跳动过大或者与已知准确的温湿度计对比存在较大偏差。排查步骤避免传感器自热确保代码中两次完整测量之间有足够的延时如8-10秒。不要以高于1Hz的频率连续读取。热源隔离将AHT10传感器远离Arduino Nano、移动电源等可能发热的元件。最好用杜邦线将其引出放置在被测环境中。校准与参考AHT10出厂已校准但可能存在个体差异。如果你有高精度的参考仪表可以在一个稳定的环境中如密闭房间同时测量记录下系统误差。如果需要可以在代码中对读取值进行简单的偏移补偿例如correctedTemp sensorValue 0.5;。供电稳定性为整个系统提供稳定、干净的5V电源。使用廉价的手机充电器可能引入纹波干扰。6.5 功耗优化与长期运行考虑原型在面包板上跑通了但如果你想把它做成一个靠电池长期运行的壁挂设备功耗就成了关键。降低显示功耗OLED本身功耗很低但你可以让它在大部分时间关闭。修改代码只在读取数据后点亮屏幕显示几秒然后调用display.ssd1306_command(SSD1306_DISPLAYOFF);关闭显示。让Arduino休眠Arduino Nano在运行loop循环时功耗仍有几十毫安。可以使用LowPower库让MCU在测量间隔进入深度睡眠Sleep模式此时功耗可降至微安级。醒来后读取传感器、刷新显示然后继续睡眠。优化供电架构考虑使用3.3V系统。AHT10和SSD1306都支持3.3V。将Arduino Nano更换为3.3V工作的板子如Seeed Xiao SAMD21或使用低压差稳压器LDO从电池获取3.3V可以显著延长电池寿命。7. 项目进阶与扩展思路这个温湿度监测原型系统就像一块乐高底板你可以在此基础上添加更多模块构建更复杂的应用。7.1 数据记录与离线存储当前系统只能实时查看数据关机即失。添加一个SD卡模块就可以将带有时间戳的温湿度数据记录到txt或CSV文件中。你需要学习SPI通信协议SD卡常用以及文件系统的操作。结合DS3231等高精度RTC实时时钟模块就能获得准确的时间信息。7.2 无线传输与云端监控让数据“飞”起来。将Arduino Nano替换为ESP8266如NodeMCU或ESP32开发板利用其Wi-Fi功能可以将数据发送到本地服务器如运行在树莓派上的Home Assistant、Node-RED实现本地智能家居联动。公有云平台如ThingsBoard、Blynk、阿里云物联网平台实现手机App远程查看和历史数据图表分析。私有云通过MQTT协议将数据发布到自建的Mosquitto服务器再由其他应用订阅处理。7.3 声光报警与本地联动为系统增加“感官”和“反应”。连接一个蜂鸣器和一个RGB LED灯。逻辑实现在代码中设置温湿度的阈值例如温度高于30°C或湿度高于80%。触发动作当读数超过阈值时让蜂鸣器响起LED灯变为红色当读数恢复正常时LED变为绿色。这就实现了一个简单的本地环境超限报警器。7.4 迈向产品化从面包板到PCB正如我在项目初衷里提到的面包板只是起点。最终我希望它是一个可以挂在墙上的独立设备。这需要核心最小化用更小的MCU如ATmega328P-AU贴片芯片或ARM Cortex-M0核心的SAMD21替代Arduino Nano整板。设计PCB使用EDA工具如EasyEDA, KiCad将Arduino Nano、AHT10、SSD1306以及必要的电源电路、连接器集成到一块定制电路板上。这能极大提高可靠性缩小体积。电源管理在PCB上集成锂电池充电管理芯片如TP4056和升压电路实现充放电一体化。结构设计使用3D建模软件如Fusion 360设计一个外壳并3D打印出来。外壳上要预留传感器的通风孔和显示屏的视窗。从一堆散乱的元件到一个握在掌心、稳定工作的成品这个跨越带来的满足感远超让面包板上的灯闪烁几下。这个温湿度监测项目就是一个完美的起点它涉及的硬件连接、软件编程、调试排错、系统优化乃至后续的产品化思维正是嵌入式开发从入门到精通的完整缩影。