Funpack第八期-环境监测站
基于Arduino NANO-33 BLE Sense开发板
标签
嵌入式系统
DayDay
更新2021-05-18
872

简介

基于Arduino NANO-33 BLE Sense开发板实现了一个微型环境监测站,可以检测周围温度、湿度、气压、光强和噪声,然后通过BLE功能将数据给手机,在手机微信小程序上接收数据并展示。

主要功能及代码片段

Arduino提供了丰富的例程和便捷的API,并对开发流程做了极大简化。只需要实现初始化和大循环两个函数。

void onPDMdata() {
  int bytesAvailable = PDM.available();
  if(bytesAvailable == MICROPHONE_BUFFER_SIZE_IN_BYTES)
  {
    PDM.read(microphoneBuffer, bytesAvailable);
    microphoneBufferReadyFlag = true;
  }

}

void setup() {
  //Serial.begin(9600);
  //while (!Serial);

  if (!HTS.begin()) {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }
  if (!BARO.begin()) {
    Serial.println("Failed to initialize pressure sensor!");
    while (1);
  }
  if (!APDS.begin()) {
    Serial.println("Error initializing APDS9960 sensor.");
    while (true);
  }
  PDM.onReceive(onPDMdata);
  if (!PDM.begin(1, 16000)) {
    Serial.println("Failed to start PDM!");
    while (1);
  }
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }
  BLE.setLocalName("EnvironmentMonitor");
  BLE.setAdvertisedService(envMonitorService);
  envMonitorService.addCharacteristic(temperatureChar);
  envMonitorService.addCharacteristic(humidityChar);
  envMonitorService.addCharacteristic(pressureChar);
  envMonitorService.addCharacteristic(lightIntensityChar);
  envMonitorService.addCharacteristic(noiseChar);
  BLE.addService(envMonitorService);

  BLE.advertise();
  Serial.println("Bluetooth device active, waiting for connections...");

}

初始化函数中,初始化所有需要的传感器,并开启蓝牙广播。

void updateValue()
{
  float temperature = HTS.readTemperature();
  if(temperatureChar.subscribed())
  {
    temperatureChar.writeValue(temperature);
  }
  float humidity    = HTS.readHumidity();
  if(humidityChar.subscribed())
  {
    humidityChar.writeValue(humidity);
  }
  float pressure = BARO.readPressure();
  if(pressureChar.subscribed())
  {
    pressureChar.writeValue(pressure);
  }
  int r,g,b,a;
  if (APDS.colorAvailable()) {
    APDS.readColor(r, g, b ,a);
    if(lightIntensityChar.subscribed())
    {
      lightIntensityChar.writeValue(a);
    }
  }
  int16_t micMax = 0;
  if(microphoneBufferReadyFlag)
  {
      uint16_t i;
      for(i=0;i<MICROPHONE_BUFFER_SIZE_IN_WORDS;++i)
      {
          if(microphoneBuffer[i]>micMax)
          {
            micMax = microphoneBuffer[i];
          }
      }
      if(noiseChar.subscribed())
      {
        noiseChar.writeValue(micMax);
      }
      microphoneBufferReadyFlag = false;
  }
  if(Serial)
  {
      Serial.println(temperature);
      Serial.println(humidity);
      Serial.println(pressure);
      Serial.println(a);
      Serial.println(micMax);
  }
}

void loop() {
  static long previousMillis = 0;
  BLEDevice central = BLE.central();
  if(central)
  {
    while (central.connected()) {
      long currentMillis = millis();
      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
        updateValue();
      }
    }  
  } 
}

大循环中,当BLE连接建立后,每200ms读取更新传感器数据,并通过BLE发送通知。

微信小程序代码主要逻辑是,扫描广播设备,连接Environment Monitor,连接建立服务发现后,使能所有特征值的通知。当得到通知数据,将其处理并显示。

