Поменять положение реле после поступления команды на 5 секунд и выключить

mrw
Offline
Зарегистрирован: 14.03.2022
Всем привет!
 
Кто поможет разобраться, как сделать так, чтобы при получении команды "м" реле "включалось" на 5 секунд, потом само выключалось до следующего поступления команды "м"? После нескольких попыток, получил данный код, но он постоянно включает и выключает реле после поступления команды "м". В чем проблема и как исправить? Спасибо!

 

SoftwareSerial BTserial(12,13);

char choice;

const int loopDelay = 50;

int IgnitionPin = 10;
const long ignitionInterval = 5000;
int ignitionState = HIGH;
unsigned long previousMillis = 0;

void setup() 
{
  BTserial.begin(115200);  

  digitalWrite(IgnitionPin, HIGH);
  pinMode(IgnitionPin, OUTPUT);
}
 
void loop()
{
  if (BTserial.available())
  {
    choice = BTserial.read();
  }

  if( choice == 'm' )
  {
    ignitionState = HIGH;
    digitalWrite(IgnitionPin, ignitionState);
    ignitionCountTime = millis();
  }

  if (ignitionCountTime - previousMillis >= ignitionInterval) {

    previousMillis = ignitionCountTime;

    if (ignitionState == HIGH) 
    {
      ignitionState = LOW;
    }

    digitalWrite(IgnitionPin, ignitionState);
  }
 
 delay(loopDelay);
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Что должно происходить, если новая команда m поступит во время этих 5 секунд?

mrw
Offline
Зарегистрирован: 14.03.2022

Ничего, игнорировать эту команду. Я пытаюсь имитировать зажигание, крутить стартер 5 секунд при поступлении команды "м". 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Читайте внимательно.

После того, как команда m пришла в первый раз, и всё отработало, что будет происходить при следующем проходе loop?

Поскольку нового ничего не пришло, условие в строке №22 будет ложным и строка №24 не отработает.

А что будет с условием в строке №27? Чему сейчас равна choice? Оппа ... условие-то будет истинным и строки №№29-31 сработают! И будут срабатывать ВСЕГДА.

Вот оно у Вас и срабатывает.

mrw
Offline
Зарегистрирован: 14.03.2022

Переделал код, но теперь код работает только один раз. При поступлении новой команды "м" второй раз реле молчит.

SoftwareSerial BTserial(12,13);

char choice;

const int loopDelay = 50;

int IgnitionPin = 10;
unsigned long startTime;
unsigned long ignitionInterval = 30000;
unsigned long ignitionCountTime = 0;

void setup() 
{
  BTserial.begin(115200);  

  digitalWrite(IgnitionPin, HIGH);
  pinMode(IgnitionPin, OUTPUT);
}

void loop()
{
  if (BTserial.available())
  {
    choice = BTserial.read();
  }

  if( choice == 'm' )
  {
    digitalWrite(IgnitionPin, HIGH);
    ignitionCountTime = millis();
  }

  if (ignitionCountTime - startTime >= ignitionInterval)
  {
    digitalWrite(IgnitionPin, LOW);
  }

 delay(loopDelay);
}

 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

33 строка - трэшь какой-то

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mrw пишет:

Переделал код, но теперь код работает только один раз. При поступлении новой команды "м" второй раз реле молчит.

SoftwareSerial BTserial(12,13);

char choice;

const int loopDelay = 50;

int IgnitionPin = 10;
unsigned long startTime;
unsigned long ignitionInterval = 30000;
unsigned long ignitionCountTime = 0;

void setup() 
{
  BTserial.begin(115200);  

  digitalWrite(IgnitionPin, HIGH);
  pinMode(IgnitionPin, OUTPUT);
}

void loop()
{
  if (BTserial.available())
  {
    choice = BTserial.read();
  }

  if( choice == 'm' )
  {
    digitalWrite(IgnitionPin, HIGH);
    ignitionCountTime = millis();
  }

  if (ignitionCountTime - startTime >= ignitionInterval)
  {
    digitalWrite(IgnitionPin, LOW);
  }

 delay(loopDelay);
}

 

Мля, давайте с начала. Уже по новому коду

ЕвгенийП пишет:

После того, как команда m пришла в первый раз, и всё отработало, что будет происходить при следующем проходе loop?

Поскольку нового ничего не пришло, условие в строке №22 будет ложным и строка №24 не отработает.

А что будет с условием в строке №27? Чему сейчас равна choice? Оппа ... условие-то будет истинным и строки №№29-31 сработают! И будут срабатывать ВСЕГДА.

Т.е. ignitionCountTime всегда будет обновляться свежим millis

Вы не с того конца взялись. Вы пытаетесь выразить мысль, которую Вы не до конца сформулировали на языке, который Вы не до конца понимаете.

Начните с того, что сядьте и по-русски напишите, что должно происходить в loop. детально, "если ... иначе .. то" но по-русски, внятно. Убедитесь, что это правильно, и только потом пытайтесь писать код.

 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

v258 пишет:

33 строка - трэшь какой-то

До 33 мы с ним ещё не добрались :-)

