2020年7月12日日曜日

【家の自動化プロジェクト】#2 モジュールをテストしてみた

どうも。caketetuです。
前回はESP32を使ってBLE子機ユニットと拡張モジュールを作りました。
これだけではただマイコンを囲った箱ですので接続できても何もできません。
よって今回は、拡張モジュールにいくつか機能を付け足し、テストしてみよう
と思います。

前回より、以下のモジュールを追加しました。
 ・環境センサモジュール
 ・ミニI/Fパネル
 ・サブプロセッサモジュール



これが全面のミニI/Fパネルです。ここで紹介したSSD1306 OLED
ディスプレイと3つのボタン、赤青のLEDがついています。これで
単体でも最低限の操作をできるようになると思います。




モジュール右側に追加した環境センサモジュールです。使用してるセンサは
BME280とCCS811で気温、湿度、気圧、CO2濃度、総揮発性有機化合物(TVOC)
を測定できます。どちらもI2C接続なので配線は電源合わせ4線で済みます。




モジュール上側に追加したサブプロセッサモジュールです。Arduinoを
マイコン単体で動作させ、シリアル通信で接続します。ESP32はBLEを使ったとき
動作が不安定になる感じがあったので、ハードウェア制御は別のマイコンを
使うことにしました。マイコン単体をArduino化させるのはここで紹介しています。



本ユニット全体の回路としてはこんな感じになってます。本体には
デバック用として圧電ブザーを付けました。子機デバイス一つ目としては
ほとんど完成だと思います。



ここからソフトを書き込んでモジュールごとにチェックしていきます。
まずミニI/Fパネルから動かしていきます。ボタン操作でページを変える
サンプルを作ってみました。
I/Fパネルサンプルプログラム
//*********************************************************
//    Easy_IF_pannel_test
//    ESP32_Core_Unit向け簡易IFパネルテストプログラム
//    1.0   2020 7/3  作成
//*********************************************************

//==========================================================
//    Include Header
//==========================================================
#include <Wire.h>             //I2Cヘッダ(OLED)
#include <Adafruit_GFX.h>     //Adafruit グラフィックヘッダ(OLED)
#include <Adafruit_SSD1306.h> //Adafruit LCDヘッダ(OLED)

//==========================================================
//    Macro Definition
//==========================================================
//ディスプレイ関連
#define SCREEN_WIDTH 128    //OLEDピクセルX
#define SCREEN_HEIGHT 64    //OLEDピクセルY
#define OLED_RESET     -1   //OLEDリセット(本モジュールは無し)
//ピン定義
#define BUZZER_PIN 23
#define LED1 12
#define LED2 14
#define SW1 13
#define SW2 27
#define SW3 26

#define PAGE_MAX 2    //表示ページ最大
#define KEY_OFF 150   //ボタンウェイト時間

//==========================================================
//    Global Variable
//==========================================================
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);   //ディスプレイクラス
int page = 0;     //ページ


//==========================================================
//    Function Prototype
//==========================================================
void show_disp0(void);
void show_disp1(void);
void show_disp2(void);


//----------------------------------------------------------
//    Set Up Function
//----------------------------------------------------------
void setup() {
  Serial.begin(115200);   //シリアル初期化
  ledcSetup(1,12000, 8);  //ブザーPWM初期化

  //ピン設定
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
  digitalWrite(LED1,HIGH);
  digitalWrite(LED2,HIGH);
  pinMode(SW1,INPUT);
  pinMode(SW2,INPUT);
  pinMode(SW3,INPUT);

  //OLED設定
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // 失敗の時は無限ループ
  }
  display.display();      //ディスプレイ表示
  delay(1000);            //ちょっと待つ
  display.clearDisplay(); //ディスプレイクリア
  
}

//----------------------------------------------------------
//    Main Loop Function
//----------------------------------------------------------
void loop() {
  if(digitalRead(SW1)==LOW){        //ボタン1動作
    ledcAttachPin(BUZZER_PIN,1);    //ブザーピンセット
    digitalWrite(LED1,LOW);         //LED1 ON
    digitalWrite(LED2,LOW);         //LED2 ON
    ledcWriteNote(1, NOTE_C, 4);    //ブザーを鳴らす
    delay(KEY_OFF);                 //指定時間待つ(チャタリング防止)
    ledcDetachPin(BUZZER_PIN);      //ブザーピンを解除
    page++;   //次のページへ
  }else if(digitalRead(SW2)==LOW){  //ボタン2動作
    ledcAttachPin(BUZZER_PIN,1);    //ブザーピンセット
    digitalWrite(LED1,LOW);         //LED1 ON
    ledcWriteNote(1, NOTE_G, 4);    //ブザーを鳴らす
    delay(KEY_OFF);                 //指定時間待つ(チャタリング防止)
    ledcDetachPin(BUZZER_PIN);      //ブザーピンを解除
    page=0;   //最初のページに戻る
  }else if(digitalRead(SW3)==LOW){  //ボタン3動作
    ledcAttachPin(BUZZER_PIN,1);    //ブザーピンセット
    digitalWrite(LED2,LOW);         //LED2 ON
    ledcWriteNote(1, NOTE_A, 4);    //ブザーを鳴らす
    delay(KEY_OFF);                 //指定時間待つ(チャタリング防止)
    ledcDetachPin(BUZZER_PIN);      //ブザーピンを解除
    page--;   //前のページへ
  }
  
  digitalWrite(LED1,HIGH);    //LED1 OFF
  digitalWrite(LED2,HIGH);    //LED2 OFF

  if(page>PAGE_MAX) page=0;         //ページ上限
  else if(page<0) page = PAGE_MAX;  //ページ下限

  //pageによって表示を切り替え
  switch(page){
    case 0: show_disp0(); break;
    case 1: show_disp1(); break;
    case 2: show_disp2(); break;
    default: break;
  }
}

