if-else - вопрос супер новичка

danik

✩✩✩✩✩✩✩
12 Фев 2020
18
0
Всем привет!

Только начинаю, и столкнулся с проблемой, которая кажется простой, но понять как ее решить не могу.
Есть фоторезистор, есть светодиод. Необходимо, чтобы при значения с фоторезистора > 450 светодиод моргал, меньше - постоянно горел. Фоторезистор опрашивается каждую секунду и выводит значение в сериал. С этим я справился.
Но дальше затык. Мне необходимо, чтобы первое условие сработало через N-секунд, второе – через M-секунд. При подстановке Delay или таймера закономерно весь луп начинает задерживаться на это значение, в том числе считывание значений фоторезистора и моргание светодиода. И так далее. А необходимо чтобы:
1. фоторезистор опрашивался каждую секунду независимо от всего, что будет происходить дальше
2. первое и второе действие "стартовали" с указанной им задержкой.

Прикрепляю свой кривой код, на котором и встрял.

Заранее огромнейшее спасибо за помощь!

C++:
int photocellPin = 0;
int photocellReading;
int led = 7;
#define PER_1 1000
unsigned long timer_1;

void setup() {

Serial.begin(9600);
pinMode(led, OUTPUT);
}

void loop() {
  photocellReading = analogRead(photocellPin);
if(millis()-timer_1>PER_1){
  timer_1=millis();
Serial.print("Analog reading = ");
Serial.println(photocellReading);
};

if (photocellReading > 450) {
delay(3000);
  digitalWrite(led, HIGH);
  delay(300);
  digitalWrite(led,LOW);
  delay(300);
}
else {
  delay(8000);
  digitalWrite(led, HIGH);

};

}
 

Mix_man

✩✩✩✩✩✩✩
21 Янв 2020
65
6
Ну так это...
во-первых ты этот код запускал вообще? Почему у тебя ТочкаСзапяткой стоят после ФигурнойСкобки в Лупе? - такое сочетание используется крайне редко, в часности в библиотеках, после бъявления класса или структуры!!!

Во вторых - если ты взялся юзать миллис() то зачем юзаешь Дэлэй() ?? Если хочеш чтооб 1ое условие работало - то юзать делитансткий Делей() запрещено.

Кроме того photocellReading = analogRead(photocellPin); у тебя в лупе стоит - значит опрос датчика происходит примерно 25000 раз в секунду . Если надо именно 1 раз в секунду - то писать это надо в другом месте. - а точнее в Ифе где ты будет отмерять время ,используя миллис().

Дерзай :))
И да , юзай библиотеку из поста выше (ибо не нужно снова лисопед избретать). Примеры там есть.
объявиш 2 таймера с нужными периодами , и по срабатыванию
таймера if(Timer_name.isReady()) { будешь выполнять то что хочешь}
 

kalobyte

★★★✩✩✩✩
1 Янв 2020
741
158
поздравляю автора
ты столкнулся с моментом, когда нужно использовать модель или паттерн программирования под названием конечный автомат

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

danik

✩✩✩✩✩✩✩
12 Фев 2020
18
0
Всем огромное спасибо! Чуть погрузился в тему, удалось наладить для проекта корректную работу, НО!
Почему-то все работает в обратном порядке. При значении фоторезистора больше 300 светодиод горит, а меньше - гаснет... Все через нужные промежутку времени, однако в моей голове пока не укладывается – почему поменялся порядок... Буду благодарен за разъяснение.

C:
#include "GyverTimer.h"
int photocellPin = 0;
int photocellReading;
int led = 6;
GTimer Timer1(MS, 1000);
GTimer Timer2(MS);
GTimer Timer3(MS);


void setup() {

  Serial.begin(9600);
  pinMode(led, OUTPUT);
}

void loop() {
  photocellReading = analogRead(photocellPin);
  if (Timer1.isReady()) Serial.println(photocellReading);

  if (photocellReading > 300) {
    Timer2.setTimeout(5000);
  }
  if (Timer2.isReady())
    digitalWrite(led, LOW);

  if (photocellReading < 300) {
    Timer3.setTimeout(8000);
  }
  if (Timer3.isReady())
    digitalWrite(led, HIGH);
}
 

danik

✩✩✩✩✩✩✩
12 Фев 2020
18
0
И простите за совсем глупость, но почему работает вариант:
if (Timer2.isReady())
digitalWrite(led, LOW);

но не работает вариант
if (Timer3.isReady){
digitalWrite(led, HIGH);
delay(50);
digitalWrite(led,LOW);
delay(50);
}
выдает ошибку cannot convert 'GTimer::isReady' from type 'boolean (GTimer::) {aka bool (GTimer::)}' to type 'bool'
 

kalobyte

★★★✩✩✩✩
1 Янв 2020
741
158
При значении фоторезистора больше 300 светодиод горит, а меньше - гаснет..
так все правильно, ты же его выключаеш
if (Timer2.isReady())
digitalWrite(led, LOW);

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

