Пример создания скетча датчика тока GY712 для MySensors

О программировании Arduino, использование библиотек, примеры и общие вопросы программирования.
Ответить
Mikhail72
Сообщения: 18
Зарегистрирован: 04 окт 2017, 06:02
Откуда: Тюмень
Контактная информация:

Пример создания скетча датчика тока GY712 для MySensors

Сообщение Mikhail72 »

Обратился к сообществу человек, с вопросом: "Есть ли скетч для работы датчика тока GY712 с передачей данных по протоколу MySensors". И я решил создать пост с примером, как создать свой скетч для работы с MyS, на основании скетча найденного в сети и руководства по созданию сообщений для отправки. И так имеем:

Код: Выделить всё

#define CURRENT_SENSOR A0 // Analog input pin that sensor is attached to
 
float amplitude_current;               //amplitude current
float effective_value;       //effective current 
 
void setup() 
{
    Serial.begin(9600); 
    pins_init();
}
void loop() 
{
    int sensor_max;
    sensor_max = getMaxValue();
    Serial.print("sensor_max = ");
    Serial.println(sensor_max);
    //the VCC on the Grove interface of the sensor is 5v
    amplitude_current=(float)(sensor_max-512)/1024*5/185*1000000;// for 5A mode,you need to modify this with 20 A and 30A mode; 
    effective_value=amplitude_current/1.414;
    //minimum_current=1/1024*5/185*1000000/1.414=18.7(mA)
    //Only for sinusoidal alternating current
    Serial.println("The amplitude of the current is(in mA)");
    Serial.println(amplitude_current,1);//Only one number after the decimal point
    Serial.println("The effective value of the current is(in mA)");
    Serial.println(effective_value,1);
}
void pins_init()
{
    pinMode(CURRENT_SENSOR, INPUT);
}
/*Function: Sample for 1000ms and get the maximum value from the S pin*/
int getMaxValue()
{
    int sensorValue;             //value read from the sensor
    int sensorMax = 0;
    uint32_t start_time = millis();
    while((millis()-start_time) < 1000)//sample for 1000ms
    {
        sensorValue = analogRead(CURRENT_SENSOR);
        if (sensorValue > sensorMax) 
        {
            /*record the maximum sensor value*/
            sensorMax = sensorValue;
        }
    }
    return sensorMax;
}
тремя звёздочками и между множеством звёздочек отмечены строки, которые были добавлены мной в приведённый выше скетч

Код: Выделить всё

#define MY_DEBUG                                   // *** Вывод отладочной информации в сериал
#define MY_RADIO_NRF24                             // *** Радио
//#define MY_NODE_ID 1                             // *** Номер ноды выдается автоматически

#include <SPI.h>                                   // *** Подключение библиотек
#include <MySensors.h>                             // ***

#define CURRENT_SENSOR A0                          // Аналоговый вход к которому подключен сенсор
#define CHILD_ID_AMPLITUDE 0                       // ***Id сенсоры ноды (0-254)
#define CHILD_ID_EFFECTIVE 1                       // ***
float amplitude_current;                           // Амплитудный ток
float old_amplitude_current;                       // *** Предыдущее значение АТ
float effective_value;                             // Еффективный ток
float old_effective_value;                         // *** Предыдущее значение ЕТ
bool Ack0, Ack1, err;                              // ***
byte count;                                        // ***

MyMessage amplmsg(CHILD_ID_AMPLITUDE, V_CURRENT);  // *** Создание контейнеров
MyMessage effmsg(CHILD_ID_EFFECTIVE, V_CURRENT);   // *** для хранения информации

void setup() 
{
  pins_init();
}

