/**************************************
電流のセンサ情報を取得してAmbientにデータを送る
**************************************/
#include <WiFi.h>
#include "Ambient.h"
volatile float coefficient; //係数
const float OFFSET_CH0 = 0.00; //CH0の補正値
const float OFFSET_CH1 = 0.00; //CH1の補正値
#define CH0_APIN 34 //センサ0のアナログピン番号:A6:34
#define CH1_APIN 35 //センサ1のアナログピン番号:A7:35
#define CH2_APIN 32 //アナログピン番号中間電位 :A4:32
volatile uint16_t value_CN2;
volatile uint32_t SquareAdd_CN0;
volatile uint32_t SquareAdd_CN1;
const uint16_t SAMPLE = 1000; //ポーリング回数:200μsごとに100サンプルで1周期(50Hz)ぶん取得する
volatile uint16_t isrCounter; //電流値のポーリング回数のカウント変数
#define WIFISSID "*****" // ルーターのSSID
#define WIFIPASS "********" // ルーターのpassword
//Ambient
WiFiClient client;
Ambient ambient;
const uint32_t channelId = *****; // AmbientのチャネルID
const char* writeKey = "****"; // ライトキー
// タイマー処理用タスク
hw_timer_t* tm0 = NULL; //timer 初期化
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
volatile boolean t0flag = true; // 割り込み待ち変数
const uint32_t DELAYTIME = 15000000; //送信頻度μsで指定
volatile uint32_t startTime;
void IRAM_ATTR WiFi_ON() {
//WiFiの接続
WiFi.begin(WIFISSID, WIFIPASS);
Serial.println(WIFISSID);
int waiting = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(100);
waiting = waiting + 1;
if (waiting >= 200) { //タイムアウト
Serial.println(F("WiFi Err ESP Reset"));
esp_restart();
}
}
Serial.println(F("----WiFi ON"));
// 本機のIPアドレスをシリアル出力
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
/*********************************************
タイマ割り込みによるポーリングでアナログ電圧値取得
*********************************************/
void IRAM_ATTR Task0() { //電流データをサンプル回数分ポーリングする
uint16_t loopTime = micros();
portENTER_CRITICAL_ISR(&timerMux); // 排他制御で下記を実行
isrCounter += 1;
//電流値値取得
uint32_t AnlogValue0 = analogReadMilliVolts(CH0_APIN) - value_CN2; //中間電位とCH1の差分を取る
uint32_t AnlogValue1 = analogReadMilliVolts(CH1_APIN) - value_CN2; //中間電位とCH2の差分を取る
//2乗した値を加算していく
if (AnlogValue0 > 0) {
SquareAdd_CN0 += +AnlogValue0 * AnlogValue0;
}
if (AnlogValue1 > 0) {
SquareAdd_CN1 += AnlogValue1 * AnlogValue1;
}
portEXIT_CRITICAL_ISR(&timerMux); // 排他制御終了
if (isrCounter >= SAMPLE) {
loopTime = micros() - loopTime;
Serial.printf("Task0 Time: %d μs\n",loopTime); //実測だと104μs
t0flag = true;
timerEnd(tm0);
tm0 = NULL;
xSemaphoreGiveFromISR(timerSemaphore, NULL); // セマフォを開放
}
}
/*********************************************
セットアップ関数
*********************************************/
void setup() {
//CTL-10-CLS 超小型クランプ式交流センサ(Φ10/80Arms)
const uint16_t RL = 100; //センサ抵抗値
const float K = 0.98; //結合係数
const uint16_t N = 3000; //巻数比
//1mVあたりの電流Io(A)
coefficient = N / RL / K / 1000; //0.030612448
Serial.begin(115200);
ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化
delay(1000);
Serial.print("coefficient: "); Serial.println(coefficient, 5);
Serial.printf("CH0:analogRead()=%d\n", (int)analogRead(CH0_APIN));
Serial.printf("CH1:analogRead()=%d\n", (int)analogRead(CH1_APIN));
Serial.printf("CH2:analogRead()=%d\n", (int)analogRead(CH2_APIN));
Serial.printf("CH0:analogReadMilliVolts()=%d mV\n", (int)analogReadMilliVolts(CH0_APIN));
Serial.printf("CH1:analogReadMilliVolts()=%d mV\n", (int)analogReadMilliVolts(CH1_APIN));
Serial.printf("CH2:analogReadMilliVolts()=%d mV\n", (int)analogReadMilliVolts(CH2_APIN));
Serial.println(F("Loop start"));
}
void loop() {
while (t0flag == true) {
startTime = micros(); // 開始時間保存
t0flag = false;
isrCounter = 0;
SquareAdd_CN0 = 0.00;
SquareAdd_CN1 = 0.00;
value_CN2 = 0;
for (int i = 0; i < 10; i++) {
value_CN2 += analogReadMilliVolts(CH2_APIN); //中間電位を取得
}
value_CN2 = value_CN2 / 10; //平均値を利用する。
Serial.printf("CH2: %d mV\n", value_CN2);
// WDT(ウォッチドックタイマ)設定
timerSemaphore = xSemaphoreCreateBinary(); //バイナリセマフォを作成
tm0 = timerBegin(0, getApbFrequency() / 1000000, true); //タイマ番号0-3まで利用可,ペリフェラル周波数:timer=1us,
timerAttachInterrupt(tm0, &Task0, true); //タイマ割り込みが入ったときにタスク実行
timerAlarmWrite(tm0, 200, true); //アラーム、引数2はμ秒で指定:200μs
timerAlarmEnable(tm0); //タイマー有効化
}
delay(110); //電圧の取得が終わるまで待つ
if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE) {
//2乗平均平方根で電流実効値を計算する。
float rms_CN0 = 0.00;
if (1.0 < SquareAdd_CN0) {
rms_CN0 = sqrt(SquareAdd_CN0 / SAMPLE);
rms_CN0 = rms_CN0 * coefficient + OFFSET_CH0;
}
float rms_CN1 = 0.00;
if (1.0 < SquareAdd_CN1) {
rms_CN1 = sqrt(SquareAdd_CN1 / SAMPLE);
rms_CN1 = rms_CN1 * coefficient + OFFSET_CH1;
}
float sumRms = rms_CN0 + rms_CN1;
Serial.print(F("Ch0: ")); Serial.print(rms_CN0); Serial.println(F(" A"));
Serial.print(F("Ch1: ")); Serial.print(rms_CN1); Serial.println(F(" A"));
Serial.print(F("ChSum: ")); Serial.print(sumRms); Serial.println(F(" A"));
WiFi_ON();
// 温度、湿度の値をAmbientに送信する
ambient.set(1, String(sumRms).c_str());
if (ambient.send()) {
Serial.println(F("ambient Send OK!"));
} else {
Serial.println(F("ambient Send NG"));
}
delay(200);
WiFi.mode(WIFI_OFF); //WiFiをOFFにして省電力
Serial.println(F("----WiFi OFF"));
//ループの設定時間から処理時間分を引いてdylayする。
uint32_t delaytaTime = micros() - startTime;
delaytaTime = (DELAYTIME - delaytaTime) / 1000;
Serial.printf("LOOPTIME: %d ms\n", (int)(DELAYTIME / 1000));
Serial.printf("DelayTime: %d ms\n", delaytaTime);
delay(delaytaTime);
}
}