mrw
Offline
Зарегистрирован: 14.03.2022

Правильно ли я понимаю, что в конце цикла мне нужно "обнулить" choice? В моем цикле после поступления команды "м" он постоянно "м", пока не прийдет новое значение?

Тогда вопрос, как обнулить?

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

У меня только один вопрос: А почему эта тема не в песочнице? ))

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

mrw пишет:

Правильно ли я понимаю, что в конце цикла мне нужно "обнулить" choice? В моем цикле после поступления команды "м" он постоянно "м", пока не прийдет новое значение?

Тогда вопрос, как обнулить?

Бинго. Так и есть. Обнулить - значит присвоить значение '\0'. Или вообще любое значение, кроме 'm'.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

mrw пишет:

Тогда вопрос, как обнулить?

Например, присвоить 'Y' ))

mrw
Offline
Зарегистрирован: 14.03.2022

Не знаю насколько это правильно, но получилось как-то так.

SoftwareSerial BTserial(12,13);

char choice;

int IgnitionPin = 10;
uint32_t timeout = 5 * 60;
uint8_t flag = 0;

void setup() 
{
  BTserial.begin(115200);  

  pinMode(IgnitionPin, OUTPUT);
  digitalWrite(IgnitionPin, LOW);
}

void loop()
{
  if (BTserial.available())
  {
    choice = BTserial.read();
  }

  if (choice == "m") 
   { 
    timeout = 5 * 60;
    flag = 1;
    digitalWrite(IgnitionPin, HIGH); 
   } 
   else if ((timeout > 0) && (flag == 1))
    {
            timeout--;
    }
   else 
    { 
       digitalWrite(IgnitionPin, LOW);
       flag = 0;
    }

choice = '\0';
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mrw пишет:

Правильно ли я понимаю, что в конце цикла мне нужно ...

Нет, Вы неправильно понимаете.

Что нужно делать правильно, я Вам написал

ЕвгенийП пишет:

Начните с того, что сядьте и по-русски напишите, что должно происходить в loop. детально, "если ... иначе .. то" но по-русски, внятно. Убедитесь, что это правильно, и только потом пытайтесь писать код.

Вы решили проигнорировать? Ваше право, пожалуйста. Только по-другому это не работает. Либо кто-то просто напишет код за Вас из жалости, либо Вы начнёте делать это правильно, а именно - сначала добьётесь (от себя) внятной и строгой формулировки алгоритма.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

В #12 ты такты считаешь, а не время. Воспользуйся подсказкой Евгения Петровича, иначе тут без вариантов.

mrw
Offline
Зарегистрирован: 14.03.2022
SoftwareSerial BTserial(12,13);

char choice;

int ignitionState;
unsigned long ignitionInterval = 50;
unsigned long ignitionCountTime = 0;

void setup() 
{
  BTserial.begin(115200);  

  pinMode(IgnitionPin, OUTPUT);
  digitalWrite(IgnitionPin, LOW);
}

void loop()
{
  if (BTserial.available())
  {
    choice = BTserial.read();
  }

  if(choice == 'm')
  {
    ignitionState = HIGH;
    digitalWrite(IgnitionPin, ignitionState);
    ignitionCountTime = 0;
  }

  if (ignitionState == HIGH) 
  {
    ignitionCountTime = ignitionCountTime + 1;

    if (ignitionCountTime >= ignitionInterval) 
    {
      ignitionState = LOW;
    }

    digitalWrite(IgnitionPin, ignitionState);
  }

choice = '\0';
}

Логическая цепочка такова:

- читаем поступающие команды
- при получении команды "м" 
-- переводим реле в режим Включено
-- начинаем отсчет времени 
-- при достижении поставленного времени
--- переводим реле в режим Выключено
--- обнуляем переменную с отсчетом времени?
 
Насколько мне известно, функция millis() считает время с начала запуска ардуино. Не очень понимю как обнулять время после каждого поступления команды "м".
 
В чем проблема моего нынешнего кода, с точки зрения логики? Вроде все работает, но как теперь следить завременем и обнулять его...
 
 
 
BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

В чем проблема Вашей логики - Евгений Петрович пояснит. 
По поводу миллис - да, начинается отсчёт от включения, но не прекращается и даже переполняется (можно грубо сказать обнуляется) и все это пока мк работает. Но эти значения можно получить, можно, присвоить и даже сверить.) И не нужно писать новый код пока Евгений Петрович не скажет что делать дальше.

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