Mix_man

✩✩✩✩✩✩✩
21 Янв 2020
65
6
И простите за совсем глупость, но почему работает вариант:
if (Timer2.isReady())
digitalWrite(led, LOW);

но не работает вариант
if (Timer3.isReady){
digitalWrite(led, HIGH);
delay(50);
digitalWrite(led,LOW);
delay(50);
}
выдает ошибку cannot convert 'GTimer::isReady' from type 'boolean (GTimer::) {aka bool (GTimer::)}' to type 'bool'

В if скобки ты забыл. isReady() - это функция, а не переменная.
Это называется: "Смотрю в книгу- вижу фигу"

Внимательно с синтаксисом! ;)
 

danik

✩✩✩✩✩✩✩
12 Фев 2020
18
0
@kalobyte, но второй таймер же, который реагирует на значения фоторезистора > 300 говорит LOW - выключи светодиод, но на макете при тесте и загруженном указанном коде работает все наоборот, т.е. при >300 он включается (HIGH), при <300- выключается...
 

Mix_man

✩✩✩✩✩✩✩
21 Янв 2020
65
6
@danik, раз только в начале, то для облегчения набивки кода советую место Arduino IDE установить Visual Studio Code. Но если не получится разобраться, хотябы Notepad++
 

kalobyte

★★★✩✩✩✩
1 Янв 2020
741
158
т.е. при >300 он включается (HIGH), при <300- выключается...
когда фоторезистор освещаеш, то сопротивление у него падает
а значение ацп будет уже зависить от схемы включения фоторезистора в резистивном делителе
если он сверху включен, то значение будет расти

так что поменяй резисторы местами
 

danik

✩✩✩✩✩✩✩
12 Фев 2020
18
0
Всем еще раз привет и спасибо за помощь!
Я постепенно со всем этим разобрался, но осталась последняя - завершающая проблема по моему проекту. Я уже понял, что это называется конечный автомат, но все примеры, которые я нашел, не дают мне четкого ответа на решение моей проблемы.

конструкция проста:
фоторезистор, пищалка и модуль воспроизведения mp3 файлов + динамик.
1. if фоторезистор больше 1, то через небольшую паузу пищим пищалкой. тут все предельно понятно и получается.
2. if фоторезистор меньше 1, то запускаем необходимый файл на модуле. Это реализуется с помощью собственно библиотеки модуля, все просто, команда play(#файла). Это команда запускает файл и он играет, пока не закончится.
проблема в том, что файл должным образом не воспроизводится, потому что, как я понимаю, он постоянно тригируется каждые миллисекунды опроса фоторезистора. т.е. находится в постоянном лупе. что для пищалки это гуд, то тут совсем не применимо. мне нужно чтобы при значениях меньше 1 файл запустился только один раз, сколько бы времени фоторезистор не был бы значениях меньше 1. при больше 1 приходит команда стоп воспроизведение и начало пищаний. когда снова фоторезистор меньше 1, файл вновь должен запустится с самого начала...

Буду очень благодарен за помощь с решением этой задачи..

C:
#include "GyverTimer.h"
#include "DFRobotDFPlayerMini.h"
#include "Arduino.h"
#include "SoftwareSerial.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

int photocellPin = 0;
int photocellReading;


GTimer Timer1(MS, 1000);
GTimer Timer3(MS);


const int buzzer = 6;
const int c = 1047;
const int e = 1397;
void beep(int ton, int time)
{
  tone(buzzer, ton, time);
  delay(time + 20);
}


void setup() {

  mySoftwareSerial.begin(9600);
  Serial.begin(9600);

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true);
  }
  Serial.println(F("DFPlayer Mini online."));

  myDFPlayer.volume(10);

}

void loop() {

  photocellReading = analogRead(photocellPin);
  if (Timer1.isReady()) Serial.println(photocellReading);

  if (photocellReading < 1) {
    myDFPlayer.stop();
  }


  if (photocellReading > 1) {
    myDFPlayer.play(3);
  }

  if (photocellReading < 1) {
    Timer3.setTimeout(3000);
  }

  if (Timer3.isReady()) {

    do {
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);


      noTone(buzzer);
      delay(1200);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);
      beep(c, 20);
      beep(e, 20);


      noTone(buzzer);
      delay(5000);
    } while (analogRead(photocellPin) < 1);
  }
}
 

Эдуард Анисимов

★★★★✩✩✩
23 Сен 2019
904
265
54
Марий-Эл
Я с этой библиотекой не знаком и проверить не на чем. Плеер можно опрашивать на предмет его занятости, в каком режиме он находится в данный момент?
Если да, то всё просто. В месте, где воспроизведение запускается, ставим цикл с опрашиванием плеера. Пока он не скажет, что закончил из цикла не выходим.
 

