Зависание arduino uno

Здравствуйте, делаю проект, в котором arduino uno обрабатывает данные с датчиков движения и включает свет, а также контролирует температуру в бочке с водой. Я заметил, что при контроле температуры( то есть при выполнении функций handleTemperature() и resetTemperatureControl() ардуино зависает и прекращает выполнение инструкций. Компилятор пишет мне следующее:
Sketch uses 14238 bytes (44%) of program storage space. Maximum is 32256 bytes.
Global variables use 586 bytes (28%) of dynamic memory, leaving 1462 bytes for local variables. Maximum is 2048 bytes.
Вот код:

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Dusk2Dawn.h>

#define ONE_WIRE_BUS 7 // пин термометра

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensor(&oneWire);

const float gisterezis = 1.2; // гистерезис

static const uint8_t RXPin = 10, TXPin = 11; // rx, tx для gps датчика
static const uint32_t GPSBaud = 9600; // "боды" для работы с последовательным портом gps

TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

Dusk2Dawn MyTown(50.06, 43.2379, +3);

uint16_t now_minutes = 0;
uint32_t now_seconds = 0;
uint16_t previousMinutes = 0;
uint32_t lamp_seconds = 0;
uint16_t SunriseMinutes = 0;
uint16_t SunsetMinutes = 0;

uint8_t minute = 0;
uint8_t hour = 0;
uint8_t month = 0;
uint16_t year = 0;
uint8_t day = 0;
uint8_t seconds = 0;

float temperature = 0;
float target_temperature = 0;


void setup() {
  pinMode(4, INPUT_PULLUP); // пин датчика движения
  pinMode(6, OUTPUT); // пин реле лампочки
  ss.begin(GPSBaud);
  sensor.begin();
  Serial.begin(9600);
  sensor.setResolution(12);
  pinMode(8, INPUT_PULLUP); // пин АП для определения включён душ или нет
  pinMode(A1, INPUT); // пин потенциометра
  pinMode(5, OUTPUT); // пин пускателя, который замыкает цепь на ТЭН
  pinMode(9, OUTPUT); // пин светодиода
  pinMode(13, OUTPUT); // пин подачи напряжения на термометр
  pinMode(0, OUTPUT); // 

}

void loop() {

  processGPS(); // Обработка данных GPS
  
  if (gps.date.isValid() && gps.time.isValid() && gps.date.day() != 0) {
    updateTimeAndSunriseSunset();
  }

  if (digitalRead(8) == LOW) {
    handleTemperature();
  } else {
    resetTemperatureControl();
  }

  controlLamp();
  
  checkNewDay();
}

void processGPS() {
  while (ss.available()) {
    gps.encode(ss.read());
  }
}

void updateTimeAndSunriseSunset() {
  minute = gps.time.minute();
  hour = gps.time.hour();
  day = gps.date.day();
  month = gps.date.month();
  year = gps.date.year();
  seconds = gps.time.second();
  
  SunriseMinutes = MyTown.sunrise(year, month, day, false);
  SunsetMinutes = MyTown.sunset(year, month, day, false);

  hour += 3; // Часовой пояс Волгоградской области

  now_minutes = hour * 60 + minute;
  now_seconds = hour * 3600 + minute * 60 + seconds;
}

void handleTemperature() {
  target_temperature = float(10) * (analogRead(A1)) / float(1023) + 33;

  if (now_minutes - previousMinutes >= 5) {
    previousMinutes = now_minutes;
    digitalWrite(13, HIGH);
    sensor.requestTemperatures();
    temperature = sensor.getTempCByIndex(0);

    if (temperature < target_temperature - gisterezis && temperature > 9) {
      digitalWrite(5, HIGH);
      digitalWrite(9, LOW);
    } else if (temperature > target_temperature && temperature > 9) {
      digitalWrite(5, LOW);
      digitalWrite(9, HIGH);
    }

    if (temperature < 0) {
      digitalWrite(5, LOW);
    }
  } else {
    digitalWrite(13, LOW);
  }
}

void resetTemperatureControl() {
  digitalWrite(5, LOW);
  digitalWrite(9, LOW);
  digitalWrite(13, LOW);

}

void controlLamp() {
  if (digitalRead(4) == LOW && (now_seconds - lamp_seconds >= 90)) {
    digitalWrite(6, LOW);
  }

  if (digitalRead(4) == HIGH && (now_minutes >= SunsetMinutes || now_minutes <= SunriseMinutes)) {
    digitalWrite(6, HIGH);
    lamp_seconds = now_seconds;
  }
}

void checkNewDay() {
  if (now_seconds < lamp_seconds) {
    lamp_seconds = now_seconds;
  }

  if (now_minutes < previousMinutes) {
    previousMinutes = now_minutes;
  }
}

P.S. зависание происходит не всегда, а абсолютно случайно - невозможно определить закономерность

Как проявляется “зависание” и где схема?

Схему сейчас начерчу, зависание проявляется так: лампочка если была включена, так и остаётся включённой, а если не была - не включается. То есть все состояния пинов(HIGH или LOW) сохраняются и висят так до момента перезапуска. Не думаю, что проблема в переполнении оперативной памяти

Когда нет приема GPS наверное?

Нет, приём gps в этот момент происходит, я проверял это путём вывода данных через последовательный порт

У вас контроля времени кроме спутника в программе нет. Если нет спутников - ничего не работает.
Ненадежное решение.

Выдели пин под alive светодиод, который раз в 5 секунд будет вспыхивать на 50мс. Будешь видеть когда зависло. Вообще, сначала выкини всё лишнее из кода, оставь минимальную функциональность, например, с выводом в Serial, а потом наращивай поблочно и смотри за поведением.

1 лайк

Как по мне - библиотека <DallasTemperature.h> может блокировать, пробуйте запустить код без опроса датчика, с постоянным значением темп-ры


Прилагаю схему.

Хорошо, спасибо. Попробую

Нет. Ардуино зависает намертво. Тут дело не в gps, поскольку я пробовал подключать другие функции, не требующие контроля времени, и они не работали

void loop() {
  if(ss.available()){
  processGPS(); // Обработка данных GPS
  }

Правильно ли я понял, что “другие функции” останавливаются, а GPS продолжает работать и выдавать в Сериал данные? - тогда это не называется “зависание”
Или не так?

Ой, что-то я запутался… В общем, приём от gps почти всегда стабильный, если же его нет, разумеется, управление лампой и управление ТЭНом происходит некорректно. Однако зависание здесь не связано с данными со спутников, поскольку arduino даже прекращает выводить информацию в последовательный порт(в этом коде нет блока с serial.println(), но представьте, что он есть)). Если бы ардуино не зависла и данных от gps не было, то вывод информации в последовательный порт бы осуществлялся, но, например, переменная day была бы равна нулю.

останавливается выполнение абсолютно всего кода

пробовал, зависание связано не с этим

Реле отключи.

тут не пробовать надо, а ставить контрольные точки на входе-выходе из подпрограм (в монитор порта гнать) и смотреть где зависло

1 лайк

Стало быть совет о переписывании кода с постепенным добавлением функционала таки становится все более актуальным

1 лайк