//----------------------------------------------------------
//    Show Display0 Function
//----------------------------------------------------------
void show_disp0(void){
  display.clearDisplay();   //ディスプレイクリア
  display.setTextSize(2);   //テキストサイズ設定
  display.setTextColor(SSD1306_WHITE);    //テキストカラー設定
  display.setCursor(10, 0);     //表示場所設定
  display.println(F("Page 0")); //テキスト出力
  display.display();            //画面表示
}

//----------------------------------------------------------
//    Show Display1 Function
//----------------------------------------------------------
void show_disp1(void){
  display.clearDisplay();   //ディスプレイクリア
  display.setTextSize(2);   //テキストサイズ設定
  display.setTextColor(SSD1306_WHITE);    //テキストカラー設定
  display.setCursor(10, 0);     //表示場所設定
  display.println(F("Page 1")); //テキスト出力
  display.display();            //画面表示
}

//----------------------------------------------------------
//    Show Display2Function
//----------------------------------------------------------
void show_disp2(void){
  display.clearDisplay();   //ディスプレイクリア
  display.setTextSize(2);   //テキストサイズ設定
  display.setTextColor(SSD1306_WHITE);    //テキストカラー設定
  display.setCursor(10, 0);     //表示場所設定
  display.println(F("Page 2")); //テキスト出力
  display.display();            //画面表示
}



こんな感じで動きます。画面も小さいので本当に最低限といった感じです。



次に環境センサモジュールを動かしていきます。
使用したセンサは結構有名でライブラリが豊富にそろっていますので
そちらを使っていくのが楽でしょう。私はSparkFunBME280とSparkFunCCS811
を使うことにしました。とりあえずセンサ値を垂れ流すサンプルを載せます。
//*********************************************************
//    Environmental_Sensor_Test
//    ESP32_Core_Unit向け環境センサユニットテストプログラム
//    1.0   2020 7/3  作成 BME280に対応
//    1.1   2020 7/3  作成 CCS811に対応
//*********************************************************
//==========================================================
//    Include Header
//==========================================================
#include <Wire.h>
#include "SparkFunBME280.h"
#include "SparkFunCCS811.h"

//==========================================================
//    Macro Definition
//==========================================================
#define SDA 18    //I2C SDA PIN
#define SCL 19    //I2C SCL PIN

#define BME280_ADDR 0x76    //センサアドレス BME280
#define CCS811_ADDR 0x5A    //センサアドレス CCS811

//==========================================================
//    Global Variable
//==========================================================
BME280 sen_bme280;    //センサクラス BME280
CCS811 sen_ccs811(CCS811_ADDR);    //センサクラス CCS811
//センサデータ
double temp_act = 0.0, press_act = 0.0,hum_act=0.0;
unsigned short co2=0, tvoc=0;

//==========================================================
//    Function Prototype
//==========================================================

//----------------------------------------------------------
//    Set Up Function
//----------------------------------------------------------
void setup() {
  Serial.begin(115200);   //シリアル初期化

  //I2C設定&センサ初期化
  Wire.begin( SDA, SCL, 40000);           //Pin SDA, Pin SCL, Frequency
  sen_bme280.setI2CAddress(BME280_ADDR);  //BME280 アドレスセット
  //BME280 セットアップ
  if(sen_bme280.beginI2C() == false){ 
    Serial.println("Sensor BME280 connect failed");   //エラーなら停止
    while(1);
  }
  //CCS811 セットアップ
  if (sen_ccs811.begin() == false){
      Serial.print("Sensor CCS811 connect failed");   //エラーなら停止
      while (1);
  }
  Serial.println("start ");
}


//----------------------------------------------------------
//    Main Loop Function
//----------------------------------------------------------
void loop() {
  //センサ値取得 BME280
  temp_act = sen_bme280.readTempC();
  press_act = sen_bme280.readFloatPressure();
  hum_act = sen_bme280.readFloatHumidity();

  //センサ値取得 CCS811
  if (sen_ccs811.dataAvailable()){
    sen_ccs811.readAlgorithmResults();
    co2 = sen_ccs811.getCO2();
    tvoc = sen_ccs811.getTVOC();
  }

  //シリアル出力
  Serial.print(" Humidity: ");
  Serial.print(hum_act, 0);
  Serial.print(" Pressure: ");
  Serial.print(press_act, 0);
  Serial.print(" Temp: ");
  Serial.print(temp_act, 2);

  Serial.print(" CO2: ");
  Serial.print(co2);
  Serial.print(" tVOC: ");
  Serial.print(tvoc);
  
  Serial.println();

  delay(500);   //ちょっと待つ
}

動きはこんな感じです。
値は取れているので通信はOKのようです。しかし、値は何となく違う感じ
がしています。実用にはセンサ値を分析してフィルタや補正を考えてやる
必要がありそうです。


今回、拡張モジュールを追加してIoT機器っぽくなりました。しかしこれだけではちょっと
物足りません。部屋のものをいろいろ操作できるぐらいでないとホームオートメーション
とは言えません。次回はESP32から部屋の機器を何かを操作できるようにしてみたい
と思います。





0 件のコメント:

コメントを投稿