一、实物

1、HI3861

如图是普中-Hi3861开发板,

(1)标号「3」的金属屏蔽罩模块

        这个模块就是普中 - Hi3861 开发板的核心大脑,不是单纯的 WiFi 模块,而是主控 + WiFi + 蓝牙三合一的系统级芯片模组,型号是Hi3861L。核心功能:

  • 主控单元:负责运行你的 C 语言代码,执行传感器数据采集、预处理、MQTT 通信等所有逻辑,是整个系统的 “CPU”。
  • 内置 WiFi 功能:它自带完整的 WiFi 电路和协议栈,通过左上角那个金色小圆点(天线)发射和接收信号。你在代码里配置好路由器的 SSID 和密码,它就能自动连接 WiFi,实现联网,完全不用额外接网卡。
  • 内置蓝牙功能:同时支持蓝牙通信
  • 低功耗控制:作为鸿蒙 IoT 芯片,它自带休眠 / 唤醒控制,适合物联网低功耗场景。

(2)标号「9」的黄色排针

        这排黄色的引脚是通用 GPIO(通用输入输出)扩展接口,大多传感器(MAX30102、DS18B20)都是通过它和主控连接的。

为什么它能连接传感器?
  1. 引脚定义清晰:每一个引脚都对应着 Hi3861 芯片的一个功能接口,板子上丝印标注了每个引脚的功能,比如:
    • 3V3:3.3V 电源,给传感器供电
    • GND:接地,构成完整电路
    • GPIO0~GPIO14:通用输入输出引脚,可配置为 I2C、单总线等通信模式
    • ADC:模数转换引脚,可接模拟传感器
  2. 通信协议支持:通过代码配置,这些引脚可以变成不同的通信接口:
    • MAX30102,就是通过配置GPIO13GPIO14I2C 通信模式,实现数据读写;
    • DS18B20 则是用GPIO10配置为单总线模式,实现温度数据采集。
  3. 扩展能力强:除了你的两个传感器,还可以接 LED、按键、舵机等其他外设,这就是它叫 “扩展口” 的原因。

2、传感器

(1)MAX30102

核心原理:光电容积描记法 (PPG)。这是一种利用光来监测血管中血容量变化的技术。它会向皮肤发射特定波长的光,然后检测反射回来的光强度信号,可以无创地测量心率和血氧饱和度。

工作流程详解:

  1. 发射:内置的红光 (~660nm) 和红外光 (~880nm) LED交替或同时发光,穿透皮肤表层。

  2. 吸收与反射:血液中的血红蛋白对不同波长光的吸收能力不同。氧合血红蛋白 (HbO2) 吸收更多红外光,而脱氧血红蛋白 (Hb) 吸收更多红光。

  3. 检测:光电探测器接收未被吸收而反射回来的光信号。由于每次心脏搏动都伴随着动脉血容量和含氧量的周期性变化,反射光强度也会随之波动。

  4. 计算:MAX30102 内部的 AFE(模拟前端)将光信号转换为原始的 PPG 数字量(红光和红外光的ADC采样值)。Hi3861 通过 I2C 读取这些原始数据后,再运行心率、血氧算法(如FFT、峰值检测、比率法),最终计算出心率和血氧值。

主要特点:

  • 高度集成光学模块,专为可穿戴设备设计。

  • 超低功耗,支持关断模式(典型值0.7µA)。

  • 拥有强大的环境光抑制能力,能提升测量准确性。

(2)DS18B20

核心技术:片内集成的一个 温度-频率转换模块,它会:

  • 使用两个特性差异巨大的振荡器:一个频率非常稳定,几乎不受温度影响;另一个的频率则对温度极其敏感,会随温度升高而升高。

  • 通过一系列复杂的脉冲计数与逻辑运算,将温度值转换为一个16位的数字量,直接输出。

  • 最终,Hi3861只需通过简单指令,就能从DS18B20中读出这个已经完成模数转换的温度数值。

使用指南:

  1. 连接:其最大特色是采用 单总线 (1-Wire) 协议,只需一根数据线(加上电源和地)就能与Hi3861通信,可以大大节省MCU的引脚资源。

  2. 操作:主机(Hi3861)必须严格按照复位脉冲、存在脉冲、读/写时隙等特定时序来操作总线(对烧录到板子中的代码的要求)。

  3. 读取:在转换完成后,只需向传感器发送0xBE [读取暂存器] 命令,即可读出9到12位的数字化温度值。

  4. 分辨率:可以根据需要在9到12位之间调整,默认12位模式下,最高分辨率可达 0.0625°C

