Как повысить стабильность работы программы?

olderman
Offline
Зарегистрирован: 08.10.2017

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

Вот последний скетч: 

#include <avr/sleep.h>
 
int wakePin2 = 2;                 // Пин используемый для просыпания (прерывания по входу)
int wakePin3 = 3;                // Пин используемый для просыпания (прерывания по выходу)
int sleepStatus = 0;             // Переменная для хранения статуса (спим, проснулись) - не используется в коде                 // Счетчик
int LedPin = 13;                 // Светодиод для оценки состояния процессора
int chel;                        //количество народа на кухне
volatile int A;                  //1 если вход 2
volatile int B;                  //1 если выход 3
unsigned int  times = 250000;    //временная задержка
 
void wakeUpNow2()                // Прерывание при входе
{
  noInterrupts();                 //на всякий случай отключаю остальные прерывания
  if (sleepStatus)               // Если мы спали,
  {
    sleep_disable();             // то первое, что нужно сделать после просыпания - выключить спящий режим
    digitalWrite(LedPin, HIGH); // Включаем светодиод - проснулись
    A = 1;                      //есть вход
    sleepStatus = 0;
    delayMicroseconds(times);  // В переменную заносим статус бодрствования
    interrupts();              //разрешаем прерывания
  }
}
 
void wakeUpNow3()                 // Прерывание при выходе
{
  noInterrupts();               //на всякий случай отключаю остальные прерывания
  if (sleepStatus)               // Если мы спали,
  {
    sleep_disable();             // то первое, что нужно сделать после просыпания - выключить спящий режим
    digitalWrite(LedPin, HIGH);  // Включаем светодиод - проснулись
    B = 1;                      // есть выход
    sleepStatus = 0;             // В переменную заносим статус бодрствования
    delayMicroseconds(times);    //задержка
    interrupts();               //разрешаем прерывания
  }
 
}
 
void setup()
{
  pinMode(LedPin, OUTPUT);
  digitalWrite(LedPin, HIGH);                // Включаем светодиод
  pinMode(wakePin2, INPUT);             //вход для перывания по входу
  digitalWrite(wakePin2, HIGH);        //подтяжка к 5 в.
  pinMode(wakePin3, INPUT);           //вход для перывания по выходу
  digitalWrite(wakePin3, HIGH);        //подтяжка к 5 в.
  attachInterrupt(0, wakeUpNow2, FALLING); // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow2 (прерывание вызывается только при смене значения на порту с HIGH на LOW - подтянуть ногу 2 на 5в.)
  attachInterrupt(1, wakeUpNow3, FALLING); // Используем прерывание 1 (pin 3) для выполнения функции wakeUpNow3 (прерывание вызывается только при смене значения на порту с HIGH на LOW - подтянуть ногу 3 на 5в.)
  pinMode(4, OUTPUT);//выход
  pinMode(5, OUTPUT);//1
  pinMode(6, OUTPUT);//2
  pinMode(7, OUTPUT);//3
  pinMode(8, OUTPUT);//4
  pinMode(13, OUTPUT);
  chel = 0;
  digitalWrite(4, HIGH); //гасим свет
 
}
 
void sleepNow()         // Функция увода ардуины в спячку.
{
  digitalWrite(LedPin, LOW);             // Выключаем светодиод, процессор спит
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // Здесь устанавливается режим сна
  sleep_enable();                        // Включаем sleep-бит в регистре mcucr. Теперь возможен слип
 
  sleepStatus = 1;                       // В переменную заносим статус сна
 
  sleep_mode();                          // Здесь устройство перейдет в режим сна!!!
  // -----------------------------------------------ПОСЛЕ ПРОСЫПАНИЯ ВЫПОЛНЕНИЕ КОДА ПРОДОЛЖИТСЯ ОТСЮДА!!!
 
}
 