void presentation()  {                            // *** Презентация сенсоров на контроллере
  sendSketchInfo("GY712", "1.0");
 wait(20);
  present(CHILD_ID_AMPLITUDE, S_MULTIMETER, "Amplitude");
 wait(20);
  present(CHILD_ID_EFFECTIVE, S_MULTIMETER, "Effective");
}
void loop() 
{
    int sensor_max;
    sensor_max = getMaxValue();
    Serial.print("sensor_max = ");
    Serial.println(sensor_max);
    //the VCC on the Grove interface of the sensor is 5v
    amplitude_current=(float)(sensor_max-512)/1024*5/185*1000000; // Для 5А (5/185), для 20А (20/100), для 30А (30/66)
    effective_value=amplitude_current/1.414;
    // Минимальный ток=1/1024*5/185*1000000/1.414=18.7(mA)
    // Только для синусоидального переменного тока
    Serial.println("The amplitude of the current is(in mA)");
    Serial.println(amplitude_current,1);//Only one number after the decimal point
    Serial.println("The effective value of the current is(in mA)");
    Serial.println(effective_value,1);

// **********************************************************************************************************************************************************
if(amplitude_current != old_amplitude_current){                 // Если значение амплитудного тока изменилось
send(amplmsg.setDestination(0).setSensor(CHILD_ID_AMPLITUDE).set((amplitude_current),1), true);  // Отправка его данных c подтверждением доставки на контроллер
  wait(50, 1, V_CURRENT);                                       // Ждём подтверждения отправки
  wait(500, 1, V_CURRENT);                                      // Ждём подтверждения доставки
  while (Ack0 == 0) {                                           // Пока статус доставки ложь
      count++;                                                  // Включаем счётчик повторных отправок
      Serial.print("Sending a message, try No.");               // Выводим в монитор порта попытку отправки
      Serial.println(count);                                    // и её номер
      send(amplmsg.setDestination(0).setSensor(CHILD_ID_AMPLITUDE).set((amplitude_current),1), true); // Отправляем сообщение повторно
      wait(50, 1, V_CURRENT);                                   // Ждём подтверждения отправки
      wait(1000, 1, V_CURRENT);                                 // Ждём подтверждения доставки
      if (count ==  3){                                         // Если сделано 3 попытки
        err = 1;                                                // Устанавливаем флаг ошибки
        count = 0;                                              // Обнуляем счётчик
        Ack0 = 1;                                               // Выходим из цикла
        }
      }
  if ((Ack0 == 1) && (err == 1)){                               // Если выражение истина
    Serial.println("Delivery failed");                          // Выводим сообщение "Доставка не удалась"
    Ack0 = 0;                                                   // Сбрасываем флаг доставки
    err = 0;                                                    // И ошибки
  } else if ((Ack0 == 1) && (err == 0 )){                       // Иначе если выражение истина
           Serial.println("Message sent and delivered");        // Вывести в сериал "Сообщение отправлено и доставлено"
           Ack0 = 0;                                            // Сбрасываем флаг
           count = 0;                                           // Обнуляем счётчик
           old_amplitude_current = amplitude_current;           // Обновляем предыдущее значение
           }
}
if(effective_value != old_effective_value){                     // Если значение еффективного тока изменилось
 send(effmsg.setDestination(0).setSensor(CHILD_ID_EFFECTIVE).set((effective_value),1), true);  // Отправка еффективного тока c подтверждением на контроллер
  wait(50, 1, V_CURRENT);                                       // Ждём подтверждения отправки
  wait(500, 1, V_CURRENT);                                      // Ждём подтверждения доставки
  while (Ack1 == 0) {                                           // Пока статус доставки ложь
      count++;                                                  // Включаем счётчик повторных отправок
      Serial.print("Sending a message, try No.");               // Выводим в монитор порта попытку отправки
      Serial.println(count);                                    // и её номер
      send(effmsg.setDestination(0).setSensor(CHILD_ID_EFFECTIVE).set((effective_value),1), true); // Отправляем сообщение повторно
      wait(50, 1, V_CURRENT);                                   // Ждём подтверждения отправки
      wait(1000, 1, V_CURRENT);                                 // Ждём подтверждения доставки
      if (count ==  3){                                         // Если сделано 3 попытки
        err = 1;                                                // Устанавливаем флаг ошибки
        count = 0;                                              // Обнуляем счётчик
        Ack1 = 1;                                               // Выходим из цикла
        }
      }
  if ((Ack1 == 1) && (err == 1)){                               // Если выражение истина
    Serial.println("Delivery failed");                          // Выводим сообщение "Доставка не удалась"
    Ack1 = 0;                                                   // Сбрасываем флаг доставки
    err = 0;                                                    // И ошибки
  } else if ((Ack1 == 1) && (err == 0 )){                       // Иначе если выражение истина
           Serial.println("Message sent and delivered");        // Вывести в сериал "Сообщение отправлено и доставлено"
           Ack1 = 0;                                            // Сбрасываем флаг
           count = 0;                                           // Обнуляем счётчик
           old_effective_value = effective_value;               // Обновляем предыдущее значение
           }
 
 }
}
void receive(const MyMessage &message)                         // Функция обработки входящих сообщений
{
if ((message.sender == 0)&&(message.sensor == CHILD_ID_AMPLITUDE)&&(message.isAck())){
  Ack0 = 1;
}
if ((message.sender == 0)&&(message.sensor == CHILD_ID_EFFECTIVE)&&(message.isAck())){
  Ack1 = 1;
}
}

