任务介绍
本期的任务是测试测量主题的,我们在其中发现了一个温度采集任务,,所以我们选择了本次的任务2-数字温度/环境传感器采集模块,设计一款集成数字温度(或环境)传感器的采集模块,通过数字接口直接读取传感器值,为后续测量或控制系统提供数据源。基本要求:
- 至少集成一种数字温度传感器(DS18B20、BME280、SHT30 等)
- 数字通信接口(I2C/SPI/1-Wire 至少一种)
- 板载3.3V或5V供电,含去耦电容
- 提供MCU接口(含必要的上拉电阻)
- 板载工作指示LED。
硬件介绍
本次设计的传感器模块基于ENS210-LQFM传感器为核心构建,实际上我们设计过几款温湿度次啊及模块,这次用的传感器是一个之前没有接触过的传感器,所以这次着重体验一下。ENS210-LQFM是由ScioSense推出的一款超小型数字温湿度传感器,它在一颗芯片上同时集成了高精度温度传感器和相对湿度传感器,并内置I²C数字接口,出厂已完成数字预校准,可直接输出%RH和开尔文温度值,开发者无需再做复杂的补偿计算。芯片采用QFN-4封装,尺寸仅2.0mm×2.0mm×0.75mm,底部带散热焊盘,非常适合空间受限的便携式和穿戴式设备。电气性能方面,工作电压范围宽达1.71V至3.6V,可直接适配3.3V或1.8V的MCU系统;温度测量范围-40°C至+100°C,全温精度典型值±0.15°C;湿度测量范围0%至100%RH,典型精度±2.0%RH,分辨率达16位;温度响应时间小于1秒,湿度响应时间小于3秒。应用场景非常广泛,包括智能家居与楼宇自动化(HVAC、空气质量检测、智能恒温器)、白色家电(洗衣机、烘干机、冰箱)、可穿戴与个人健康设备、物联网节点、气象站以及运输环境监控等。
模块介绍
方案设计主要要求任务要求进行设计选型,尽可能做的小一点,基本方案模块组成如下:
原理图和PCB模块介绍

