M-Design设计竞赛 - 基于BLE和微信小程序的简易温湿度计
该项目使用了arduino nano matter开发板和之前硬禾赠送的传感器扩展板,实现了BLE传输温湿度数据并且可以控制板载小灯的设计,它的主要功能为:nano开发板通过i2c接口获取板载温湿度传感器NSTH30温湿度数据采集并通过蓝牙BLE上传到微信小程序并动态展示。微信小程序也有开关按钮可以控制板载的LED小灯。
标签
BLE
温湿度传感器
传感器扩展板
NSHT30
M-Design
murongxuehua
更新2025-04-01
16

项目背景

感谢贸泽和硬禾联合举办的M-Design活动,本项目完成的任务方向是 方向三:无线通信、物联网 -> 蓝牙。具体实现的功能是arduino nano开发板通过i2c接口获取板载温湿度传感器NSTH30温湿度数据采集并通过蓝牙BLE上传到微信小程序并动态展示。微信小程序也有开关按钮可以控制板载的LED小灯。


系统框图:

image.png


程序流程图:

image.png

主要模块介绍:

主控单元Arduino Nano Matter开发板:

Arduino Nano Matter 板采用 SiLabs MGM240SD22VNA 微控制器构建,该微控制器包含一个运行频率高达 78MHz 的 32 位 Arm Cortex-M33 内核,并具有数字信号处理(DSP)和浮点单元(FPU)加速功能。板载 256kB 静态随机存取存储器(SRAM)和 1536kB 大容量闪存,以及 IEEE 802.15.4 和蓝牙 5.3 低功耗(BLE)无线电模块,前者支持 Thread 等协议,后者支持蓝牙 Mesh。


该板采用面包板友好型设计,具有 22 个外露的通用输入 / 输出(GPIO)引脚,所有引脚均支持外部中断和脉冲宽度调制(PWM)输出,但同时只能使用五个 PWM 输出。20 个引脚可作为 12 位模数转换器(ADC)的输入,其中四个引脚可提供 8 至 12 位分辨率的数模转换(DAC)。Arduino 称,每个引脚在 3.3V 时可提供 40mA 电流和吸收 28mA 电流


需要注意的是目前这款板子有社区预览版和正式版,在购买的时候需要仔细查看一下。细微的区别在于板子能否输出5V电压,社区预览版无此功能。

在编译代码的时候,需要正确选择所使用的协议栈,否则会出现编译错误。

image.png


传感器扩展板