Старик Похабыч

★★★★★✩✩
14 Авг 2019
1,686
415
Москва
Да, плеер можно опрашивать , но это по сериалу и долго, если часто опрашивать будут тормаза самого плеера, но у плеера ест выхо BUSY который имеет высокий уровень если плеер не играет ничего и низкий если наоборот
 

danik

✩✩✩✩✩✩✩
12 Фев 2020
18
0
@Эдуард Анисимов,
Да, можно опрашивать, но насколько я понимаю мне не подойдет, так как необходим функционал, что фоторезистор может изменить значение на меньше единицы в любой момент воспроизведения файла (а не только когда он доиграет до конца), и, соотвественно, воспроизведение должно остановиться в этот момент. И когда заново будет значение больше единицы - просто стартануть с начала.
А возможно как-то реализовать этот функционал без опрашивания плеера? Т.е. по логике когда значение больше одного, то запускаем блок с play один раз и дальше на этот блок как бы не обращаем внимание и просто считываем дальше фоторезистор? Т.е. однократно действие внутри лупа. Кажется, такой функционал может пригодиться и в будущем для многих других вещей :)
 

Mix_man

✩✩✩✩✩✩✩
21 Янв 2020
65
6
Что значит " фоторезистор больше(или меньше) 1 ?????
С фоторезистора идет аналог, значит 0...1023. тобишь ты ловишь какуюто суперпупертемноту , и чуть 10 фотонов прилетело и попало на фоторезистор , ты музыку включаешь. Это первое.

И второе - зачем в программе столько много писанины в сериал ? ктото постоянно будет пялиться в этот лог? это же тормозит ЦП "

Плюс целая куча delay o_O:sneaky: ,..

Кроме того в библиотеке плеера должно быть описание как она работает, постоянно вызывать надо или 1 раз, я хз ..
Если 1 раз вызывать , то "грабли" надо настраивать )))
 

Arhat109

★★★✩✩✩✩
9 Июн 2019
382
125
Во-первых, посоветую посмотреть эту тему: https://community.alexgyver.ru/threads/programmirovanie-konechnyx-avtomatov-bez-delay.2657/
А во-вторых, давайте переформулируем ваше ТЗ четче:

Дано: фоторезистор, замеряет текущую освещенность и, если она превышает некий "порог", то включаем "пищалку" И (возможно) отправляем команду "стоп" для "игралки mp3-файла". При снижении сигнала фоторезистора ниже порога, отправляем команду play() "игралке", если она выключена или ничего не делаем.

Итого у нас есть "конченные автоматы":
1. "Фоторезистор": имеет "слушателя входного потока" (замер освещенности) и может находится в состояниях: "порог превышен" и "порог не достигнут". Действие этого КА происходит в процессе СМЕНЫ сотояния, то есть это "автомат Милли";
2. "Игралка": имеет тоже 2 состояния, но .. не имеет "слушателя", поскольку управляется "извне", а именно КА "Фоторезистор". Первое состояние "остановлен" - ничего не делает. Второе состояние "играем файл". Соответственно, смена состояний - это просто отправка (вызов, исполнение) 2-х команд: "играй(файл)" и "стоп". Всё, что требуется "хранить" для этого КА - это переменную "состояние" (играем/остановлен).
3. "Пищалка": .. практически даже и вовсе не КА, а просто функция tone(), запускаемая "когда требуется"

Кстати, в ТЗ не указано как долго должна пищать пищалка при превышении порога! Как правило, такое переформулирование ТЗ часто находит такие вот "умолчания" и недозаданности.

Собственно это всё, можно писать код "в лоб":

1 "Фоторезистор": имеем переменную - состояние с двумя значениями (кстати, какое изначально при запуске? третье - "нет замера" - что делать с пищалкой и игралкой?) и функцию "слушателя" - замер значения и определение нового статуса. Как реализовать - зависит от конструкции.

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

3. "Исполнитель состояния замер ниже порога" - функция, вызываемя при переходе сюда фоторезистора. Аналогично, проверяет состояние "игралки" и если та ещё не играет файлик, то запускает команду "играй(файл)". Иначе не делает ничего (пищалка выключится самостоятельно, по ТЗ ..)

4. Команда "стоп" - выключает игралку И меняет её состояние на "остановлено".

5. Команда "играй(файл)" принимает файл и запихивает его в игралку, меняя её состояние на "играй файло".

...

В силу примитивности функций, их все можно реализовать "макропроцессором Си" и воткнуть куда следует в loop(). Впрочем, умный компилятор так сделает даже самостоятельно, т.к. вызовы по 1 разу практически везде.
В силу малого количества состояний у всех КА, использовать библиотеку из ссылки выше - в общем-то даже и незачем. Все реализуется простыми if(){}else{} даже проще.

P.S. Нигде не ошибся в переводе вашего ТЗ? ;)