主要特点

  • 测量范围宽:-55°C ~ +125°C,在 -10°C ~ +85°C 范围内精度高达 ±0.5°C

  • 无需任何外部元件,可直接与微控制器连接。

  • 支持多点组网,一根总线上可挂载多个传感器。

  • 支持“寄生电源”模式,可以不接外部电源,直接从数据线上获取工作电力。

        从Hi3861的视角看,I2C和单总线这两种通信方式虽然原理不同,但在逻辑上都遵循了标准的软件操作流程(即所谓“通信协议”或“时序”),通过读写寄存器来完成数据交换,这为你连接和处理这两类传感器提供了清晰的技术路径。

二、接线

1、MAX30102(I2C 通信)

代码中 I2C 引脚定义(核心代码片段)

hi_void code_io_init(hi_void)
{
    hi_gpio_init();

    // IIC
    hi_io_set_func(HI_IO_NAME_GPIO_0, HI_IO_FUNC_GPIO_0_I2C1_SDA);
    hi_io_set_func(HI_IO_NAME_GPIO_1, HI_IO_FUNC_GPIO_1_I2C1_SCL);
    if (hi_i2c_init(1, 400000) == HI_ERR_SUCCESS)
        printf("I2C INIT END  P0 P1\r\n");
}
MAX30102 引脚 Hi3861 引脚 功能
VCC 3.3V 供电
GND GND 接地
SDA GPIO0 I2C 数据
SCL GPIO1 I2C 时钟

2、 DS18B20(单总线 1-Wire)

1. 代码中隐含的单总线引脚

        DS18B20 是单总线温度传感器,通过 1-Wire 单总线 通信,普中 Hi3861 开发板的 DS18B20 单总线默认映射到 GPIO9(普中官方驱动默认引脚为 GPIO9)

2. 硬件接线对应关系

Hi3861 引脚 DS18B20 引脚 功能说明 补充说明
GPIO9 DQ 单总线数据引脚 需外接 4.7K~10K 上拉电阻 到 3.3V
3.3V VDD 电源(3.3) DS18B20 支持寄生电源 / 外部电源,推荐外部 3.3V 供电
GND GND 必须共地

三、核心代码

1、头文件与全局配置(基础依赖)

#include <Arduino.h>// MAX30102依赖(需安装Adafruit MAX3010x库)
...

/********************* 配置参数 *********************/
// WiFi配置
const char* WIFI_SSID = "你的WiFi名称";
const char* WIFI_PWD  = "你的WiFi密码";
// MQTT配置
const char* MQTT_BROKER = "MQTT服务器IP"; // 如192.168.1.100或公网地址
const int   MQTT_PORT   = 1883;          // MQTT默认端口
const char* MQTT_TOPIC  = "sensor/data"; // 上传数据的主题
const char* MQTT_CLIENT_ID = "esp32_sensor_001"; // 客户端唯一ID
// 引脚定义
#define DS18B20_PIN 4 // DS18B20数据引脚

/********************* 全局对象 *********************/
// MAX30102对象
MAX30105 particleSensor;
// DS18B20对象
OneWire oneWire(DS18B20_PIN);
DallasTemperature sensors(&oneWire);
// WiFi+MQTT对象
WiFiClient espClient;
PubSubClient mqttClient(espClient);

2、MAX30102 模块(心率 / 血氧采集)

核心功能:初始化传感器、采集红外 / 红光值、计算心率。

// 心率计算缓存
uint32_t irValue = 0; // 红外光值
int beatAvg;          // 平均心率

// 初始化MAX30102
void initMAX30102() {
  Serial.println("初始化MAX30102...");
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) { // I2C高速模式
    Serial.println("MAX30102初始化失败!");
    while (1); // 卡死等待排查
  }
  // 配置传感器参数(官方推荐默认配置)
  particleSensor.setup(60, 4, 2, 411, 11); // 采样率、脉宽、增益等
  particleSensor.setPulseAmplitudeRed(0x0A); // 红光强度
  particleSensor.setPulseAmplitudeIR(0x0A);  // 红外光强度
  particleSensor.setPulseAmplitudeGreen(0);  // 关闭绿光(仅测心率/血氧)
  Serial.println("MAX30102初始化完成");
}

