Таймер включения нагрузки на 10 минут на ARDUINO UNO

SyrBrandon
Offline
Зарегистрирован: 18.04.2014

Добрый день.

Подскажите, как можно решить следующую задачу. Необходимо запрограммировать включение мотора от кнопки ровно на 10 минут, не используя функцию delay(), т.е. цикл loop не должен 

останавливаться. 

В любой момент двигатель можно выключить и включать этой же кнопкой, но он автоматически 

должен отключаться через 10 мин после включения. В качестве индикатора включения насоса 

будет служить индикатор LED13.

Вот моя заготовка программы:

// Таймер включения мотора на 10 минут
// 

const int  buttonPOWER = 7; // Кнопка включения  и выключения мотора, 10k на землю.
const int LedPOWER = 13;     // Выход на реле мотора

// Переменные для работы с кнопкой
int buttonStatePOWER = 0;
int old_val = 0;
int state = 0;

int StartMotor = 0;              // Маркер запуск мотора
long previousMillisMotor = 0;           // Засекаем время на момент включения Мотора

void setup() {
  pinMode(buttonPOWER, INPUT);
  pinMode(LedPOWER, OUTPUT);
  
  digitalWrite(LedPOWER, LOW);
  Serial.begin(9600); // монитор порта для диагностики
}

void loop() {


// -----Организация включения кнопки POWER с защитой от дребезга контактов---
      buttonStatePOWER = digitalRead(buttonPOWER);   
   if ((buttonStatePOWER == HIGH)&&(old_val == LOW)) {
          state = 1 - state;
          delay(200);
        }
      old_val = buttonStatePOWER;
  if (state == 1) { 
                    if ((StartMotor == 0)&&(old_val == HIGH)) { unsigned long previousMillisMotor = millis(); 
                                                                                           // Засечка времени
                                                                Serial.println("StartMotor=1");
                                                                Serial.println(previousMillisMotor); // смотрим время засечки
                                                              }
                                           StartMotor=1; 
                   } else
      { StartMotor=0; Serial.println("StartMotor=0");}

// ------------------------------------------------------- 

//--------------Управление мотором------------------------
   if (StartMotor == 1) { 
                                       digitalWrite(LedPOWER, HIGH); // включение мотора

                                      // далее, действия при включении мотора
                                      // опрос теплового и т.д.
  
                                }

}  

 

SyrBrandon
Offline
Зарегистрирован: 18.04.2014

Для этой задачи использую ARDUINO UNO R3 с контроллером ATmega8 c загруженным bootloader'om на внутренний кварц 8 МГц.

И для выключения мотора след строка
 
 if (StartMotor == 0) { 
                                digitalWrite(LedPOWER, LOW); // выключение мотора
 
// действия при выключении мотора  
  
}
 
В общем принцип действия этого скетча понятен, в данный момент он включает и выключает светодиод (он же мотор), при нажатии на кнопку pin 7. При включении мотора, на COM-порт выводится 2 строки: "StartMotor=1" и
"26449" (время засечки), при отключении на COM-порт выводится "StartMotor=0" (постоянно бежит). *Вот как бы сделать, чтобы эта строка исполнялась только один раз.
Но в этом коде не хватает условия по отключению светодиодиода по прошествию 10 минут. Была попытка использовать функцию millis() текущее время, с условием if (millis() -previousMillis >= 10 мин), т.е. при включении мотора мы засекаем время в переменную previousMillis ( unsigned long previousMillisMotor = millis(); ) , затем при наступлении условия millis() -previousMillis >= 10 мин, должно происходить отключение.
но эта связка у меня почему то не работала. Отключение не происходило. Скорее всего что то делал не так. Вот и прошу помощи, как это сделать грамотно. Готового примера на просторах интернета не нашел, возможно этот пример кому нибудь пригодится из новичков для своих творческих работ. Прошу не пинайте сильно, все мы учимся. Заранее спасибо.

 

std
Offline
Зарегистрирован: 05.01.2012