//****************************************************************************************************************************

void pins_init()
{
    pinMode(CURRENT_SENSOR, INPUT);
}
/*Function: Sample for 1000ms and get the maximum value from the S pin*/
int getMaxValue()
{
    int sensorValue;             //value read from the sensor
    int sensorMax = 0;
    uint32_t start_time = millis();
    while((millis()-start_time) < 1000)//sample for 1000ms
    {
        sensorValue = analogRead(CURRENT_SENSOR);
        if (sensorValue > sensorMax) 
        {
            /*record the maximum sensor value*/
            sensorMax = sensorValue;
        }
    }
    return sensorMax;
}
P.S. Скетч в работе не проверялся, т.к. нет данного датчика для теста. Буду рад если отзовётся тот кто сможет потестить.
Mikhail72
Сообщения: 18
Зарегистрирован: 04 окт 2017, 06:02
Откуда: Тюмень
Контактная информация:

Re: Пример создания скетча датчика тока GY712 для MySensors

Сообщение Mikhail72 »

Вот так этот же проект выглядит на FBD в программе FLprog
ACS712.jpg
ACS712.jpg (29.9 КБ) 18102 просмотра
Ну и сам проект прилагаю
serghei
Сообщения: 53
Зарегистрирован: 05 апр 2018, 09:12
Откуда: Молдова

Re: Пример создания скетча датчика тока GY712 для MySensors

Сообщение serghei »

Mikhail72 писал(а): 01 ноя 2017, 18:23 P.S. Скетч в работе не проверялся, т.к. нет данного датчика для теста. Буду рад если отзовётся тот кто сможет потестить.
Приветствую. Потестил исходный скетч , так как очень интересует тема измерения мощности на ардуино. Результат работы на выхлопе в сериале
Spoiler
Show
  • sensor_max = 517
    The amplitude of the current is(in mA)
    0.0
    The effective value of the current is(in mA)
    0.0
    sensor_max = 517
    The amplitude of the current is(in mA)
    0.0
    The effective value of the current is(in mA)
    0.0
И вот тут опять столкнулся с ситуацией : дрейф начального уровня на выходе модуля 712. Теоретически при отсутствии нагрузки мы должны получить среднюю точку при величине 512 единиц. По факту получается 517 - 520. Скорее всего это связано с не точным значением питания в 5 вольт.Приходится вводить поправочный коэффициент или вычитать 517 в строчке

Код: Выделить всё

amplitude_current=(float)(sensor_max-517)/1024*5/66*1000000;
что не есть правильно.

А следующий вопрос или даже просьба.

Для контроля постоянного тока зарядки аккумуляторов нашел сайт и код Зарядного устройства. По Вашему примеру переписал код под MySensors. Только не уверен насколько правильно.

Код: Выделить всё

/*
Измерение тока с использованием ACS712
*/

#define MY_DEBUG                                   // *** Вывод отладочной информации в сериал
#define MY_RADIO_NRF24                             // *** Радио
#define MY_NODE_ID 112                             // *** Номер ноды выдается автоматически

//#include <SPI.h>                                   // *** Подключение библиотек
#include <MySensors.h>                             // ***

#define CURRENT_SENSOR A0                          // Аналоговый вход к которому подключен сенсор
#define CHILD_ID_AMPLITUDE 0                       // ***Id сенсоры ноды (0-254)
//#define CHILD_ID_EFFECTIVE 1                       // ***


const int analogIn = A5;
int nRelayDrive = 7;

int mVperAmp = 185; //  используем 100 для модуля 20A и 66 для модуля 30A

int RawValue= 0;
int ACSoffset = 2500; 
double Voltage = 0;
double Amps = 0;
double old_Amps = 0;
boolean bCharged = false;

bool Ack0, Ack1, err;                              // ***
byte count;                                        // ***  

MyMessage amplmsg(CHILD_ID_AMPLITUDE, V_CURRENT);  // *** Создание контейнеров
//MyMessage effmsg(CHILD_ID_EFFECTIVE, V_CURRENT);   // *** для хранения информации