// 读取MAX30102数据(心率)
float readMAX30102HeartRate() {
  long irValue = particleSensor.getIR(); // 读取红外光值(核心:心率由红外光波动计算)
  
  // 心率算法(heartRate库内置)
  if (checkForBeat(irValue)) { // 检测到心跳脉冲
    beatAvg = getHeartRate();  // 获取平均心率
  }
  
  // 过滤无效值(心率范围:30-200)
  if (beatAvg < 30 || beatAvg > 200) {
    return -1; // 无效值标记
  }
  return (float)beatAvg;
}

核心逻辑: MAX30102 通过红外光(IR)检测血液流动的光反射变化,checkForBeat() 检测心跳脉冲,getHeartRate() 累计计算平均心率;血氧需同时读取红光 + 红外光的比值,逻辑类似但需校准公式(可扩展,计算血氧逻辑太复杂,就把代码放到另一个文章了)。

3、DS18B20 模块(温度采集)

核心功能:初始化单总线、触发温度转换、读取精准温度值。

// 初始化DS18B20
void initDS18B20() {
  Serial.println("初始化DS18B20...");
  sensors.begin(); // 初始化单总线
  Serial.println("DS18B20初始化完成");
}

// 读取DS18B20温度(℃)
float readDS18B20Temperature() {
  sensors.requestTemperatures(); // 触发温度转换(必须调用)
  float temp = sensors.getTempCByIndex(0); // 读取第一个传感器的温度(℃)
  
  // 过滤无效值(DS18B20默认返回-127℃表示故障)
  if (temp == -127.00) {
    Serial.println("DS18B20读取失败");
    return -1;
  }
  return temp;
}

核心逻辑: DS18B20 是单总线协议,requestTemperatures() 是 “触发转换” 指令(传感器需要时间采集温度),getTempCByIndex(0) 读取转换后的温度(支持多传感器级联,index 区分)。

4、MQTT+WiFi 模块(数据上传)

核心功能:WiFi 重连、MQTT 重连、封装传感器数据为 JSON 并发布。

// 连接WiFi
void connectWiFi() {
  Serial.print("连接WiFi: ");
  Serial.println(WIFI_SSID);
  
  WiFi.mode(WIFI_STA); // 客户端模式(非AP模式)
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  
  // 等待连接(超时10秒)
  int retry = 0;
  while (WiFi.status() != WL_CONNECTED && retry < 10) {
    delay(500);
    Serial.print(".");
    retry++;
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi连接成功!");
    Serial.print("IP地址: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nWiFi连接失败!");
    ESP.restart(); // 重启重试
  }
}

// 重连MQTT(断连自动重连)
void reconnectMQTT() {
  while (!mqttClient.connected()) {
    Serial.print("连接MQTT...");
    // 连接MQTT服务器(无账号密码版,有密码则加参数:mqttClient.connect(CLIENT_ID, USER, PWD))
    if (mqttClient.connect(MQTT_CLIENT_ID)) {
      Serial.println("MQTT连接成功!");
      // 可选:订阅主题(如需接收服务器指令)
      // mqttClient.subscribe("sensor/control");
    } else {
      Serial.print("失败,错误码:");
      Serial.print(mqttClient.state()); // 打印错误码(如-4=超时,-2=拒绝)
      Serial.println(",5秒后重试...");
      delay(5000);
    }
  }
}

// 封装传感器数据并发布到MQTT
void publishSensorData() {
  // 读取传感器数据
  float temp = readDS18B20Temperature();
  float heartRate = readMAX30102HeartRate();
  
  // 封装JSON(便于服务器解析)
  char payload[128]; // 缓存JSON字符串
  snprintf(payload, sizeof(payload), 
           "{\"temperature\":%.2f, \"heartRate\":%.1f}", 
           temp, heartRate);
  
  // 发布数据
  if (mqttClient.publish(MQTT_TOPIC, payload)) {
    Serial.print("MQTT发布成功: ");
    Serial.println(payload);
  } else {
    Serial.println("MQTT发布失败!");
  }
}

5、主函数(整合所有模块)

void setup() {
  Serial.begin(115200); // 串口调试
  
  // 初始化所有模块
  initMAX30102();
  initDS18B20();
  connectWiFi();
  mqttClient.setServer(MQTT_BROKER, MQTT_PORT); // 设置MQTT服务器地址+端口
}

void loop() {
  // 保证WiFi和MQTT始终连接
  if (WiFi.status() != WL_CONNECTED) {
    connectWiFi();
  }
  if (!mqttClient.connected()) {
    reconnectMQTT();
  }
  mqttClient.loop(); // 处理MQTT心跳/消息(必须调用)
  
  // 每2秒发布一次数据
  publishSensorData();
  delay(2000);
}

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