С millis() время не нужно обнулять, нужно запоминать текущее значение в момент включения реле, и от этого момента отсчитывать нужные вам 5 секунд

lilik
Offline
Зарегистрирован: 19.10.2017
SoftwareSerial BTserial(12,13);

char choice;


int IgnitionPin = 10;

void setup() 
{
  BTserial.begin(115200);  

  pinMode(IgnitionPin, OUTPUT);
  digitalWrite(IgnitionPin, LOW);
}

void loop()
{
  if (BTserial.available())
  {
    choice = BTserial.read();
    if(choice == 'm')
  {
   digitalWrite(IgnitionPin, HIGH);
   delay(5000);
   digitalWrite(IgnitionPin, LOW);
  }
  }

  

  
}

ТС ваши скетчи не компилируются, вот вам с делеем, без миллис и не мучайтесь логикой - она проста "если пришёл символ и этот символ м, то включаем реле, ждём 5 секунд, выключаем реле" :-)

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

lilik, ничего личного - но "прерывать обучение" как минимум не этично. Пусть учится, если хочет. Вроде желание есть.

mrw
Offline
Зарегистрирован: 14.03.2022

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

lilik
Offline
Зарегистрирован: 19.10.2017

BOOM пишет:

lilik, ничего личного - но "прерывать обучение" как минимум не этично. Пусть учится, если хочет. Вроде желание есть.

Это не обучение, а бесцельное времяпрепровождение :-)

Впрочем, раз это тренировочные куски кода, я не смею больше влезать, миллис вам в помощь.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

lilik пишет:

Это не обучение, а бесцельное времяпрепровождение :-)

Это суждение преподавателя (в Вашем лице)?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mrw пишет:

SoftwareSerial BTserial(12,13);

char choice;

int ignitionState;
unsigned long ignitionInterval = 50;
unsigned long ignitionCountTime = 0;

void setup() 
{
  BTserial.begin(115200);  

  pinMode(IgnitionPin, OUTPUT);
  digitalWrite(IgnitionPin, LOW);
}

void loop()
{
  if (BTserial.available())
  {
    choice = BTserial.read();
  }

  if(choice == 'm')
  {
    ignitionState = HIGH;
    digitalWrite(IgnitionPin, ignitionState);
    ignitionCountTime = 0;
  }

  if (ignitionState == HIGH) 
  {
    ignitionCountTime = ignitionCountTime + 1;

    if (ignitionCountTime >= ignitionInterval) 
    {
      ignitionState = LOW;
    }

    digitalWrite(IgnitionPin, ignitionState);
  }

choice = '\0';
}

Уважаемый, я Вам уже ДВАЖДЫ говорил

ЕвгенийП пишет:
Начните с того, что сядьте и по-русски напишите, что должно происходить в loop. детально, "если ... иначе .. то" но по-русски, внятно. Убедитесь, что это правильно, и только потом пытайтесь писать код.

Говорю это в третий и в последний раз. Если Вы твёрдо решили игнорировать то, что я говорю, не вижу смысла бить пальцы об клавиши - они (пальцы) у меня не сменные.

mrw пишет:
В чем проблема моего нынешнего кода

В том, что Вы пытаетесь его писать не имея алгоритма, т.е. не понимая что именно Вы пишете.