void setup(){ 
 //Serial.begin(9600);
 //pinMode(nRelayDrive,OUTPUT);
// digitalWrite(nRelayDrive, HIGH);
// Serial.println("BEGIN");
    pins_init();
    Serial.println("BEGIN");
 }

 void presentation()  {                            // *** Презентация сенсоров на контроллере
  sendSketchInfo("GY712", "1.0");
 wait(100);
  present(CHILD_ID_AMPLITUDE, S_MULTIMETER, "Current");
// wait(20);
 // present(CHILD_ID_EFFECTIVE, S_MULTIMETER, "Effective");
}

void loop(){ 
  if(!bCharged){  
    digitalWrite(nRelayDrive, LOW);
    delay(2000); 
    chargeBattery();
    digitalWrite(nRelayDrive, HIGH);
  }

   // **********************************************************************************************************************************************************
if(Amps != old_Amps){                 // Если значение амплитудного тока изменилось
send(amplmsg.setDestination(0).setSensor(CHILD_ID_AMPLITUDE).set((Amps),1), true);  // Отправка его данных c подтверждением доставки на контроллер
  wait(50, 1, V_CURRENT);                                       // Ждём подтверждения отправки
  wait(500, 1, V_CURRENT);                                      // Ждём подтверждения доставки
  while (Ack0 == 0) {                                           // Пока статус доставки ложь
      count++;                                                  // Включаем счётчик повторных отправок
      Serial.print("Sending a message, try No.");               // Выводим в монитор порта попытку отправки
      Serial.println(count);                                    // и её номер
      send(amplmsg.setDestination(0).setSensor(CHILD_ID_AMPLITUDE).set((Amps),1), true); // Отправляем сообщение повторно
      wait(50, 1, V_CURRENT);                                   // Ждём подтверждения отправки
      wait(1000, 1, V_CURRENT);                                 // Ждём подтверждения доставки
      if (count ==  3){                                         // Если сделано 3 попытки
        err = 1;                                                // Устанавливаем флаг ошибки
        count = 0;                                              // Обнуляем счётчик
        Ack0 = 1;                                               // Выходим из цикла
        }
      }
  if ((Ack0 == 1) && (err == 1)){                               // Если выражение истина
    Serial.println("Delivery failed");                          // Выводим сообщение "Доставка не удалась"
    Ack0 = 0;                                                   // Сбрасываем флаг доставки
    err = 0;                                                    // И ошибки
  } else if ((Ack0 == 1) && (err == 0 )){                       // Иначе если выражение истина
           Serial.println("Message sent and delivered");        // Вывести в сериал "Сообщение отправлено и доставлено"
           Ack0 = 0;                                            // Сбрасываем флаг
           count = 0;                                           // Обнуляем счётчик
           old_Amps = Amps;           // Обновляем предыдущее значение
           }
}
}

void chargeBattery(){
  do{
     RawValue = analogRead(analogIn);
     Voltage = (RawValue / 1023.0) * 5000; // Получаем  мВ
     Amps = ((Voltage - ACSoffset) / mVperAmp); 
     Serial.print("Current = "); //  показывает текущий измеренный ток
     Serial.println(Amps,3); // 3 цифры после запятой
     delay(1000);    
  }while (Amps > 0.130); 
  bCharged = true;
  Serial.println("Battery is Charged");   
}

void receive(const MyMessage &message)                         // Функция обработки входящих сообщений
{
if ((message.sender == 0)&&(message.sensor == CHILD_ID_AMPLITUDE)&&(message.isAck())){
  Ack0 = 1;
}
/*
if ((message.sender == 0)&&(message.sensor == CHILD_ID_EFFECTIVE)&&(message.isAck())){
  Ack1 = 1;
}
*/
}

void pins_init()
{
    pinMode(CURRENT_SENSOR, INPUT);
}

/*Function: Sample for 1000ms and get the maximum value from the S pin*/
int getMaxValue()
{
    int sensorValue;             //value read from the sensor
    int sensorMax = 0;
    uint32_t start_time = millis();
    while((millis()-start_time) < 1000)//sample for 1000ms
    {
        sensorValue = analogRead(CURRENT_SENSOR);
        if (sensorValue > sensorMax) 
        {
            /*record the maximum sensor value*/
            sensorMax = sensorValue;
        }
    }
    return sensorMax;
}
В коде еще есть реле , которое выключает зарядку при полном заряде аккумулятора. Можно в скетче как то добавить его работу ?

Заранее благодарен.
MySensors Гетвей на ESP8266 с веб интерфейсом + много нод на NRF52832
Ответить