(资料:https://www.eetree.cn/platform/2590)是硬禾学堂推出的传感器模块,方便进行快速原型开发。

扩展板搭载了几款常见传感器和功能模块,包括为初学者准备的麦克风、蜂鸣器、、红外收发、霍尔效应开关、加热电阻,为进阶操作准备的温湿度传感器、六轴传感器、接近/环境光/IR传感器、颜色传感器。其中温湿度传感器、六轴传感器、接近传感器、颜色传感器可拆卸为单个模块,通过杜邦线等连接线延伸其使用的空间范围。出厂默认传感器正面朝上使用。若需背面朝上使用,则自行焊接排母后按指示方向插入。

本项目着重使用的是板载的纳芯微公司的NSHT30温湿度传感器。NSHT30是一款基于CMOS-MEMS的相对湿度 (%RH)和温度(T)传感器。它在单芯片上 集成了一个完整的传感器系统,包括电容式的 相对湿度传感器、COMS温度传感器和信号处 理器以及I 2 C数字通信接口,采用 2.5mm×2.5mm×0.9mm的DFN空腔封装。 其I2C接口的通信方式、极小的封装和低功耗 特性使得NSHT30可以更广泛地集成到各种应 用中。


NSHT30 有两种工作模式,其中Single shot mode 为单次测量模式,用户可发送hex code:2400(high) /240B(Medium)/2416(low)触发该模式,不同指令对应不同的可重复性配置,详见下表。

image.png

芯片接受到单次转换命令后,根据指令对应的Repeatability配置,进行一次温湿度测量,并在测量完成 后更新一次测量数据,测量数据包含温度值,温度CRC值,湿度值和湿度CRC值。用户可通过I2 C总线,从 芯片I2C地址回读6Bytes数据,根据CRC校验结果判定无异常后,根据转换公式转换为温度值,相对湿度 值;具体可参考DataSheet及Demo Code部分。

image.png

首先要初始化NSHT30,其地址为0x44:

  if (!sht31.begin(0x44)) {  // Set to 0x44 for alternate i2c addr
    Serial.println("Couldn't find SHT31");
    while (1) delay(1);
  }

/**
 * Initialises the I2C bus, and assigns the I2C address to us.
 *
 * @param i2caddr   The I2C address to use for the sensor.
 *
 * @return True if initialisation was successful, otherwise False.
 */
bool Adafruit_SHT31::begin(uint8_t i2caddr) {
  if (i2c_dev) {
    delete i2c_dev; // remove old interface
  }


  i2c_dev = new Adafruit_I2CDevice(i2caddr, _wire);


  if (!i2c_dev->begin()) {
    return false;
  }


  reset();
  return readStatus() != 0xFFFF;
}


接下来是温湿度数据的获取:

  float temperature = sht31.readTemperature();
  float humidity = sht31.readHumidity();

/**
 * Internal function to perform a temp + humidity read.
 *
 * @return True if successful, otherwise false.
 */
bool Adafruit_SHT31::readTempHum(void) {
  uint8_t readbuffer[6];


  if (!writeCommand(SHT31_MEAS_HIGHREP))
    return false;


  delay(20);


  if (!i2c_dev->read(readbuffer, sizeof(readbuffer)))
    return false;


  if (readbuffer[2] != crc8(readbuffer, 2) ||
      readbuffer[5] != crc8(readbuffer + 3, 2))
    return false;


  int32_t stemp = (int32_t)(((uint32_t)readbuffer[0] << 8) | readbuffer[1]);
  // simplified (65536 instead of 65535) integer version of:
  // temp = (stemp * 175.0f) / 65535.0f - 45.0f;
  stemp = ((4375 * stemp) >> 14) - 4500;
  temp = (float)stemp / 100.0f;


  uint32_t shum = ((uint32_t)readbuffer[3] << 8) | readbuffer[4];
  // simplified (65536 instead of 65535) integer version of:
  // humidity = (shum * 100.0f) / 65535.0f;
  shum = (625 * shum) >> 12;
  humidity = (float)shum / 100.0f;


  return true;
}


串口可以打印温湿度数据:

07:17:39.011 -> Temp *C = 14.63		Hum. % = 58.57


如果要使用BLE传输至微信小程序,还需要增加如下代码:

/**************************************************************************/ /**
 * Sends a BLE indication with the current temperature to the connected device
 * if enabled, then waits for a second
 *****************************************************************************/
static void handle_temperature_indication() {
  // Return immediately if indications are not enabled
  if (!indication_enabled) {
    return;
  }
 
  uint8_t buffer[4];
  // Get the current CPU temperature
  float temperature = sht31.readTemperature();
  float humidity = sht31.readHumidity();

  int32_t TenMillicelsius  = (int32_t)(temperature * 100);
  int32_t TenMillihumidity = (int32_t)(humidity * 100);

  buffer[0] = (uint8_t)(TenMillicelsius / 10);
  buffer[1] = (uint8_t)TenMillicelsius % 10;

  buffer[2] = (uint32_t)(humidity*100)/100;
  buffer[3] = (uint32_t)(humidity*100)%100;

  // Send the indication
  sl_bt_gatt_server_send_indication(connection_handle, temp_measurement_characteristic_handle, sizeof(buffer), buffer);

  if (! isnan(temperature)) {  // check if 'is not a number'
    Serial.print("Temp *C = "); Serial.print(temperature); Serial.print("\t\t");
  } else {
    Serial.println("Failed to read temperature");
  }
 
  if (! isnan(humidity)) {  // check if 'is not a number'
    Serial.print("Hum. % = "); Serial.println(humidity);
  } else {
    Serial.println("Failed to read humidity");
  }


  // Wait for a second
  delay(1000);
}

代码中之所以要先扩大100倍,就是想把小数部分也传输过去。


微信小程序部分主要是作为BLE 主机来扫描周围BLE设备,然后发起连接。连接成功后,作为GATT 客户端来获取GATT服务器侧的温湿度数据(特性值)。核心代码如下:

  getBLEDeviceCharacteristics(deviceId, serviceId) {
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
console.log('getBLEDeviceCharacteristics success', res.characteristics)
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i]
if (item.properties.read) {
wx.readBLECharacteristicValue({
deviceId,
serviceId,
characteristicId: item.uuid,
})
}
if (item.properties.write) {
this.setData({
canWrite: true
})
this._deviceId = deviceId
this._serviceId = serviceId
this._characteristicId = item.uuid
this.writeBLECharacteristicValue()
}
if (item.properties.notify || item.properties.indicate) {
wx.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: item.uuid,
state: true,
})
}
}
},
fail(res) {
console.error('getBLEDeviceCharacteristics', res)
}
})
// 操作之前先监听,保证第一时间获取数据
wx.onBLECharacteristicValueChange((characteristic) => {
const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId)
const data = {}
if (idx === -1) {
data[`chs[${this.data.chs.length}]`] = {
uuid: characteristic.characteristicId,
value: ab2hex(characteristic.value)
}
} else {
data[`chs[${idx}]`] = {
uuid: characteristic.characteristicId,
value: ab2hex(characteristic.value)
}
}
if(characteristic.characteristicId == '0000FE42-8E22-4541-9D4C-21EDAE82ED19' ||characteristic.characteristicId == '00002A1C-0000-1000-8000-00805F9B34FB' )
{
let dataView = new DataView(characteristic.value)
const temp = ((dataView.getUint8(0))*10 + dataView.getUint8(1))*1.0/100.0;
const hum = ((dataView.getUint8(2))*100 + dataView.getUint8(3))*1.0/100.0;
this.setData({
humidity: hum,
temperature: temp,
})
}
this.setData(data);
})
}


