[经验分享] 【2024 DigiKey 创意大赛】会议声源追踪器 会议室环境检测(2)

左手阿飞   2024-10-22 15:30 楼主

这次打算做一个会议拾音系统,主要功能如下:

1、声源定位,识别声音方向;(麦克风阵列,控制器)

2、声源追踪,用步进电机控制麦克风方向,追踪声源,减少干扰噪声;(麦克风阵列,控制器)

3、检测会议室环境,上传云端,可以提醒工作人员提前开启空调等设备。(传感器、ESP32)。

 

上一次发帖,通过DHT11进行温湿度检测,并上传到阿里云,通过手机可以查看。

本次增加了SGP30,进行TVOC和CO2检测并上传阿里云。

一、SGP30基本参数:

SGP30通过I2C通信,并且可以采集的数据有CO2和TVOC的含量。TVOC是“Total Volatile Organic Compounds”,意思是总挥发性有机化合物。

1、TVOC输出范围  0~·60000,CO2输出范围400~60000,IIC地址0x58。

2、数据格式:6个字为一组,每3个字为一个数据:前两个字为数据内容,第三个字为CRC校验。

图片.png

图片.png    

图片.png  

二、软件实现:

代码如下:

1、包含库函数:

图片.png  

2、IIC引脚定义:

图片.png  

3、声明一个类:

图片.png  

4、初始化:

图片.png  

5;检测TVOC和CO2:

图片.png  

6、上传到阿里云:

图片.png  

三、效果展示:

1、硬件连接:内部已经有上拉电阻,使用IIC连接时,不再外加上拉电阻,也可以正常工作。

图片.png  

图片.png  

2、阿里云后台数据显示:

(1)正常数据显示:

图片.png

    (2)吹气后,数据显示:

图片.png   (3)手机APP数据显示:

图片.png  

附代码:

#include <Arduino.h>
#include <WiFi.h>
#include "PubSubClient.h"
#include "DHT.h"
#include "ArduinoJson.h"
#include "Adafruit_SGP30.h"

#define DHTPIN 4
#define LED 38
#define DHTTYPE DHT11

#define SCL 20
#define SDA 21

DHT dht(DHTPIN,DHTTYPE) ;

#define WIFI_SSID         "HONOR 200 Pro"
#define WIFI_PASSWORD     "87654321"

#define PRODUCT_KEY       "a1H4kfnF05D"
#define DEVICE_NAME       "ESP32S3Test"
#define DEVICE_SECRET     "c0fcb349106f4730b6358b62320f4aab"
#define REGION_ID         "cn-shanghai"


#define MQTT_SERVER                  PRODUCT_KEY".iot-as-mqtt."REGION_ID ".aliyuncs.com"
#define MQTT_PORT                    1883
#define MQTT_USERNAME                DEVICE_NAME"&"PRODUCT_KEY

#define CLIENT_ID                    "a1H4kfnF05D.ESP32S3Test|securemode=2,signmethod=hmacsha256,timestamp=1729067953966|"
#define MQTT_PASSWD                  "252b17f2417acf371e14d0d1f3ac85d070ea49960db96f001ff33b1eafbe1bc0"
#define ALINK_BODY_FORMAT            "{\"id\":\"ESP32S3Test\",\"version\":\"1.0\",\"method\":\"thing.event.property.post\",\"params\":%s}"
#define ALINK_TOPIC_PROP_POST        "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"

const char* topic="/sys/a1H4kfnF05D/ESP32S3Test/thing/service/property/set";

unsigned long lastMs=0;


Adafruit_SGP30 sgp;

/* return absolute humidity [mg/m^3] with approximation formula
* @param temperature [°C]
* @param humidity [%RH]
*/
uint32_t getAbsoluteHumidity(float temperature, float humidity) {
    // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
    const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
    const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
    return absoluteHumidityScaled;
}

WiFiClient espClient;
PubSubClient client(espClient);

float soil_data;
float tep;

float TVOC_data;
uint32_t CO2_data;


