支持 C/C++ 及 MicroPython 编程,并配有 3D 打印外壳,内部预留空闲空间,便于集成传感器模块。

系统框架很简单,从传感器读取环境数据,然后展示到12指神探的屏幕上。
原理图

实际成品

硬件测试
板子打好后,先再焊盘上焊上引线对板子做初步测试。首先是使用I2C扫描,看看是否能读取到两颗传感器芯片的I2C地址。

只能读到一个传感器的地址。先是怀疑板子焊接问题,仔仔细细、来来回回检查了PCB板子,确认了焊脚都是OK的。于是向群里各位老师求教。老师们介绍这个12指神探能做逻辑分析仪,可以抓取I2C波形图来寻找问题所在。

在硬件调试过程中,通过逻辑分析仪抓取 I²C 总线波形时,仅观察到与温度传感器 NST461-DQNR 的通信数据,而绝压传感器 NSPAD1N200DR04 的通信波形完全缺失。进一步排查发现,问题根源在于该绝压传感器的 I²C 地址配置:其官方文档明确标注设备地址为 0x7F,但此地址在标准的 7-bit I²C 地址空间 中属于 保留区,通常用于特殊协议或未定义设备。
常规的 I²C 扫描程序会默认跳过保留地址段,导致主机无法识别该传感器。许多开源库的扫描范围仅覆盖 0x03-0x77,因此 0x7F 被自动忽略。这一机制解释了为何波形图中未出现绝压传感器的通信数据——主机根本未尝试访问该地址。
#include <Wire.h>
#include "SPI.h"
#include "TFT_eSPI.h"
#include "U8g2_for_TFT_eSPI.h"
arduino::MbedI2C Wire0(20, 21);
TFT_eSPI tft = TFT_eSPI(); // tft instance
U8g2_for_TFT_eSPI u8f; // U8g2 font instance
void setup()
{
Wire0.begin();
tft.begin();
tft.setRotation(0);
tft.fillScreen(TFT_BLACK);
u8f.setFontMode(0); // use u8g2 none transparent mode
u8f.setFontDirection(0); // left to right (this is default)
u8f.setForegroundColor(TFT_WHITE); // apply color
u8f.setFont(u8g2_font_wqy15_t_gb2312);
u8f.begin(tft); // connect u8g2 procedures to TFT_eSPI
Serial.begin(115200);
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
char buf[20];
Serial.println("Scanning...");
u8f.setCursor(0, 20);
u8f.print("Scanning...");
nDevices = 0;
for (address = 1; address <= 127; address++)
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire0.beginTransmission(address);
error = Wire0.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
u8f.setCursor(0, 40 + 20 * nDevices);
sprintf(buf, "I2C device address 0x%02x", address);
u8f.print(buf);
if (address < 16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error == 4)
{
Serial.print("Unknow error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}经过调整出来了地址

项目实现
搞定了硬件,接下来的开发就变得很简单了。

读取温度。温度分两个温度:一个本地温度,一个远端温度。远端温度通过读取的温度值和实际温度做比较,高了约1.83℃。查阅官方手册,可以通过寄存器进行校准,不过可惜是寄存器校准,这就意味着一旦断电,就需要重新校正,所以这里将这个1.83℃的温差,写死在了程序里。

代码
// 手工测的 远端与本地温度相差为1.83°C 将偏差温度写入寄存器
void setTempOffset()
{
uint8_t buf[2];
float offset = -1.83;
buf[0] = (int8_t)(floor(offset));
buf[1] = (uint8_t)((offset - floor(offset)) * 16);
writeReg8(REG_R_OFFS_H, buf[0]);
writeReg8(REG_R_OFFS_L, buf[1]);
}
// 读取远本地温度,返回单位为 °C 的 float
float readLocalTemp()
{
uint8_t buf[2];
/* 读本地温度 */
Wire0.beginTransmission(NST_ADDR);
Wire0.write(REG_L_TEMP_H);
Wire0.endTransmission(false);
Wire0.requestFrom(NST_ADDR, 2);
buf[0] = Wire0.read();
buf[1] = Wire0.read();
return (int16_t)((buf[0] << 8 | buf[1]) >> 4) * 0.0625f;
}
// 读取远端温度,返回单位为 °C 的 float
float readRemoteTemp()
{
uint8_t buf[2];
/* 读远端温度 */
Wire0.beginTransmission(NST_ADDR);
Wire0.write(REG_R_TEMP_H);
Wire0.endTransmission(false);
Wire0.requestFrom(NST_ADDR, 2);
buf[0] = Wire0.read();
buf[1] = Wire0.read();
return (int16_t)((buf[0] << 8 | buf[1]) >> 4) * 0.0625f;
}绝压传感器读取也是比较简单的,直接读取出气压值。
// --------------绝压传感器NSPAD1N200DR04------------------------------------------
/* 向寄存器写 1 字节 */
bool nspad1n_writeReg(uint8_t reg, uint8_t val)
{
Wire0.beginTransmission(I2C_ADDR);
Wire0.write(reg);
Wire0.write(val);
return Wire0.endTransmission(true) == 0;
}
/* 从寄存器连续读 n 字节 */
bool nspad1n_readRegs(uint8_t reg, uint8_t *buf, uint8_t len)
{
Wire0.beginTransmission(I2C_ADDR);
Wire0.write(reg);
if (Wire0.endTransmission(false) != 0)
return false; // restart
Wire0.requestFrom(I2C_ADDR, len);
if (Wire0.available() != len)
return false;
for (uint8_t i = 0; i < len; ++i)
buf[i] = Wire0.read();
return true;
}
/* 触发转换并等待完成,最大等待 100 ms */
bool nspad1n_triggerAndWait(void)
{
if (!nspad1n_writeReg(REG_CMD, 0x0A))
return false;
uint8_t status = 0;
unsigned long t = millis();
do
{
if (!nspad1n_readRegs(REG_CMD, &status, 1))
return false;
if (status & 0x02)
return true; // bit1 = 1 表示转换完成
} while (millis() - t < 100);
return false; // 超时
}
/* 读取压力并返回单位 kPa,失败返回 NAN */
float nspad1n_readPressure(void)
{
uint8_t buf[3];
if (!nspad1n_triggerAndWait())
return NAN;
if (!nspad1n_readRegs(REG_PDATA, buf, 3))
return NAN;
int32_t code = ((uint32_t)buf[0] << 16) | ((uint16_t)buf[1] << 8) | buf[2];
if (code > 8388607)
code -= 16777216; // 符号扩展
return (float)code * A / 8388607.0f + B;
}在成功读取温度传感器 NST461-DQNR 的本地与远程温度数据,以及绝压传感器 NSPAD1N200DR04 的气压值后,采用 U8g2_for_TFT_eSPI 库在 LCD 彩屏上实现数据可视化。该库专为嵌入式设备优化,支持流畅的图形渲染与文本显示。通过调用库函数,在屏幕固定区域绘制本地温度与远程温度,单位为 °C,并动态更新数值;在右侧区域显示当前气压值,单位为 kPa。为提升可读性,添加标题标签并调整字体大小与颜色,确保信息清晰区分。整个绘制过程占用少量 CPU 资源,与传感器数据读取任务并行运行,实现实时环境监测的桌面摆件功能。
实现效果

我要赚赏金