实物展示部分如下所示


image.png


系统上电后,打卡微信小程序,点击开始扫描,可以发现名称为“EETREE M-Design”的BLE广播名称,点击进行连接。

image.png


点击EETREE M-Desgin发起连接:

image.png


与此同时,串口也输出相应的调试信息:

Connection opened
BLE event: 0x20600A0
Value Len: 1
027
BLE event: 0x40600A0
Value Len: 1
027
BLE event: 0x80600A0
Value Len: 175
10
BLE event: 0x900A0
Value Len: 175
10
BLE event: 0x90600A0
Value Len: 0
728
BLE event: 0x20600A0
Value Len: 1
0251
BLE event: 0x20600A0
Value Len: 1
0251
Temperature indication enabled
Temp *C = 14.63 Hum. % = 58.13
BLE event: 0xA00A0
Value Len: 2
10
BLE event: 0x40600A0
Value Len: 15
00
Temp *C = 14.63 Hum. % = 58.13
Temp *C = 14.63 Hum. % = 58.14
Temp *C = 14.63 Hum. % = 58.13
Temp *C = 14.63 Hum. % = 58.15
Temp *C = 14.63 Hum. % = 58.23


除了实时温湿度蓝牙上报,还具有蓝牙开关灯的功能。

image.png



心得体会:

之前对贸泽的了解不是很多,通过这次活动也了解了更多的采购渠道,借助本次活动,成功了完成了自己对BLE传输温湿度数据的小目标。期待后续活动能够持续下去,然后借助比赛,提高自己对能力。

再次感谢硬禾和贸泽电子。


参考:

  1. 小程序部分参考了刘工(网友:lulugl)分享的小程序模板
  2. Nano Matter https://docs.arduino.cc/hardware/nano-matter/
  3. 温湿度传感器-NSHT30



附件下载
arduinocode_miniprogram.zip
团队介绍
大一新生
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号