Задержка иногда останавливает выполнение навсегда

У меня есть Arduino для управления системой орошения, состоящей из одного насоса (в коде он называется "бомба") и 5 водяных клапанов на 12 В.

Каждый клапан управляет одним ирригационным контуром, и идея состоит в том, чтобы открывать каждый из них последовательно в течение одной минуты, а затем переходить к следующему.

Код такой:

const int TIEMPO_RIEGO = 64; // секунды

const int TRIGGER = 5;

const int BOMBA = 6;
const int CIRCUITO_1 = 8;
const int CIRCUITO_2 = 9;
const int CIRCUITO_3 = 10;
const int CIRCUITO_4 = 11;
const int CIRCUITO_5 = 12;

const int CIRCUITOS_ACTIVOS[] = {
  CIRCUITO_1,
  CIRCUITO_2,
  CIRCUITO_3,
  CIRCUITO_4,
  CIRCUITO_5,
};

void _abrirValvula(int circuito, int t) {
    digitalWrite(circuito, HIGH);
    digitalWrite(BOMBA, HIGH);
    unsigned long waitTime = t * 1000L;
    delay(waitTime);
    digitalWrite(BOMBA, LOW);
    digitalWrite(circuito, LOW);
}

void cicloRiegoCompleto() {
  int numeroDeCircuitos = sizeof(CIRCUITOS_ACTIVOS) / sizeof(CIRCUITOS_ACTIVOS[0]);
  for (int i=0; i<numeroDeCircuitos; i++){
    _abrirValvula(CIRCUITOS_ACTIVOS[i], TIEMPO_RIEGO);
  }
}

void setup() {
  pinMode(BOMBA, OUTPUT);
  pinMode(CIRCUITO_1, OUTPUT);
  pinMode(CIRCUITO_2, OUTPUT);
  pinMode(CIRCUITO_3, OUTPUT);
  pinMode(CIRCUITO_4, OUTPUT);
  pinMode(CIRCUITO_5, OUTPUT);
  pinMode(TRIGGER, INPUT);
}

void loop() {
  if (digitalRead(TRIGGER) == HIGH) {
   cicloRiegoCompleto(); 
  }
}

К контакту 5 (ТРИГГЕР) у меня подключен raspberry pi, который также подключен к Интернету, поэтому, когда я отправляю ему сообщение с телефона, он подает на этот контакт 3,3 В и запускает процесс.

Он отлично работал около месяца, но несколько дней назад насос не остановился, когда должен был, и продолжал работать через несколько часов после запуска.

Я выдергиваю вилку из розетки, и когда я снова включаю ее, она снова исправно работает еще 2 или 3 дня.

Но сегодня это снова не прекратилось. Я проверил, что насос работал около 15 минут, пока я не вытащил пробку, и первый клапан (CIRCUITO_1) был открыт все время, похоже, что петля for застряла в первом итерация.

Может быть, это какая-то проблема с функцией delay?

По какой-то причине он ожидает намного больше, чем должен?

Иногда это работает, а иногда нет, поэтому я думаю: может быть, это какая-то странная проблема с переполнением?

, 👍2

Обсуждение

Код кажется мне законным. Можете ли вы войти в систему пи, когда именно она включает и выключает вывод? Просто посмотреть, правильно ли это работает., @chrisl

Когда у вас возникает эта проблема, каково состояние логического выхода Pi?, @Edgar Bonet

pi переводит свой выход в ВЫСОКОЕ состояние только на одну секунду, а затем снова в НИЗКОЕ значение. Но, даже если бы он был ВЫСОКИМ все время, он должен проходить через каждый клапан, а не застревать в первом навсегда., @Enuff

Как вы подключаете насосы к Arduino? Можете выложить схему? А как вы питаете насосы? Они питаются отдельно от Arduino или Arduino получает питание от той же цепи, что и насосы?, @GMc

Клапаны управляются через мосфеты IRL510 (или IRL540? сейчас не помню), помпа с реле ардуино 5В. Питается все от блока питания 15А 12В, используется понижающий для малины и питания реле. Вечером постараюсь скинуть схему., @Enuff

Это дешевый китайский nano за 1 доллар или настоящий Arduino nano?, @Majenko

Купил его на amazon.es в упаковке по 6 штук примерно за 15 евро, так что, вероятно, это китайская версия. Не знаю, как найти отличия, вот фото: https://imgur.com/03C2WyB, @Enuff

Дешевая китайская хрень. Вы знаете, *как* они получают их так дешево? Все просто: микроконтроллеры выходят из мусорного бака. Вместо того, чтобы фабрика в Китае выбрасывала их, они продавали их дешево на местном рынке. Таким образом, вы можете ожидать, что они будут некачественными и случайно выйдут из строя..., @Majenko


4 ответа


0

Он отлично работает уже месяц или около того... это заставляет меня задуматься: может быть, это какая-то странная проблема с переполнением?

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

Может быть, это какая-то проблема с функцией задержки?

Нет


Я предлагаю посмотреть на аппаратное обеспечение или код на Pi.

,

В этом есть смысл. Пи-код выглядит нормально, но должен ли я просто проверить часть схемы MOSFET или сам Arduino? Что я имею в виду: может ли Arduino каким-то образом сломаться, чтобы случайно застрять в строке кода? Или, если бы ардуино сломалось, оно бы вообще не работало?, @Enuff

Я сомневаюсь, что он "застрянет" в строке кода. Процессор работает или нет. Я бы использовал измеритель, чтобы проверить, что выходной сигнал настроен так, как вы ожидаете., @Nick Gammon


1

Основываясь на вашем опыте работы с системой и источнике Nano, лучший и самый быстрый тест, который я могу придумать, — это заменить другой Nano, чтобы выяснить, сохраняется ли проблема или исчезает.

,

1

Есть ли у вас резисторы 10 кОм между затвором и землей на полевых МОП-транзисторах? Возможно, вы страдаете от остаточного заряда на затворе MOSFET, удерживая его включенным, когда он должен быть выключен.

,

Ага, а также обратноходовые диоды на каждом клапане., @Enuff


0

Возможно, у вас возникла проблема при приведении переменной t к времени ожидания переменной. t — это целое число, а время ожидания — длинное, поэтому при умножении t на 1000L вы можете получить пару дополнительных байтов, используемых другими частями кода:

Например, если t хранится по адресу 0x100:0x101 в ОЗУ, а некоторые другие переменные или случайные данные хранятся по адресу 0x102:0x103, вы передаете 100 функции в переменной t, которая, как вы ожидаете, умножается на время ожидания как 100 000 мс или 100 с, но если данные, хранящиеся по адресу 0x102:0x103, например, имеют случайное значение 0xFFFF, умножение на время ожидания фактически дает (100*65536)+65535 = 6 619 135 мс или 1,83 часа.

Можно либо передать в функцию значение long, либо преобразовать t, чтобы оно соответствовало времени ожидания:

время ожидания = (длительное) t * 1000 л;

Обратите внимание, что порядок байтов зависит от того, как компилятор обрабатывает хранение переменных.

,

Компиляторы не перезаписывают память только потому, что вы что-то отбрасываете. Это было бы довольно плохим поведением, если бы они это сделали. Возможно, если вы приведете указатель к другому типу указателя, но это обычная переменная., @Nick Gammon

Приведение и умножение почти наверняка выполняются в регистрах, а переменная waitTime вряд ли когда-либо будет существовать отдельно, так как результат умножения будет оставлен в регистрах или сразу же помещен в стек в качестве аргумента для delay( ), и больше никогда не упоминается., @JRobert