Давайте посмотрим, что Вы называете "логикой"

mrw пишет:

Логическая цепочка такова:
- читаем поступающие команды
- при получении команды "м" 
-- переводим реле в режим Включено
-- начинаем отсчет времени 
-- при достижении поставленного времени
--- переводим реле в режим Выключено
--- обнуляем переменную с отсчетом времени?

Это не алгоритм, это хотелки или, если хотите, "чувственные идеи". Чтобы написать какой-то код по таким хотелкам, нужна очень высокая квалификация программиста.  Как говорил граф Калиостро: «Материализация чувственных идей - есть труднейшая задача научной магии»

Попробуйте таки написать так, как я Вам говорил

ЕвгенийП пишет:
Начните с того, что сядьте и по-русски напишите, что должно происходить в loop. детально, "если ... иначе .. то" но по-русски, внятно.

Если не получится, я помогу поправить, но если увижу от Вас хоть строчку кода до того, как алгоритм будет готов, просто слиняю с темы - отвечать ничего не буду.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

 Как говорил граф Калиостро: «Материализация чувственных идей - есть труднейшая задача научной магии»

интересно, кто кроме меня из присутствующих понимает, что именно имел ввиду Калиостро )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

интересно, кто кроме меня из присутствующих понимает, что именно имел ввиду Калиостро )))

Боюсь, что никто. Тут один специалист по научной магии :-)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

ua6em пишет:

интересно, кто кроме меня из присутствующих понимает, что именно имел ввиду Калиостро )))

Боюсь, что никто. Тут один специалист по научной магии :-)

а если попытать с пристрастием, может есть скрытые? )))

mrw
Offline
Зарегистрирован: 14.03.2022
Не имею права усомниться в высокой квалификации графа Евгения П., но методы обучения по написанию кода без кода не до конца ясны. Наверное это приходит с годами и возрастным познанием всего вечного и беспечного.
 
Почитал про millis() и пришел к такому результату:
  if(choice == 'm')
  {
    ignitionState = HIGH;
    digitalWrite(IgnitionPin, ignitionState);
    currentMillis = millis();
  }

  if (ignitionState == HIGH) 
  {
    if (millis() - currentMillis >= period)
    {
      ignitionState = LOW;
    }

    digitalWrite(IgnitionPin, ignitionState);
  }

  choice = '\0';
Для графа Евгения П:
 
  если: (choice == 'm') - если значение переменной choice равно латинской букве 'm'
  {
    ignitionState = HIGH; - поменять статус переменной ignitionState
    digitalWrite(IgnitionPin, ignitionState); - перевести реле в режим OН
    currentMillis = millis(); - запомнить значение millis() на данный момент
  }

  если: (ignitionState == HIGH) - если значение переменной ignitionState равно HIGH (высоко, большо, сильно)
  {
    если: (millis() - currentMillis >= period) - если millis() на данный момент минус запомненное значение больше или равно указанному периоду
    {
      ignitionState = LOW; - поменять статус переменной в LOW (низко, слабо, небольшо)
    }

    digitalWrite(IgnitionPin, ignitionState); - перевести реле в режим OФФ
  }

  choice = '\0'; - обнулить переменную choice
 
Вообше пошел уже какой-то сюр. Сначала Вы, писали:
 
После того, как команда m пришла в первый раз, и всё отработало, что будет происходить при следующем проходе loop?
Поскольку нового ничего не пришло, условие в строке №22 будет ложным и строка №24 не отработает.
А что будет с условием в строке №27? Чему сейчас равна choice? Оппа ... условие-то будет истинным и строки №№29-31 сработают! И будут срабатывать ВСЕГДА.
Вот оно у Вас и срабатывает.
 
- В следствии чего было добавлено: choice = '\0';
Правильно ли я понимаю, что в конце цикла мне нужно "обнулить" choice? В моем цикле после поступления команды "м" он постоянно "м", пока не прийдет новое значение?
 
Но Вы пишите:
 
Нет, Вы неправильно понимаете.
 
 
v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

mrw пишет:

Не имею права усомниться в высокой квалификации графа Евгения П., но методы обучения по написанию кода без кода не до конца ясны. 

Вот и не сомневайтесь. Он как никак преподаватель. И далеко не каждого он берется учить, как вас ;)