Нельзя просто так взять

и написать понятно.

 

Пробуем обдумать, чего надо от программы. Я так понимаю:

1. Вкл/выкл двигателя, + показать состояние светиком на D13. Надо: одна переменная bool.

2. Всё равно выкл через 10 минут. Надо:

- с допустимой ошибкой в единицы секунд - по millis(), то есть одна переменная unsigned long, или

- с допустимой ошибкой меньше секунды - тогда надо RTC (например 1307), часовой кварц и все дела

3. послать в сериал, по факту действия.

Итак, в случае версии с milis() будет так:

#define pin_led   (13)
#define pin_motor (12)
#define pin_btn   (7)

unsigned long last_on;
boolean state_on;

void setup(){
  pinMode(pin_led,OUTPUT);        // peripheral configuration
  pinMode(pin_motor,OUTPUT);
  pinMode(pin_btn,INPUT_PULLUP);
  Serial.begin(9600);
  last_on=0;
  state_on=false;                 // initial state (off)
  changestate();
}

void changestate(){
  digitalWrite(pin_led,state_on);
  digitalWrite(pin_led,state_on);
  if(state_on){
    Serial.println('Motor state: ON');
    Serial.print('On time:');
    Serial.println(last_on,DEC);
  }else{
    Serial.println('Motor state: OFF');
  }
  delay(1500);
}

void loop(){
  if(state_on){                        // motor on
    if(digitalRead(pin_btn)==LOW){     // button pressed
      state_on=false;
      changestate();
    }
    if(millis()-last_on>=600000){      // time expired (600000 ms = 10 min)
      state_on=false;
      changestate();
    }
  }else{                               // motor off
    if(digitalRead(pin_btn)==LOW){     // button pressed
      state_on=true;
      last_on=millis();
      changestate();
    }
  }
}

В случае версии на часах - нужна библиотека, и собсно часы. Заводим переменную типа, ну скажем long. Хотя чё мелочиться, можно и unsigned long. Читаем из часов минуты, секунды, пишем в эту переменную по формуле минуты*60+секунды. Прибавляем 600, потом каждый раз читаем из часов, считаем по той же формуле другую переменную такого же типа, сравниваем. Всё остальное будет такое же.

Delay в функции changestate() - защита от повторного срабатывания цикла, тогда следующее действие кнопки выполнится не раньше 1500 мс. Если убрать, то двиг может включиться и тут же выключиться, т. к. loop() выполняется достаточно быстро, чтобы успеть обработать условие несколько раз за то время, пока жмут кнопку.

SyrBrandon
Offline
Зарегистрирован: 18.04.2014

std, огромное спасибо за пример, пришлось немного подкорректировать код после вставки в Arduino:

     Serial.println('Motor state: ON');

    Serial.print('On time:');
    Serial.println(last_on,DEC);
  }else{
    Serial.println('Motor state: OFF');

на

Serial.println("Motor state: ON");

    Serial.print("On time:");
    Serial.println(last_on,DEC);
  }else{
    Serial.println("Motor state: OFF");

иначе вместо текста в COM порт почему то передавались какие то цифры:

17990
20302
259145616
 

благодаря вашему коду нашел у себя ошибку из за чего у меня не работало:

В секции описания переменной в моем коде было const unsigned long TimePower=1000*60*10;  10 мин.

TimePower почему то вычислялся как 10176 !

Исправил TimePower=600000; 

стало нормально

В секции управления мотором было:
 
//--------------Управление мотором------------------------
   if (StartMotor == 1) { 
                           digitalWrite(LedPOWER, HIGH); // включение мотора
                           
     //---- Функция выключения через 10 минут--------------------
                             currentTime = millis();                               // считываем текущее время
          if (currentTime >= (previousMillisMotor+TimePower)) // сравниваем текущий таймер с переменной previousMillisMotor + 10 мин.
                    {  
                           StartMotor == 0;  // Здесь тоже была ошибка StartMotor = 0; 
                           previousMillisMotor = currentTime;                       // в previousMillisMotor записываем новое значение
                    }
      //----------------------------------------------------------             
                                    

                                      // далее, действия при включении мотора
                                      // опрос теплового и т.д.
  
                                }
   if (StartMotor == 0) { 
                                       digitalWrite(LedPOWER, LOW); // выключение мотора

                                      // далее, действия при выключении мотора
                                     
  
                                }
}  

 

