Nano every + часы реального времени (тройка) + сд-картридер (тройка)

Тема в разделе "Arduino & Shields", создана пользователем crn4, 29 сен 2021.

  1. crn4

    crn4 Нуб

    привет.

    столкнулся с непонятной для меня проблемой - делаю автополив / контроль температуры (включение реле с обогревателем), все это пишется в лог на СД карту. основная плата - nano every. часы реального времени пока в данном случае используются исключительно для получения времени, чтоб в лог писать, в дальнейшем - будут контроллировать "световой" день.

    частично все это работает хорошо. но именно частично. модуль реального времени в определенный момент вместо времени начинает выдавать белиберду:
    Код (Bash):
    01:15:20.794 -> [B]28.09.2021;23:59:15[/B];268;26.05
    ...
    01:15:26.038 -> [B]28.09.2021;23:59:20[/B];267;25.97
    ...
    01:16:05.819 -> [B]@5.@5.2165;45:0/:85[/B];268;28.85
    ...
    01:16:11.084 -> [B]@5.@5.2165;45:0/:85[/B];267;28.19
     
    закономерность появления этой белиберды я так и не осознал. пробовал разные варианты - грешил в том числе на шумы, менял питание с юсб на пины 5v&GND.

    СД ридер работает подобным образом. то работает хорошо и пишет все исправно, то в одном модуле одно сохранение данных не срабатывает, а второе срабатывает (по выводу в сериал - ридер не может получить доступ к файлу) - хотя открытие / закрытие сделано через отдельную функцию. а в определенный момент он просто записывает в файл что-нибудь типа "Statêæv˜ÊìÊ؈ÂèÊv¨ÒÚÊv¦èÂèêæv˜ÊìÊ؈ÂèÊv¨ÒÚÊv¦èÂèêæv˜ÊìÊØ€j\€j\dbljvhjt`^tpjvÐÊÂèÒÜÎ@Òæ" вместо нормальной строки.

    прикладываю скетч. сразу прошу простить за корявость - тут много артефактов для тестирования и попытки поймать ошибки.

    Код (C++):
    #include <math.h>
    //#include <GyverPower.h>
    #include <SPI.h>
    #include <SD.h>
    #include <Wire.h>
    #include "TroykaRTC.h" //библиотека для работы с часами реального времени

    // объявляем пины
    #define MOISTURE_PIN A1
    #define PUMP_PIN 9
    #define RELAY_HEAT_PIN 10
    #define RELAY_LIGHT_PIN 8
    #define TERMIST_PIN A0
    #define SD_PIN 7

    // настройки термистра
    #define TERMIST_B 4300 //конкретный тип используемого термистора
    #define VIN 5.0 // используется в расчетах температуры

    // настройки для часов реального времени
    #define LEN_TIME 12 // размер массива для времени
    #define LEN_DATE 12 // размер массива для даты
    #define LEN_DOW 12 // размер массива для дня недели

    // пользовательские настройки
    #define TEMPERATURE_TRESHOLD 29.0 // поменять на боевые условия
    #define MOISTURE_TRESHOLD 400 // 0-300 - сухая почва. требуется калибровка

    RTC_A clock;
    char time[LEN_TIME];
    char date[LEN_DATE];

    void setup() {
     
     
      pinMode(PUMP_PIN, OUTPUT);
      pinMode(RELAY_HEAT_PIN, OUTPUT);
      pinMode(RELAY_LIGHT_PIN, OUTPUT);
      Serial.begin(9600);

    //  // настройки сна
    //  power.autoCalibrate();
    //  power.setSleepMode(STANDBY_SLEEP);

      // карт-ридер
      Serial.println("Initializing SD card...");
      // если microSD-карта не была обнаружена
      if (!SD.begin(SD_PIN)) {
        Serial.println("Card failed, or not present");
        // don't do anything more:
        return;
      } else {
        Serial.println("Card initialized.");
      }

      clock.begin();
      clock.set(__TIMESTAMP__);


      SDsave("cond.csv", "Date;Time;Moisture level;Temperature");
     
      SDsave("grow_log.csv", "Date;Time;Status;Level");
    }

    void loop() {
      // считываем данные с датчика влажности почвы
      int moist_data = analogRead(MOISTURE_PIN);

      // вычисляем температуру с термисторам
      float voltage = analogRead(A0) * VIN / 1024.0;
      float r1 = voltage / (VIN - voltage);
      float temperature = 1./( 1./(TERMIST_B)*log(r1)+1./(25. + 273.) ) - 273;

      Serial.println(moist_data);
      // 0-300 сухая почва 300-600 влажная почва 600-750 вода
      if (moist_data > MOISTURE_TRESHOLD){
        moistureControl(moist_data);
      }

      // проверяем температуру и отправляем в функцию управления реле
      if (temperature >= TEMPERATURE_TRESHOLD) {
        temperature = temperatureControl();
      }

      Serial.println(temperature);
      delay(200);


      clock.read();
      clock.getTime(time);
      clock.getDate(date);
      // делаем строку для записи в лог: время - сухость почвы - температура
      String data = String(date) + ";" + String(time) + ";" + String(moist_data) + ";" + String(temperature);
      // пишем в лог с показателями
      SDsave("cond.csv", data);

      if(data){
        Serial.println("not empty");
        Serial.println(data);
      } else {
        Serial.println("empty");
      }

      Serial.println("Go to sleep...");
     
      delay(5000);

    //  power.sleepDelay(10000);
    }

    float temperatureControl() {
      digitalWrite(RELAY_HEAT_PIN, HIGH);
      Serial.println("Start heating...");

      float voltage = analogRead(A0) * VIN / 1024.0;
      float r1 = voltage / (VIN - voltage);
      float temperature = 1./( 1./(TERMIST_B)*log(r1)+1./(25. + 273.) ) - 273;

      clock.read();
      clock.getTime(time);
      clock.getDate(date);
      // делаем строку для записи в технический лог: время - тип операции - основной показатель
      String data = String(date) + ";" + String(time) + ";" + "heating is on" + ";" + String(temperature);
      delay(200);
      SDsave("grow_log.csv", data);
     
      while (temperature >= TEMPERATURE_TRESHOLD) {
        // вычисляем температуру с термисторам
        voltage = analogRead(A0) * VIN / 1024.0;
        r1 = voltage / (VIN - voltage);
        temperature = 1./( 1./(TERMIST_B)*log(r1)+1./(25. + 273.) ) - 273;

        delay(1000);
      }

      if (temperature < TEMPERATURE_TRESHOLD) {
        digitalWrite(RELAY_HEAT_PIN, LOW);
        Serial.println("temperature is ok, shut down");

        clock.read();
        clock.getTime(time);
        clock.getDate(date);
        // делаем строку для записи в технический лог: время - тип операции - основной показатель
        data = String(date) + ";" + String(time) + ";" + "heating is off" + ";" + String(temperature);
        delay(200);
        SDsave("grow_log.csv", data);
      }
      return temperature;
    }

    void moistureControl(int moistureData) {

      Serial.println("i am here");
     
      analogWrite(PUMP_PIN, 255);

      clock.read();
      clock.getTime(time);
      clock.getDate(date);
      // делаем строку для записи в технический лог: время - тип операции - основной показатель
      String data = String(date) + ";" + String(time) + ";" + "pump is on" + ";" + String(moistureData);
      delay(200);
      Serial.println(data);
      SDsave("grow_log.csv", data);
     
      delay(10000); //включаем помпу на 10 секунд
      analogWrite(PUMP_PIN, 0);

      delay(200);
     
      clock.read();
      clock.getTime(time);
      clock.getDate(date);
      // делаем строку для записи в технический лог: время - тип операции - основной показатель
      data = String(date) + ";" + String(time) + ";" + "pump is off" + ";" + String(moistureData);
      delay(200);
      Serial.println(data);
      SDsave("grow_log.csv", data);

      delay(500);
    }

    void SDsave(String filename, String data) {
      File logFile = SD.open(filename, FILE_WRITE);
      if (logFile) {
        logFile.println(data);
        logFile.close();
        Serial.println(filename + " was saved");
      } else {
        Serial.println("Error opening " + filename);
      }
    }
    подскажите, пожалуйста, куда копать, куда смотреть. все перерыл, никаких идей нет.

    p.s. на nano every не работает амперковская библиотека для RTC "из коробки" - пришлось переименовать наименование класса в библиотеке с RTC на RTC_A, так как у every RTC уже занято.

    всем спасибо.
     
  2. b707

    b707 Гуру

    может памяти не хватает? А может просто RTC задергали.
    Код совершенно жуткий. Вы его копипастом писали. что ли?
    зачем три абсолютно одинаковых процедуры измерения температуры?
    зачем пять (пять!!!) одинаковых куска записи на СД-карту?

    при этом вы каждый раз заново дергаете RTC. Вполне возможно, что от столь частых запросов модуль просто не в состоянии быстро отдать ответ - возникают артефакты.
    Надо переписать так - сначала опрос всех датчиков. потом собираем все данные в строку, ОДИН РАЗ запрашиваем время и ОДИН РАЗ пишем все на карту
     
    Последнее редактирование: 29 сен 2021
  3. crn4

    crn4 Нуб

    спасибо! буду пробовать

    я правильно понимаю (помимо рефакторинга кода, конечно же), что лучше отказаться от попытки записать в лог близкие по времени события? типа когда включилась помпа, когда отключилась (с учетом того, что между ними проходит 10 секунд)?
    конечно же, в рамках тестирования, я и температуру повышаю и помпу включаю на очень близких временных интервалах. в итоге да, получается, что на карточку пишется что-то постоянно и время, соответственно, дергается.
     
  4. b707

    b707 Гуру

    10 секунд это не близкие события. По вашему коду иногда вы читаете время с интервалом 0.2 секунды - вот это БЛИЗКИЕ события
     
  5. crn4

    crn4 Нуб

    большое спасибо за наводку. разобрался и сам понял, что написал корявейший код. сильно упростил и СД карточка начала работать как положено.

    однако с модулем RTC проблема не решилась. нет, я, конечно же, также упростил и перестал дергать его очень часто, но, кажется, что проблема не в этом - все равно выпадали артефакты, хотя я дергал время раз в 10 секунд и реже.

    решил протестировать модуль RTC на другой библиотеке. взял RTClib. сначала протестил тестовый пример из библиотеки без изменений на всей изначальной схеме. заметил, что в момент, когда трогаю термист (использую это для повышения его температуры) снова появляются артефакты:
    Код (Bash):
    01:35:33.522 -> 2021/9/30 (Thursday) 1:22:53
    01:35:33.522 ->  since midnight 1/1/1970 = 1632964973s = 18900d
    01:35:33.522 ->  now + 7d + 12h + 30m + 6s: 2021/10/7 13:52:59
    01:35:33.555 ->
    01:35:36.530 -> 2165/165/165 (Wednesday) 165:165:85
    01:35:36.564 ->  since midnight 1/1/1970 = 2282427985s = 26416d
    01:35:36.564 ->  now + 7d + 12h + 30m + 6s: 2042/5/7 12:16:31
     
    собственно изменение данных с RTC произошло ровно в момент, когда я зажал термистр (конечно же я проверил это несколько раз и это не совпадение). для чистоты эксперимента отключил все лишние датчики / пины, оставил только термистр и модуль RTC. ситуация повторяется.
    не всегда это происходит ровно в момент прикосновения к термистру, но чаще всего.

    термистр подключен с делителем напряжения на 10 кОм (термистр B57164-K 103-J) на пин А0. RTC подключен через А4, А5, как SDA SCL. питание платы от юсб, хотя пробовал и от внешнего через пин 5v - ситуация повторяется

    есть какие-нибудь идеи, куда смотреть в этот раз?

    еще раз спасибо :)
     
  6. ANTISPAM

    ANTISPAM Нуб


    Как я понимаю идут наводки от прикосновения? Если так, то нужно колдовать с железом, а именно ставить фильтр и скорее всего на термистр, ведь именно он даёт наводки на все железо.
     
  7. Airbus

    Airbus Радиохулиган Модератор

    [​IMG]
     
  8. crn4

    crn4 Нуб

    проблема решилась изменением библиотеки. долго копал тему с наводками, все оказалось ок.
    использовал амперковскую библиотеку, где-то ее даже пришлось поправить (почему-то она некорректно считала год). и вот в определенный момент появлялись такие артефакты. жаль, но с самой библиотекой не захотелось разбираться, может быть это какие-то особенности nano every как другого чипа и поэтому появляется такая фигня.
    заменил на RTClib и все заработало без проблем