以ENS210-LQFM数字温湿度传感器为核心搭建的极简型检测模块原理图,依托传感器原生的I2C通信接口完成数据交互,SDA与SCL两条通信线路分别串联10K限流电阻完成信号阻抗匹配,末端搭配100nF去耦电容滤除总线杂波干扰,保障I2C通信的稳定性,传感器供电引脚直接接入VCC,GND引脚可靠接地,外围电路精简高效,右侧2.54-1*4直插接口将SCL、SDA、电源与接地引脚完整引出,可直接对接各类主控平台,搭配的3K限流电阻与LED1组成电源状态指示电路,通电后即可直观反馈模块供电正常。
原理图
ENS210温湿度传感器小型PCB采用紧凑圆角外形设计,板面丝印清晰标注核心器件型号,板边预留的安装孔适配狭小空间固定需求,核心ENS210传感器放置在板面下方居中位置,四周走线短且布局紧凑,SDA、SCL两条I2C通信线路分别串联的限流电阻就近排布,走线阻抗连续无冗余弯折,供电回路的去耦电容紧邻电源引脚放置,可高效滤除供电杂波干扰,板边J1直插接口按VCC、GND、SCL、SDA的顺序规整排布,方便快速对接主控平台,电源指示灯与配套限流电阻布局在板侧,大面积铺铜连通全板地网络,有效降低电磁干扰,在极小的板载空间内兼顾了信号完整性与测量稳定性,适配可穿戴设备、小型物联网节点等对体积要求严苛的温湿度采集场景。
PCB
本次的设计主要注意的就是传感器附近尽量不覆铜,如果可以做避空更好,我们这次通过做槽进行避空。
3D效果图
实物图
测试调试
本次我们使用的是STM32C562开发板来进行本次的ENS210传感器模块驱动设计,注意STM32C562只能用STM32CubeMX2进行初始化代码进行生成,然后使用VScode或者IAR进行工程编辑,我们本次生成的是Cmake工程,使用VScode开发。
本次的硬件连接如下:
实现的主要功能是通过串口对温湿度数据进行打印,定时打印,采样周期2s。
主要代码说明
主应用入口:
#include "main.h"
#include <stdint.h>
#include <stdio.h>
#include "ens210.h"
#include "usart2.h"
static void print_i32(int32_t v)
{
char buf[12]; int n = 0; bool neg = false;
if (v < 0) { neg = true; v = -v; }
if (v == 0) { buf[n++] = '0'; }
while (v > 0) { buf[n++] = (char)('0' + (v % 10)); v /= 10; }
if (neg) USART2_PutChar('-');
while (n > 0) USART2_PutChar((uint8_t)buf[--n]);
}
static void print_fix1(int32_t scaled) /* value = scaled / 10 */
{
int32_t ip = scaled / 10;
int32_t fr = scaled % 10;
if (fr < 0) fr = -fr;
print_i32(ip);
USART2_PutChar('.');
USART2_PutChar((uint8_t)('0' + fr));
}
int main(void)
{
if (mx_system_init() != SYSTEM_OK) return -1; /* 系统/时钟/I2C1 初始化 */
USART2_Init();
USART2_PutString("ENS210 demo on NUCLEO-C562RE\n");
if (!ENS210_Init())
USART2_PutString("ENS210 not detected (check I2C1 / PB6-PB7 wiring).\n");
else
{
(void)ENS210_SetSingleMode(true);
USART2_PutString("ENS210 ready.\n");
}
while (1)
{
if (ENS210_IsAvailable())
{
ENS210_Measure();
ENS210_Status_t st = ENS210_GetStatus();
float t = ENS210_GetTemperatureC();
float h = ENS210_GetHumidityPercent();
USART2_PutString("[ENS210] status=");
print_i32((int32_t)st);
USART2_PutString(" temp="); print_fix1((int32_t)(t * 10.0f));
USART2_PutString("C hum="); print_fix1((int32_t)(h * 10.0f));
USART2_PutString("%\n");
}
HAL_Delay(2000U);
}
}
ENS210 驱动
文件 ens210.h 给出寄存器映射与状态枚举:
#define ENS210_I2C_ADDR (0x43U << 1U) /* HAL 用的 8 位地址 */
#define ENS210_PART_ID_EXPECTED 0x0210U
#define ENS210_REG_PART_ID 0x00U
#define ENS210_REG_SYS_CTRL 0x10U
#define ENS210_REG_SENS_RUN 0x21U
#define ENS210_REG_SENS_START 0x22U
#define ENS210_REG_T_VAL 0x30U
#define ENS210_REG_H_VAL 0x33U
#define ENS210_THCONV_SINGLE_MS 130U /* 单次转换时间 */
typedef enum {
ENS210_STATUS_OK = 1,
ENS210_STATUS_INVALID = 2,
ENS210_STATUS_CRCERROR = 3,
ENS210_STATUS_I2CERROR = 4,
} ENS210_Status_t;
CRC-7 校验(多项式 0x89,初值 0x7F)
#define CRC7_POLY 0x89U
#define CRC7_IVEC 0x7FU
#define CRC7_WIDTH 7U
#define DATA7_WIDTH 17U
static uint8_t crc7(uint32_t val)
{
uint32_t pol = CRC7_POLY, bit;
pol <<= (DATA7_WIDTH - CRC7_WIDTH - 1U);
bit = DATA7_MSB;
val = (val & DATA7_MASK) << CRC7_WIDTH;
bit <<= CRC7_WIDTH;
pol <<= CRC7_WIDTH;
val |= CRC7_IVEC;
while (bit & (DATA7_MASK << CRC7_WIDTH))
{
if (bit & val) val ^= pol;
bit >>= 1U; pol >>= 1U;
}
return (uint8_t)(val & 0x7FU);
}
I2C 读写封装(HAL 轮询模式)
static bool ens_read(uint8_t reg, uint8_t *buf, uint8_t len)
{
hal_i2c_handle_t *hi2c = mx_i2c1_i2c_gethandle();
if (HAL_I2C_MASTER_Transmit(hi2c, ENS210_I2C_ADDR, ®, 1U, 1000U) != HAL_OK)
return false;
return (HAL_I2C_MASTER_Receive(hi2c, ENS210_I2C_ADDR,
buf, (uint32_t)len, 1000U) == HAL_OK);
}
初始化(探测 PART_ID)
bool ENS210_Init(void)
{
s_available = false;
if (!ens_lowpower(false)) return false; /* 退出低功耗才能读 ID */
uint8_t buf[2] = {0};
if (!ens_read(ENS210_REG_PART_ID, buf, 2)) {
(void)ens_lowpower(true); return false;
}
uint16_t part_id = (uint16_t)(((uint16_t)buf[1] << 8) | buf[0]);
if (part_id == ENS210_PART_ID_EXPECTED) s_available = true;
(void)ens_lowpower(true); /* 回到默认低功耗 */
return s_available;
}
单次测量与解码
void ENS210_Measure(void)
{
if (!s_available) return;
if (s_single_mode)
(void)ens_write8(ENS210_REG_SENS_RUN, ENS210_SENS_RUN_IDLE); /* 0x00 */
if (!ens_write8(ENS210_REG_SENS_START, ENS210_SENS_START_T_H)) /* 0x03 */
return;
HAL_Delay(s_single_mode ? ENS210_THCONV_SINGLE_MS
: ENS210_THCONV_CONT_MS);
uint8_t raw[6] = {0};
if (!ens_read(ENS210_REG_T_VAL, raw, 6)) return;
uint32_t t_raw = ((uint32_t)raw[2] << 16) | ((uint32_t)raw[1] << 8) | raw[0];
uint32_t h_raw = ((uint32_t)raw[5] << 16) | ((uint32_t)raw[4] << 8) | raw[3];
uint32_t t_data = 0, h_data = 0;
ENS210_Status_t ts = decode_word(t_raw, &t_data);
ENS210_Status_t hs = decode_word(h_raw, &h_data);
s_status = (ts == ENS210_STATUS_OK) ? hs : ts;
s_t_data = t_data; s_h_data = h_data;
}
物理量换算
float ENS210_GetTemperatureC(void)
{
/* t_data 单位 1/64 K; 273.15 * 64 = 17481.6 */
return ((float)(s_t_data & 0xFFFFU)) / 64.0f - 273.15f;
}
float ENS210_GetHumidityPercent(void)
{
return ((float)(s_h_data & 0xFFFFU)) / 512.0f;
}
调试结果

心得体会
本项目顺利构建了基于STM32开发平台与ENS210传感器的温湿度监测系统。通过此项目的实践,我们深入掌握了ENS210传感器的性能特性及操作方法,透彻理解传感器应用的核心流程,熟练掌握了利用arduino库实现高效快速移植开发的技术要领,并积累了嵌入式系统调试及问题解决的宝贵经验。