Здесь тоже была ошибка StartMotor == 0; 
 
Задача решена, огромное спасибо.
 
Вячеслав 151
Offline
Зарегистрирован: 25.03.2015

Добрый день!

Как ваш таймер? Откорректированный счетч можете выложить?

Ghost33
Offline
Зарегистрирован: 07.01.2018

доброго времени суток. Подскажите пожалуййста что и как делаю не так. 

Задача: включить 3 реле по температуре. Код написан на один светодио, как пример, сигнализирует о срабатывании одного реле. То есть при понижении температуры ниже 39 градусов включить реле с задержеой по времени 15 секунд первое реле, 30 секунд .
второе. 3 реле включить одновременно с первыйм, ну и чтобы вывод температуры на дисплей был постоянно


int ledPin = 6 ;  // Светодиод подключенный к вход/выходу 12

#define ONE_WIRE_BUS 5 // пин 5 к которому подключен датчик

OneWire oneWire(ONE_WIRE_BUS);  // настройка объекта oneWire для связи с любым устройством OneWire
DallasTemperature sensors(&oneWire);// передать ссылку на oneWire библиотеке DallasTemperature

void draw(void) { // настрока дисплея
  u8g.setFont(u8g_font_gdr30);
  u8g.setPrintPos(20, 31);
  u8g.print(sensors.getTempCByIndex(0));
}
void setup(void){
  sensors.begin();  // запустить библиотеку
 Serial.begin(9600);
  pinMode(ledPin, OUTPUT);      // устанавливает режим работы - выход
  digitalWrite(ledPin, LOW);  // устанавливаем в выключенное положение
}

void loop(void){
  sensors.requestTemperatures();  // отправить команду для получения температуры
  Serial.println(sensors.getTempCByIndex(0)); // напечатать температуру в градусах Цельсия
  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );
      
      while((sensors.getTempCByIndex(0) <= 30)){ // условие, температура меньше 30 сделать...
       delay(15000); // задержка времени по включению
       digitalWrite(ledPin, HIGH); //включить реле
       break; // вернуться в цикл
      }
    // while((sensors.getTempCByIndex(0) >= 30)){
    //   digitalWrite(ledPin, LOW);
    // }
  // if((sensors.getTempCByIndex(0) <= 30)) // условие, если температуру меньше указанного значения то...
  // digitalWrite(ledPin, HIGH);  // строка деййствия условия
  if((sensors.getTempCByIndex(0) >= 31)) // условие, если температуру меньше указанного значения то...
     digitalWrite(ledPin, LOW); // строка деййствия условия
  delay(500);
}

 

b707
Offline
Зарегистрирован: 26.05.2017

Ghost33 пишет:

Подскажите пожалуййста что и как делаю не так. 

все

Цитата:
Задача: включить 3 реле по температуре. Код написан на один светодио, как пример

ЭТО ПРОСТО ЛОЛ,

надо включить ТРИ РЕЛЕ, но код написан на ОДИН СВЕТОДИОД?

Цитата:
включить реле с задержеой по времени 15 секунд первое реле, 30 секунд . второе. 3 реле включить одновременно с первыйм, ну и чтобы вывод температуры на дисплей был постоянно

ага, и все это на примере одного светодиода? :)

Ghost33 - вы реально такой тупой или просто троллите форум? - в любом случае отвечать вам по существу нет смысла.

Выложите реальный код на три реле, а не "для примера". Нахрена кто-то должен тратить время на разбор "примера", не имеющего ничего общего с реальностью?