void TVOC_CO2()
{
  int counter = 0;
  if (! sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
    return;
  }
  Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
  Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");
 
  if (! sgp.IAQmeasureRaw()) {
    Serial.println("Raw Measurement failed");
    return;
  }
  Serial.print("Raw H2 "); Serial.print(sgp.rawH2); Serial.print(" \t");
  Serial.print("Raw Ethanol "); Serial.print(sgp.rawEthanol); Serial.println("");
 
  delay(1000);
 
  counter++;
  if (counter == 30) {
    counter = 0;
 
    uint16_t TVOC_base, eCO2_base;
    if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
      Serial.println("Failed to get baseline readings");
      return;
    }
    Serial.print("****Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX);
    Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX);
  }
}



void wifiInit()
{
  WiFi.begin(WIFI_SSID,WIFI_PASSWORD);
  while(WiFi.status()!=WL_CONNECTED)
  {
    delay(500);
    Serial.println("WiFi not Connect");
  }


}


void mqttCheckConnect()
{ 
  while(!client.connected())
  {
    Serial.println("Connect to MQTT Server...");
    if(client.connect(CLIENT_ID,MQTT_USERNAME,MQTT_PASSWD))
    {
      Serial.println("MQTT Connected!");
    }
    else{
      Serial.print("MQTT Connect err..");
      Serial.println(client.state());
      delay(5000);
    }


  }


}

void mqttIntervalPost()
{
    char param[32];
    char jsonBuf[128];
    
    //upload humidity
    soil_data = dht.readHumidity();   
    sprintf(param, "{\"humidity\":%2f}", soil_data);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    boolean b = client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    if(b){
      Serial.println("publish Humidity success"); 
    }else{
      Serial.println("publish Humidity fail"); 
    }

    // Upload temperature
    tep =dht.readTemperature();
    sprintf(param, "{\"temperature\":%2f}",tep);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    boolean c = client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    if(c){
      Serial.println("publish Temperature success"); 
    }else{
      Serial.println("publish Temperature fail"); 
    }

    // Upload TVOC
    TVOC_data =sgp.TVOC;
    sprintf(param, "{\"tvocCurrent\":%2f}",TVOC_data);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    boolean d = client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    if(d){
      Serial.println("publish tvocCurrent success"); 
    }else{
      Serial.println("publish tvocCurrent fail"); 
    }

    // Upload CO2
    CO2_data =sgp.eCO2;
    sprintf(param, "{\"coCurrent\":%2d}",CO2_data);
    sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
    Serial.println(jsonBuf);
    boolean e = client.publish(ALINK_TOPIC_PROP_POST, jsonBuf);
    if(e){
      Serial.println("publish coCurrent success"); 
    }else{
      Serial.println("publish coCurrent fail"); 
    }
}

//回调函数
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);   // 打印主题信息
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]); // 打印主题内容
  }
  Serial.println();

 DynamicJsonDocument doc(1024);  //创建了一个名为 doc 的动态 JSON 文档
 deserializeJson(doc, String((char *)payload));  //从一个名为 payload 的数据中解析 JSON 数据并将其填充到 doc 中

// DynamicJsonDocument params = doc["params"];

if(doc["params"].containsKey("deng"))
{
  Serial.println("GOT DENG CMD"); 
  digitalWrite(LED, doc["params"]["deng"]);
}

}

void setup() {

  pinMode(LED,OUTPUT);

  Serial.begin(115200);
  dht.begin();
  wifiInit();
  Wire.begin(SDA,SCL);

  client.setServer(MQTT_SERVER, MQTT_PORT);   /* 连接MQTT服务器 */
  client.setCallback(callback); 

  digitalWrite(LED,LOW);

  if (! sgp.begin())
  {
    while (1);
  }
  Serial.print("Found SGP30 serial #");
  Serial.print(sgp.serialnumber[0], HEX);
  Serial.print(sgp.serialnumber[1], HEX);
  Serial.println(sgp.serialnumber[2], HEX);



}

void loop() {
  TVOC_CO2();
    if (millis() - lastMs >= 5000)
    {
        lastMs = millis();
        mqttCheckConnect(); 
        /* 上报 */
        mqttIntervalPost();
    }
    client.loop();
    delay(2000);


}

 

本帖最后由 左手阿飞 于 2024-10-22 15:44 编辑

回复评论 (2)

这次测试增加了SGP30,进行TVOC和CO2检测,看起来是成功的

点赞  2024-10-23 07:29
引用: Jacktang 发表于 2024-10-23 07:29 这次测试增加了SGP30,进行TVOC和CO2检测,看起来是成功的

重点在声源定位,能找到的例程不多,还需要努力。

点赞  2024-10-23 17:15
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复