const app = getApp()
Page({
  data: {
    devices: [],
    connected: false,
    chs: [],
  },
  startScan() {
    wx.onBluetoothDeviceFound((res) => {
      res.devices.forEach(device => {
        if (!device.name && !device.localName) {
          return
        }
        const foundDevices = this.data.devices
        const idx = inArray(foundDevices, 'deviceId', device.deviceId)
        const data = {}
        if (idx === -1) {
          data[`devices[${foundDevices.length}]`] = device
        } else {
          data[`devices[${idx}]`] = device
        }
        this.setData(data)
      })
    })
    wx.startBluetoothDevicesDiscovery({
      allowDuplicatesKey: true,
      success: (res) => {
        console.log('startBluetoothDevicesDiscovery success', res)
      },
    })
  },
  createBLEConnection(e) {
    console.log('createBLEConnection ', e)
    const ds = e.currentTarget.dataset
    const deviceId = ds.deviceId
    const name = ds.name
    wx.createBLEConnection({
      deviceId,
      success: (res) => {
        console.log('devConnected ', res)
        this.setData({
          connected: true,
          name,
          deviceId,
        })
        this.getBLEDeviceServices(deviceId)
      }
    })
    wx.stopBluetoothDevicesDiscovery()
  },
  closeBLEConnection() {
    wx.closeBLEConnection({
      deviceId: this.data.deviceId
    })
    this.setData({
      connected: false,
      chs: [],
      canWrite: false,
    })
  },
  getBLEDeviceServices(deviceId) {
    wx.getBLEDeviceServices({
      deviceId,
      success: (res) => {
        for (let i = 0; i < res.services.length; i++) {
          if (res.services[i].isPrimary) {
            this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
            return
          }
        }
      }
    })
  },
  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) {

          }
          if (item.properties.write) {

          }
          if (item.properties.notify || item.properties.indicate) {
            wx.notifyBLECharacteristicValueChange({
              deviceId,
              serviceId,
              characteristicId: item.uuid,
              state: true,
            })
          }
          const data = {}
          data[`chs[${i}]`] = {
            uuid:item.uuid,
            properties:'read:'+item.properties.read+',write:'+item.properties.write+',notify:'+item.properties.notify+',indicate:'+item.properties.indicate,
          }
          this.setData(data)
        }
      },
      fail(res) {
        console.error('getBLEDeviceCharacteristics', res)
      }
    })
    wx.onBLECharacteristicValueChange((characteristic) => {
      console.log('onBLECharacteristicValueChange ', characteristic)
      switch(characteristic.characteristicId)
      {
      case "00008000-0000-1000-8000-00805F9B34FB":
        this.setData({
          temperature: "temperature:"+new DataView(characteristic.value).getFloat32(0,true),
        })  
      break;
      case "00008001-0000-1000-8000-00805F9B34FB":
        this.setData({
          humidity: "humidity:"+new DataView(characteristic.value).getFloat32(0,true),
        }) 
      break;
      case "00008002-0000-1000-8000-00805F9B34FB":
        this.setData({
          pressure: "pressure:"+new DataView(characteristic.value).getFloat32(0,true),
        })
      break;
      case "00008003-0000-1000-8000-00805F9B34FB":
        let light = new DataView(characteristic.value).getInt32(0,true);
        if(light > 100)
        {
          this.setData({
            light: "ligth-Day:"+light,
          })
        }else
        {
          this.setData({
            light: "ligth-Night:"+light,
          })
        }
      break;
      case "00008004-0000-1000-8000-00805F9B34FB":
        let micMax = new DataView(characteristic.value).getInt32(0,true);
        let k = 5;
        this.setData({
          noise: "noise:"+ 20*Math.log10(k*micMax),
        })
      break;
      }
    })
  },  

结果演示

先给板子上电,启动微信小程序,扫描到设备后建立连接,可以看到如下数据不停变化

Frj8Qy0lyps4Zwfg6aHFWluiMxsq

白天

FtP7Cpgf7ijPBAhMGd-LLUH0CCoZ

夜晚

 

体会

第一次使用Arduino,惊叹于其API的简单易用。以前不理解为什么Arduino用C++,C++本身过于复杂,使用C++开发不会增加Arduino使用难度么?现在使用后才发现,Arduino利用一些C++的特性,将API高度简化并使之易于理解,开发者使用C++开发中,不需要涉及C++复杂的一面。

针对这一款板子,Arduino也有支持不完善的地方。不过综合来看,Arduino真的是原型开发的利器。

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