void loop()
{
  delay(500);
 
  if (A == 1)    // есть вход
  {
    chel++;
    digitalWrite(4, LOW); // включаем свет
    A = 0;
  }
  if (B == 1)   //есть выход 
  {
    chel--;
  if (chel <= 0)
  {
    chel = 0;
    digitalWrite(4, HIGH); //выключаем свет
  }
  B = 0;
}
// дальше для наладки добавил индикацию работы устройства
 
if (chel == 0)
{
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
}
 
if (chel == 1)
{ digitalWrite(5, LOW);//синий многоцветный
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
}
if (chel == 2)
{ digitalWrite(6, LOW);//зеленый многоцветный
  digitalWrite(5, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
}
if (chel == 3)
{ digitalWrite(7, LOW);//красный многоцветный
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(8, HIGH);
}
if (chel >= 4)
{ digitalWrite(8, LOW); //другой красный
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
}
sleepNow();     // Вызов функции sleep() для засыпания
 
}
Десяток -другой входов-выходов отрабатывает отлично, вдруг реле издает двойной щелчок и не включается свет и диод показывает отсутствие человека, хотя он прошел. А самое странное, что иногда одновременно загораются два светодиода на ногах 8 и 5 хотя в программе это не возможно.
Как повысить стабильность работы?
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

olderman пишет:

Как повысить стабильность работы?

Написать её по-человечески.

А прежде, чем публиковать код на форуме, ознакомиться с его (форума) правилами.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

olderman пишет:

А самое странное, что иногда одновременно загораются два светодиода на ногах 8 и 5 хотя в программе это не возможно.

 
olderman пишет:
 
if (chel == 0)
{
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
}
if (chel == 2)
{ digitalWrite(6, LOW);//зеленый многоцветный
  digitalWrite(5, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
}
if (chel == 3)
{ digitalWrite(7, LOW);//красный многоцветный
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(8, HIGH);
}

 

olderman
Offline
Зарегистрирован: 08.10.2017

???

Светодиоды загораются при низком уровне.

Единственный вариант, это сброс устройства. Может быть тут какая нибудь причина кроме перебоев в питании?

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

olderman пишет:

Светодиоды загораются при низком уровне.

И откуда это людям знать? Там у вас черт знает что в железе может наворочено, а люди должны тут сидеть код кривой смотреть. Может датчики затеняются или попугай летает там. С делаями все равно не получится чего-то путнего, особенно с прерываниями в которых делай (который поидее не должен в них вообще срабатывать)

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

к тому же "А" обнуляется в иф, "В" обнуляется за иф, т.е. каждый цикл. Вот если человек выйдет между "}" и "B=0" что будет? "В" установится в 1 и тут же сбросится в 0.

olderman
Offline
Зарегистрирован: 08.10.2017

О задержка.

В документации написано, что задержки в микросекундах работают внутри обработчиков прерываний. Но тоже есть странность.  Они предполагались для того, чтобы не было прерывания от второго датчика. Сработал датчик входа -прерывания от выходного отключаются на время и наоборот. Казалось бы, чем она больше, тем меньше шансов, чтто за время прохода сработает второй датчик. Так нет. Наиболее стабильно схема работает при задержке в 200000 микросекунд. если поставить больше 300000 или меньше 150000 счетчик работает очень неустойчиво.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Да и еще, если память не изменяет, то даже при запрещенных прерываниях, само событие прерывания все равно наступает, выставляется флаг и оно будет обработано после того как разрешите прерывания.

olderman
Offline
Зарегистрирован: 08.10.2017

Спасибо за совет

Почитаю про флаги. Интересно, можно ли во время обработки прерывания очистить флаги от других прерываний.

Я начинающий ардуинщик. Последний раз программировал на бэйсике и ассемблере 30 лет назад. Приобщаю внуков к этой теме. Спасибо.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Проще для начала в прерывании запоминать "момент" когда наступило прерывание "вход" и "выход" и если между ними меньше чем надо то просто в лупе не выполнять соответствующий if и обнулять A или B.

Убрать все делаи, просто убрать и все и копать дальше.