Цикл for вместо delay, работает, будет ли тормозить остальной скетч

Katapuf
Offline
Зарегистрирован: 16.05.2018

Здравия.

Вопрос к знатокам.

Просто стало интересно.

К примеру, если в теле основного скетча, для "смены экранов", поочередное отображение информации на экране использовать не delay или millis, а цикл for?

Это работает, но.... Как это отобразится на основном скетче?

Вот пример на основе классического Blink, организовнного с помощью цикла for.

#define LED 6 // Светодиод
void setup()
{
  pinMode(LED, OUTPUT); // Объявдляем Pin как выход
}
void loop()
{
  for (unsigned long i = 0; i < 800000; i++) // Перрвый цикл
  {
    digitalWrite(LED, HIGH);                 // Светодиод включен
  }
  for (unsigned long i = 0; i < 800000; i++) // Второй цикл
  {
    digitalWrite(LED, LOW);                  // Светодиод отключен
  }
}
Просьба к "Клапауцию 112", не надо сразу запрещать.
 
И еще такой вопрос:
 
Сейчас читаю форум "по порядку" и встречается "Клапауций 999", а сейчас он "Клапауций 112",
так вот вопрос, он как millis переполнился и сейчас очередной цикл?
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Katapuf пишет:

будет ли тормозить остальной скетч

А сами-то как думаете?

Katapuf
Offline
Зарегистрирован: 16.05.2018

Есть конечно предположение, что будет, но... я только учусь....

Просто пришла как говорится мысля... решил посмотреть, что будет.

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

Как я понимаю, многопоточности в Ардуино нет...

 

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Тот код что Вы написали равносилен ДЕЛАЙ, ибо пока не выполнится фор 800000 раз программа дальше не пойдет

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

Katapuf пишет:

 решил посмотреть, что будет.

Ведь учиться можно, только на своих ошибках, 

Так смотрите и учитесь, чего нас-то спрашиваете? Вы на своих ошибках учиться собрались, или на наших?

Katapuf пишет:

Как я понимаю, многопоточности в Ардуино нет...

А где она есть? Если вычислительно ядро одно, то её, как таковой, нигде нет. Есть она только в мультиядерных системах. Но моделировать её можно везде.

inspiritus
Offline
Зарегистрирован: 17.12.2012

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

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

inspiritus пишет:

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

#define delay for (int a =0; a<100;a++){};

=) шутка юмора =)

inspiritus
Offline
Зарегистрирован: 17.12.2012

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

Katapuf
Offline
Зарегистрирован: 16.05.2018

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

Так смотрите и учитесь, чего нас-то спрашиваете? Вы на своих ошибках учиться собрались, или на наших?

А причем тут ваши ошибки? Использовать for попробывал я и ваши ошибки я не рассматривал.

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

inspiritus пишет:

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

Так я об этом же =)) я плохо знаком с плюсами не знаю как использовать переменные в макросах) но суть была что в предложеном синтаксисе если что то находится меж скобок то можно заставить delay выполнять это что то =)

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

inspiritus пишет:

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

В Ваших словах есть резон но на мой взгляд это извращение.

Пишите номально код с миллис и будет все хорошо!

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

Katapuf пишет:

А причем тут ваши ошибки? Использовать for попробывал я и ваши ошибки я не рассматривал.

Так а к чему тут был вопрос тогда? вы пробовали? разницу не заметили - зачем задали вопрос?

А вообще учитесь писать код без delay и пустых циклов =)

Katapuf
Offline
Зарегистрирован: 16.05.2018

Да с millis то понятно, у меня и построено смена экранов на нем, примерно так:

if ((millis() / 4000) % 2 == 0) // интервал 
{
led1; // Первый экран
}
else
{
led2; // Второй экарн
}

...

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

Katapuf пишет:

if ((millis() / 4000) % 2 == 0) // интервал 

Уже лучше =) а теперь еще лучше сделайте =) 

(millis() && 0x100 == 0)

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

vosara пишет:

В Ваших словах есть резон но на мой взгляд это извращение.

Пишите номально код с миллис и будет все хорошо!

Присоединяюсь. Но это маразм из-за глубого не знания всего. Пишите нормально код и все. Да и millis() не всегда в выводе на экран нужен.

 ПС Все что в теме похоже на это.

inspiritus
Offline
Зарегистрирован: 17.12.2012

А кто Вам сказал, что я это использую? Я только написал в чем разница.

если места мало и все просто, то миллис.

если для меги и много всего , то SimpleTimer и типамногозадачность, а по сути завернутый миллис.

например на сиплетаймере удобно опрашивать далласы. В сетапе запустил, потом первый раз через секунду вызвал , считал  и снова запустил. Потом через секунду пришел, или чере скольконадо. Я на этой библтотеке реализовывал каскадное регулирование четырех чиллеров ( блэкджеком и дамами с вэбом и аяксом) , работает однако уже года три.

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

inspiritus пишет:

внутрь делая ничего поместить нельзя.

Да, ладно! Не только можно, а там уже всё, что надо помещено. Вот он Ваш делэй

void delay(unsigned long ms)
{
	uint32_t start = micros();

	while (ms > 0) {
		yield();
		while ( ms > 0 && (micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}

Определите у себя функцию void yield(void)  и она будет вызываться из делэй за милую душу. А в ней уж помещайте чего хотите.

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

Katapuf пишет:

А причем тут ваши ошибки? Использовать for попробывал я и ваши ошибки я не рассматривал.

Так при том. Сам написал - сам и анализируй что получилось. Именно этот процесс анализа и есть учёба на ошибках. А Вы анализ на нас перекладываете.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Katapuf пишет:

Есть конечно предположение, что будет, но... я только учусь....

Просто пришла как говорится мысля... решил посмотреть, что будет.

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

Как я понимаю, многопоточности в Ардуино нет...

 

Давайте рассуждать логически.

Какой код выполняет Ардуина во время цикла?

Katapuf
Offline
Зарегистрирован: 16.05.2018

andriano пишет:

Давайте рассуждать логически.

Какой код выполняет Ардуина во время цикла?

Да понятно, что процесс, будет ждать, пока цикл не прокрутится.

Katapuf
Offline
Зарегистрирован: 16.05.2018

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

Katapuf пишет:

А причем тут ваши ошибки? Использовать for попробывал я и ваши ошибки я не рассматривал.

Так при том. Сам написал - сам и анализируй что получилось. Именно этот процесс анализа и есть учёба на ошибках. А Вы анализ на нас перекладываете.

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

Я не зря в самом первом посте написал: "Сейчас читаю форум "по порядку"" и насмотрелся на реакцию, некоторых индивидумов, которые себя позиционируют "всезнайками" и которым лень сказать, что - то по существу, когдау них просят совет, но зато как они любят разглагольствовать, мол ничего нет, а ты хочешь от нас, чтоб мы тебе все сделали.

Я просто хотл услышать подтверждение своих выводов, да, нет.

И еще, я обращался, лично вам ЕвгенийП ?

Нет.

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

Есть те , кто адекватно реагирует.

Интересно бы посмотреть на вас в реальной жизни, как вы общаетесь с окружающими вас людьми?

Если сегодняшнюю или подобную ситуацию, в которых вы были неоднакратно "замечены", экстраполировать на "семью": папа, а что будет если я ...? Сынок, тебе надо...., а от меня отстань, я то уже это знаю, мне не до тебя, но я тебе сейчас по этому поводу буду выносить моз, пустой информацией, которая к твоему вопросц не имеет ни малейшего отношения.

Хотя делая анализ, вашего поведения и отношения к людям - счастливая семья, много друзей?

Нет это не ваше.

Это затаенная детская, мелочная обида, на весь мир... 

 

 

Katapuf
Offline
Зарегистрирован: 16.05.2018

 

qwone пишет:

vosara пишет:

В Ваших словах есть резон но на мой взгляд это извращение.

Пишите номально код с миллис и будет все хорошо!

Присоединяюсь. Но это маразм из-за глубого не знания всего. Пишите нормально код и все. Да и millis() не всегда в выводе на экран нужен.

Вы пишите, что не всегда нужен millis при выводе на экран.

Вероятно вы имели ввиду есть еще timeout  или SimpleTimer?

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

Экран 2004, на него поочереди выводится: текущее время, параметр установленный, параметр текущий 1, параметр текущий 2. На втором экране, показания с 4 других датчиков. И "экраны" с заданным интервалом меняются. В случаии "аварии" экран меняется функцией "if" на экран на котором выводится информация о событии. Но это уже другая история, так как этот "экран"(с информациеей о событии), можно переключить(сбросить) только в ручном режиме, так как ситуация обязывает, в любом случае, присутствие человека.

Так есть другой способ?

Если есть, был бы рад, "пинку" в нужном направлении. :)

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

Katapuf пишет:

Так есть другой способ?

Если есть, был бы рад, "пинку" в нужном направлении. :)

Например система состояний, или система событий.

 

Katapuf
Offline
Зарегистрирован: 16.05.2018

ToRcH2565 пишет:

Katapuf пишет:

Так есть другой способ?

Если есть, был бы рад, "пинку" в нужном направлении. :)

Например система состояний, или система событий.

 

Система состояний, это "boolean", я правильно понял?

А система событий это прерывание по событию.

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

Но как прерывание или состояние будет управлять переключением экрана в штатном режиме? Отображение каждого экрана 4 - 5 секунд.

Отслеживать продолжительность в любом случае нужно.

А предложенные вами методы, на сколько мне известны срабатывают по событию.

Опять же я учусь и многого не знаю.

Конечно можно переключать экраны с помощью "boolean" и if но как отсчитывать время?

Если не использовать millis.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Katapuf пишет:

ToRcH2565 пишет:

Katapuf пишет:

Так есть другой способ?

Если есть, был бы рад, "пинку" в нужном направлении. :)

Например система состояний, или система событий.

 

Система состояний, это "boolean", я правильно понял?

 

Нет, ты понял неправильно. Почитай, что такое конечные автоматы. Если вкратце: есть  набор состояний автомата, система может одновременно находится в одном из них. Как пример, в псевдокоде:

uint32_t timer = 0;
typedef enum
{
	stage1,
	stage2,
	
} MachineState;

MachineState stages = stage1;

void state1()
{
	// обрабатываем первое состояние
}

void state2()
{
	// обрабатываем второе состояние
}

void setup()
{
	
}

void loop()
{
	switch(stages)
	{
		case stage1:
		{
			state1();
			if(millis() - timer > 2000)
			{
				timer = millis();
				stages = stage2;
			}
		}
		break;
		
		case stage2:
		{
			state2();
		}
		break;
	}
}

В указанном примере система 2 секунды будет вызывать функцию state1, потом, бесконечно - функцию state2. При этом по каким-то условиям внутри state2 можно всегда переключиться на другое состояние конечного автомата, попав в другую ветку кода. Состояния можно добавлять до посинения. Короче - почитай теорию, она интересная, правда ;)

inspiritus
Offline
Зарегистрирован: 17.12.2012

https://youtu.be/tt_EUA7aQNk

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

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

Katapuf пишет:
Система состояний, это "boolean", я правильно понял?

Уже ответили за меня что не так.

Katapuf пишет:

Но как прерывание или состояние будет управлять переключением экрана в штатном режиме? Отображение каждого экрана 4 - 5 секунд.

Прерывание по таймеру? не слышали?

Katapuf пишет:
Отслеживать продолжительность в любом случае нужно.

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

Katapuf пишет:
А предложенные вами методы, на сколько мне известны срабатывают по событию.

Вам никто не мешает сделать свою систему событий.

Katapuf пишет:
Опять же я учусь и многого не знаю.

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

 

Katapuf пишет:
Конечно можно переключать экраны с помощью "boolean" и if но как отсчитывать время?

Можно но не так явно, выше вам человек привел код как сделать систему "состояний". Это на много более "правильно" нежели прям в коде лепить if(millis())... 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

вот смотри.  Есть метеостанция.  Она показывает в основном время, но через некоторые промежутки показываются так же Температура и Влажность + еще может Давление и прочая х-ня.  Ясно, что дисплей в каждый определенный промежуток времени показывает что то одно, то есть находится в одном из детерминированных состояний.  Просто опиши их 

enum class enumDisplayState : byte  {Normal, Temperature, Humidity, Pressure, Error};

в состоянии Normal мы показываем часы, в состоянии Error - ошибки чтения всяких даччиков, остальное ясно из названия.   

и создай переменную этого типа:  enumDisplayState DisplayState;

Теперь, если у нас есть функция вывода на экран, ставим переключашку, чтоб выводить нужную информацию, в зав-ти от состояния

void Display(void) {

  switch (DisplayState) {

    case enumDisplayState::Normal: /* выводим часы */; break;

    case enumDisplayState::Temperature: /* выводим температуру */; break;

    case enumDisplayState::Humidity: /* выводим влажность */; break;

    case enumDisplayState::Pressure: /* выводим давление */; break;

    case enumDisplayState::Error: /* выводим сапщение об ашыпке */; break;

    default: /* выводим неведомую х-ню */;

}

}

 

теперь, меняя значение переменной DisplayState где-то в коде, да хоть периодически, по таймеру, на экране мы получим правильный вывод хоть в каком состоянии. Нужно просто новое состояние устанавливать через функцию

void setDisplayState(enumDisplayState newState) {

 if (DisplayState == newState) return;

 DisplayState = newState;

 Display();

}

и сё.

 

Katapuf
Offline
Зарегистрирован: 16.05.2018

Вот ответы, так ответы.

Благодарю.

А за видео с канала Инженерка "#070 Ардуино Библиотека SimpleTimer Libraries Arduino" отдельная благодарность.

Канал на Ютубе "Инженерка" Подписался.

Там много интересного. 

Всем начинающим советую.

Так ладно, пошел смотреть, читать.................

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

 1- новички пытаются весть код разместить в loop(). И вся простыня скетча это длиный loop(), в котором очень сложно ловить баги. А все потому что забывают о таком инструменте как функция. Достаточно куски кода выделять в функции,а лучше в методы класса.

2- вывод на экран лучше организовать в отдельной функии, а не разбросаными по скетчу print . тогда элементы на экране не будут запаздывать при показе. Итак. Надо вывести 1 экран запустили функцию vievScreen1(), а если 2 экран то vievScreen2(). Ну и так далее.

3- иногда надо менять экран не по времени чередуя 1 экран со вторым, а при нажатии кнопки в меню. Ведь человек нажимает кнопки не по не по функции delay, millis или всяким for , а по своим непонятным МК законам. Так что в обработчиках кнопки желательно будет организовать команду . Display.refrech()  /*обновить текущий экран*/  или  Display.refrech(/*номер экрана*/ 2)  /*обновить экран 2*/ . Осталось просто организовать правильно работу объекта Display.

Katapuf
Offline
Зарегистрирован: 16.05.2018

qwone пишет:

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

 1- новички пытаются весть код разместить в loop(). И вся простыня скетча это длиный loop(), в котором очень сложно ловить баги. А все потому что забывают о таком инструменте как функция. Достаточно куски кода выделять в функции,а лучше в методы класса.

Да наверное, в текущем "проекте", у меня получился давольно таки длинный  loop().

void loop()
{
  ModuleKey();       // Модуль Key RFID
  ModuleCall();      // Модуль Call
  ModuleSMS();       // Модуль SMS
  ModuleMotion();    // Модуль датчика движения
  ModuleKalitka();   // Модуль геркон 1
  ModuleVorota();    // Модуль геркон 2
  ModulePower();     // Модуль наличия сетевого напряженния
  ModuleVoltmeter(); // Модуль Вольтметр
  ModuleMQ2();       // Модуль датчика MQ-2
  ModuleMQ6();       // Модуль датчика MQ-6
  ModuleMQ7();       // Модуль датчика MQ-7
  ModulePlamya();    // Модуль Пламя
  ModuleDHT22_1();   //  Модуль датчика DHT22_1
  ModuleDHT22_2();   //  Модуль датчика DHT22_2
  ModuleNoTone();    //  Модуль выключения бузера
}

Это там еще нет "модулей" LCD, часов реального времени и еще пару модулей.

И еше несколько "модулей" которые стоят в самом низу скетча и "объявляются" в нужном месте в теле скетча, 

типа: 

"void BUZ_KLYUCH() ",

"void POLOVINA_KLYUCHA()"

Это как обычно, хотел так, по минимуму, а получилось  как всегда. 

По ходу дела надо то это и вот это прилепть. А вот без этого вообще не обойтись.

И с NANO пришлось переходить на MEGA. 

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Золотое правило Адуинской программистской механики:  текст loop() должен полностью влазить в 1 экран.

паматри, кстати, мои таймеры на GitHub-е.  Вдруг пригадЯца.  

Katapuf
Offline
Зарегистрирован: 16.05.2018

DetSimen пишет:

Золотое правило Адуинской программистской механики:  текст loop() должен полностью влазить в 1 экран.

паматри, кстати, мои таймеры на GitHub-е.  Вдруг пригадЯца.  

Пока влазит :)

Надеюсь на этом и останавлюсь(с этим скетчем).

На GitHub-е? По запросу у меня импортный дядька, а я его не понимаю.

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

Katapuf пишет:

И еще, я обращался, лично вам ЕвгенийП ?

Вы обращались ко всем, в том числе и ко мне, так что не надо.

А вот я обращался лично к Вам с вопросом "А сами-то как думаете?". Ответа не получил. Откуда сделал вывод, что никак.

Впрочем, мне пофиг.

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

2 Qwone, немного критики...

1) если нет необходимости в классе(хоть даже эстетической) - не нужно использовать его, используйте функции

2) англицкий, тяжко читать такие опечатки... и смысл понятен, и написано что глаз дерет....(View, refresh)

3) Логика работы рефреш в корне не верна =) 

  3а) Не нужно передавать в рефреш состояние, состояние должно менятся отдельно от рисования кадра для этого состояния, смена состояния вызвана ведь событием, и смена картинки является следствием смены состояния, а не причиной по которой нужно изменить состояние.

  3б) Не нужно(вообще!!!) делать функцию рефреш, нужно делать функцию инвалидации, которая скажет классу дисплея примерно следующее: "у тебя неверная картинка, следующий кадр строй с нуля". разница в том что при рефреше(как оно должно пониматся) - идет непосредственная перерисовка кадра, а при инвалидации - перерисовка кадра пойдет штатно, в положеное время.

 

Теперь по 3б подробней:

1) У вас идет отображение информации на двух экранах(Sc1 и Sc2) и так же в случае ошибок отображается экран ошибки(Er1).. Считаем что вывести ошибку - самый приоритетный для нас экран.

под экранами я понимаю "картинку"... 

2) Смена экранов Sc1 и Sc2 происходит по нажатию на кнопку(по таймеру, или еще как угодно).

3) Во время смены экрана Sc1->Sc2 происходит ошибка(аппаратная, прерывание например) и пользователю нужно показывать уже Er1.

4) Что должно произойти в случае Refresh? правильно экран моргнет отрисовав Sc2 и сразу следующим кадром Er1, т.к. оба раза были рефреши - вы использовали 2 раза отрисовку разных кадров.

5) Что произойдет в случае с инвалидацией? Вы 2 раза скажете дисплею "следующий раз рисуй с нуля", но дисплей нарисуется только единожды, с нужным экраном Er1. 

 

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017
Katapuf
Offline
Зарегистрирован: 16.05.2018

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

Katapuf пишет:

И еще, я обращался, лично вам ЕвгенийП ?

Вы обращались ко всем, в том числе и ко мне, так что не надо.

А вот я обращался лично к Вам с вопросом "А сами-то как думаете?". Ответа не получил. Откуда сделал вывод, что никак.

Впрочем, мне пофиг.

А этот ответ:

Katapuf пишет:

Есть конечно предположение, что будет, но... я только учусь....

Не считается?

И еще.

Посмотрите, сколько людей откликнулось на мой вопрос и не просто так, а с советами и объяснениями, с сылками на обучающее виде.

Они даже спорят меж собой как лучше сделать.

...

Katapuf
Offline
Зарегистрирован: 16.05.2018

Благодарю, скачал, буду посмотреть.

Здравия.

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

Katapuf пишет:

Да наверное, в текущем "проекте", у меня получился давольно таки длинный  loop().

void loop()
{
  ModuleKey();       // Модуль Key RFID
  ModuleCall();      // Модуль Call
  ModuleSMS();       // Модуль SMS
  ModuleMotion();    // Модуль датчика движения
  ModuleKalitka();   // Модуль геркон 1
  ModuleVorota();    // Модуль геркон 2
  ModulePower();     // Модуль наличия сетевого напряженния
  ModuleVoltmeter(); // Модуль Вольтметр
  ModuleMQ2();       // Модуль датчика MQ-2
  ModuleMQ6();       // Модуль датчика MQ-6
  ModuleMQ7();       // Модуль датчика MQ-7
  ModulePlamya();    // Модуль Пламя
  ModuleDHT22_1();   //  Модуль датчика DHT22_1
  ModuleDHT22_2();   //  Модуль датчика DHT22_2
  ModuleNoTone();    //  Модуль выключения бузера
}

Длинный, короткий.... главное неверный =) 

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

ах да и главное, код шикарно откоментирован!!!! (сарказм если что, загляните в литературу по программированию на любом ЯП и почитайте как должен выглядеть комментарий и сколько их надо)

ModuleNoTone - из названия данной функции(а что она вообще тут делает? ее не должно быть в этом месте кода, и я на полном серьезе, ее тут быть не должно!) Мне совершенно не понятно что это Модуль, и что он отключает генерацию Шим для пищалки... вы это для кого комментили в коде? 

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Katapuf пишет:

Здравия.

Нальёшь, при случае. 

Katapuf
Offline
Зарегистрирован: 16.05.2018

ToRcH2565 пишет:

Katapuf пишет:

Да наверное, в текущем "проекте", у меня получился давольно таки длинный  loop().

void loop()
{
  ModuleKey();       // Модуль Key RFID
  ModuleCall();      // Модуль Call
  ModuleSMS();       // Модуль SMS
  ModuleMotion();    // Модуль датчика движения
  ModuleKalitka();   // Модуль геркон 1
  ModuleVorota();    // Модуль геркон 2
  ModulePower();     // Модуль наличия сетевого напряженния
  ModuleVoltmeter(); // Модуль Вольтметр
  ModuleMQ2();       // Модуль датчика MQ-2
  ModuleMQ6();       // Модуль датчика MQ-6
  ModuleMQ7();       // Модуль датчика MQ-7
  ModulePlamya();    // Модуль Пламя
  ModuleDHT22_1();   //  Модуль датчика DHT22_1
  ModuleDHT22_2();   //  Модуль датчика DHT22_2
  ModuleNoTone();    //  Модуль выключения бузера
}

Длинный, короткий.... главное неверный =) 

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

ах да и главное, код шикарно откоментирован!!!! (сарказм если что, загляните в литературу по программированию на любом ЯП и почитайте как должен выглядеть комментарий и сколько их надо)

Вообще то это писал для себя и коментарии я писал для себя.

Еще раз повторю, я эти закорючки вижу второй календарный месяц.

Это не значит, что я этим занимаюсь, все два месяца без отрыва.

А еще из этого времени, недели две ждал пока придет заказ с комплектухой.

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

Поэтому, сколько мне потребуется коментариев, столько я и напишу. 

И по поводу: "любому кто будет с этим работать на уровне кода - будет не понятно...." еще раз я это делаю для себя, возможно выложу, кому будет не понятно, объясню. Хотя прочитав коментарии, только ... не поймет, что к чему.

Вот кусок кода, что тут не понятного?

void ModuleKey()
{
  if ( ! mfrc522.PICC_IsNewCardPresent()) // Если нет нового ключа, то...
  {
    return;                               // Возвращаемся в начало
  }
  if ( ! mfrc522.PICC_ReadCardSerial())   // Если нечего не считали, то...
  {
    return;                               // Возвращаемся в начало
  }
  for (byte i = 0; i < mfrc522.uid.size; i++) // Подсчет серийного номера ключа.
  {
    uidDecTemp = mfrc522.uid.uidByte[i]; // Получение номера ключа
    uidDec = uidDec * 256 + uidDecTemp;  // Переводим номер ключа в дисятичный вид
  }
  //// Первый ключ считывание /////////////////////////////////////////////////////////////////////////////////////////////////////
  if (uidDec == keyBoss1_1 && key1_1_State == false)     // Если считанный номер ключа равен номеру ключа 1_1 и статус ключа 1_1 выклчен, то...
  {
    Serial.println("Первая половина ключа № 1 принята"); // Выводим в COM порт сообщение "Первая половина ключа № 1 принята"
    POLOVINA_KLYUCHA(); key1_1_State = true;             // Проигрываем мелодию половинки ключа, переводим состояние ключа 1_1 в включено
    delay(200);
  }
  if (uidDec == keyBoss1_2 && key1_2_State == false)     // Если считанный номер ключа равен номеру ключа 1_2 и статус ключа 1_2 выклчен, то...
  {
    Serial.println("Вторая половина ключа № 1 принята"); // Выводим в COM порт сообщение "Вторая половина ключа № 1 принята"
    POLOVINA_KLYUCHA(); key1_2_State = true;             // Проигрываем мелодию половинки ключа, переводим состояние ключа 1_2 в включено
    delay(200);
  }
  //// Первый ключ включаем
  if (key1_1_State == true && key1_2_State == true && alarmState == false) // Если статус ключа 1_1 вклчен, статус ключа 1_2 вклчен и сигнализация отключена, то...
  {
    digitalWrite(AlarmLED, HIGH); // Включаем LED индикатор "Сигнализация влючена"
    alarmState = true; BUZ_KLYUCH(); uidDec = 0;             // Переводим состояние сигнализации в включено, проигрываем мелодию ключ подошол, обнуляем номер ключа
    key1_1_State = false; key1_2_State = false;              // Переводим состояние ключа 1_1 и ключа 1_2 в выключено
    Serial.println(AlarmOn_K1);      // Выводим в COM порт сообщение "Гараж поставлен на охрану ключом № 1!"
    sms.SendSMS(Nomer1, AlarmOn_K1); // Отправляем SMS-сообщение "Гараж поставлен на охрану ключом № 1!"
    //sms.SendSMS(Nomer2, AlarmOn_K1); // Отправляем SMS-сообщение "Гараж поставлен на охрану ключом № 1!"
    //sms.SendSMS(Nomer3, AlarmOn_K1); // Отправляем SMS-сообщение "Гараж поставлен на охрану ключом № 1!"
  }
  //// Первый ключ отключаем
  if (key1_1_State == true && key1_2_State == true && alarmState == true) // Если статус ключа 1_1 вклчен, статус ключа 1_2 вклчен и сигнализация включена, то...
  {
    digitalWrite(AlarmLED, LOW); // Выключаем LED индикатор "Сигнализация влючена"
    alarmState = false; BUZ_KLYUCH(); uidDec = 0;      // Переводим состояние сигнализации в включено, проигрываем мелодию ключ подошол, обнуляем номер ключа
    key1_1_State = false; key1_2_State = false;        // Переводим состояние ключа 1_1 и ключа 1_2 в выключено
    Serial.println(AlarmOff_K1);      // Выводим в COM порт сообщение "Гараж снят с охраны ключом № 1!"
    sms.SendS

А строки типа "Serial.println(AlarmOff_K1); // Выводим в COM порт сообщение "Гараж снят с охраны ключом № 1!"" для отладки. потом их закоментирую.

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

Развелось много идиотов, с электошокерами. У всех у кого стояла сигнализация с ключами iButton, пожгли логику. 

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

Katapuf пишет:

А этот ответ:

Katapuf пишет:

Есть конечно предположение, что будет, но... я только учусь....

Не считается?

Конечно, нет. Вопрос: "как думаете". Ответ: "есть предположение". Я же не спрашивал есть у Вас предположение или нет, я спросил "каково оно". А ведь я всего лишь хотел Вам что-то объяснить, но не про коня в вакууме, а отталкиваясь от Вашего понимания вопроса (т.е. объяснить именно Вам, а не спорить с другими). Но Вы предпочли не отвечать на мой вопрос, дело Ваше. Мне, повторяю, пофиг. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ToRcH2565 пишет:
1) если нет необходимости в классе(хоть даже эстетической) - не нужно использовать его, используйте функции

Ну здесь это больше дело вкуса, а может просто не понимания инструмента. Вы что хотите, узнать что и как. Так что мой совет. Если вы не можете правильно работать с функциями, то работайте через классы.

ToRcH2565 пишет:
3) Логика работы рефреш в корне не верна =)
Вы потеряли перегрузку. Различие понимании на уровне пользователя объекта Dispay.refresh(). И разработчика этого класса Dispay.  Пользователю достаточно знать что есть метод refresh(). А полностью или частично обновиться экран пусть решает сам Dispay. Ну не зачем знать архитектору свечки в 36этаже "сколько лить Фейри в бетон", хотя поинтересоваться в марке бетона желательно и контроле заливки указав это на чертежах.

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

Katapuf пишет:
Вообще то это писал для себя и коментарии я писал для себя.

Я вас не учу, а советую как лучше, и лучше учится сразу делать правильно.

Katapuf пишет:
И чтобы не заблудиться у меня каждая строка кода, подробно прокоментированна.

Избыточне комментарии - захламление кода, к хорошему не приводит, проверено.

Katapuf пишет:
И по поводу: "любому кто будет с этим работать на уровне кода - будет не понятно...." еще раз я это делаю для себя

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

Katapuf пишет:

Вот кусок кода, что тут не понятного?

void ModuleKey()
{
  if ( ! mfrc522.PICC_IsNewCardPresent()) // Если нет нового ключа, то...
  {
    return;                               // Возвращаемся в начало
  }
  if ( ! mfrc522.PICC_ReadCardSerial())   // Если нечего не считали, то...
  {
    return;                               // Возвращаемся в начало
  }
  for (byte i = 0; i < mfrc522.uid.size; i++) // Подсчет серийного номера ключа.
  {
    uidDecTemp = mfrc522.uid.uidByte[i]; // Получение номера ключа
    uidDec = uidDec * 256 + uidDecTemp;  // Переводим номер ключа в дисятичный вид
  }
  //// Первый ключ считывание /////////////////////////////////////////////////////////////////////////////////////////////////////
  if (uidDec == keyBoss1_1 && key1_1_State == false)     // Если считанный номер ключа равен номеру ключа 1_1 и статус ключа 1_1 выклчен, то...
  {
    Serial.println("Первая половина ключа № 1 принята"); // Выводим в COM порт сообщение "Первая половина ключа № 1 принята"
    POLOVINA_KLYUCHA(); key1_1_State = true;             // Проигрываем мелодию половинки ключа, переводим состояние ключа 1_1 в включено
    delay(200);
  }
  if (uidDec == keyBoss1_2 && key1_2_State == false)     // Если считанный номер ключа равен номеру ключа 1_2 и статус ключа 1_2 выклчен, то...
  {
    Serial.println("Вторая половина ключа № 1 принята"); // Выводим в COM порт сообщение "Вторая половина ключа № 1 принята"
    POLOVINA_KLYUCHA(); key1_2_State = true;             // Проигрываем мелодию половинки ключа, переводим состояние ключа 1_2 в включено
    delay(200);
  }
  //// Первый ключ включаем
  if (key1_1_State == true && key1_2_State == true && alarmState == false) // Если статус ключа 1_1 вклчен, статус ключа 1_2 вклчен и сигнализация отключена, то...
  {
    digitalWrite(AlarmLED, HIGH); // Включаем LED индикатор "Сигнализация влючена"
    alarmState = true; BUZ_KLYUCH(); uidDec = 0;             // Переводим состояние сигнализации в включено, проигрываем мелодию ключ подошол, обнуляем номер ключа
    key1_1_State = false; key1_2_State = false;              // Переводим состояние ключа 1_1 и ключа 1_2 в выключено
    Serial.println(AlarmOn_K1);      // Выводим в COM порт сообщение "Гараж поставлен на охрану ключом № 1!"
    sms.SendSMS(Nomer1, AlarmOn_K1); // Отправляем SMS-сообщение "Гараж поставлен на охрану ключом № 1!"
    //sms.SendSMS(Nomer2, AlarmOn_K1); // Отправляем SMS-сообщение "Гараж поставлен на охрану ключом № 1!"
    //sms.SendSMS(Nomer3, AlarmOn_K1); // Отправляем SMS-сообщение "Гараж поставлен на охрану ключом № 1!"
  }
  //// Первый ключ отключаем
  if (key1_1_State == true && key1_2_State == true && alarmState == true) // Если статус ключа 1_1 вклчен, статус ключа 1_2 вклчен и сигнализация включена, то...
  {
    digitalWrite(AlarmLED, LOW); // Выключаем LED индикатор "Сигнализация влючена"
    alarmState = false; BUZ_KLYUCH(); uidDec = 0;      // Переводим состояние сигнализации в включено, проигрываем мелодию ключ подошол, обнуляем номер ключа
    key1_1_State = false; key1_2_State = false;        // Переводим состояние ключа 1_1 и ключа 1_2 в выключено
    Serial.println(AlarmOff_K1);      // Выводим в COM порт сообщение "Гараж снят с охраны ключом № 1!"
    sms.SendS

То что ваш код говорит одно, а комментарий обратное, это первое что непонятно в этом коде.

Например return никак не "Возвращаемся в начало", а диаметрально противоположное - завершаем выполнение функции и возвращаем значение, в вашем случае null.

Дальше непонятен не этот кусок кода в частности, а что именно происходит внутри программы, если появится баг - тому кто не знаком с кодом, придется перечитать весь код чтобы найти в чем проблемма, а не "оглавление" и сразу перейти к нужному участку(Привет ООП).

Дальше что мне не понятно, зачем вы расходуете ресурсы МК? если по незнанию то посмотрите описание оператора if, а точнее его полной версии if then else

 

Katapuf пишет:
А строки типа "Serial.println(AlarmOff_K1); // Выводим в COM порт сообщение "Гараж снят с охраны ключом № 1!"" для отладки. потом их закоментирую.

Тоже неверный подход... оно конечно карашо просто закоментировать, но(!) мой вам совет, используйте условную компиляцию:

 В начале программы обьявляем #define DEBUG

Ваш код для отладки обрамляем(в синтаксисе могу немного ошибатся):

#if defined DEBUG

  Serial.println(AlarmOff_K1);

#endif

Тогда этот код будет компилироватся только пока есть директива #define DEBUG, если ее убрать - код с примера выше скомпилирован не будет, и в МК не попадет.

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

Katapuf пишет:
И да этот скетч, а вернее готовое изделие уже работает, просто, как и говорил, хочеся добавить это, это, а еще вот это.

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

 

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

 

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

qwone пишет:

Ну здесь это больше дело вкуса, а может просто не понимания инструмента. Вы что хотите, узнать что и как. Так что мой совет. Если вы не можете правильно работать с функциями, то работайте через классы.

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

Поэтму если нет причин использовать класс - лучше использовать функцию.

qwone пишет:
Вы потеряли перегрузку.

Причем тут перегрузка?(опять могут быть различия в понимании терминов, я тяну все термины из программирования для ПК).

qwone пишет:
Различие понимании на уровне пользователя объекта Dispay.refresh(). И разработчика этого класса Dispay. 
Не спорю ни чуть, о чем написал в самом низу =) 

qwone пишет:
Ну не зачем знать архитектору свечки в 36этаже "сколько лить Фейри в бетон", хотя поинтересоваться в марке бетона желательно и контроле заливки указав это на чертежах.

Ровно до момента "У меня нехватило бетона" и "Мне нужен МК с 200мгц и 30 мб памяти"

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

ToRcH2565 пишет:

оно конечно карашо просто закоментировать, но(!) мой вам совет, используйте условную компиляцию:

 В начале программы обьявляем #define DEBUG

Ваш код для отладки обрамляем(в синтаксисе могу немного ошибатся):

#if defined DEBUG

  Serial.println(AlarmOff_K1);

#endif

Тогда этот код будет компилироватся только пока есть директива #define DEBUG

ИМХО, несколько утомительно вокруг каждого вывода в Сериал писать операторы условной компиляции. Вот такой вариант мне нравится больше - подсмотрел у кого-то из местных гуру:

// определяем отдельные операторы отладлчной печати
#ifdef DEBUG
 #define DEBUG_PRINT(x)     Serial.print(x)
 #define DEBUG_PRINTDEC(x)     Serial.print(x, DEC)
 #define DEBUG_PRINTLN(x)  Serial.println(x)
#else
 #define DEBUG_PRINT(x)
 #define DEBUG_PRINTDEC(x)
 #define DEBUG_PRINTLN(x)
#endif 
.....
// в коде программы отладочный вывод печатаем как

DEBUG_PRINTLN(AlarmOff_K1) ;

 

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

b707 пишет:

ИМХО, несколько утомительно вокруг каждого вывода в Сериал писать операторы условной компиляции. Вот такой вариант мне нравится больше - подсмотрел у кого-то из местных гуру:

// определяем отдельные операторы отладлчной печати
#ifdef DEBUG
 #define DEBUG_PRINT(x)     Serial.print(x)
 #define DEBUG_PRINTDEC(x)     Serial.print(x, DEC)
 #define DEBUG_PRINTLN(x)  Serial.println(x)
#else
 #define DEBUG_PRINT(x)
 #define DEBUG_PRINTDEC(x)
 #define DEBUG_PRINTLN(x)
#endif 
.....
// в коде программы отладочный вывод печатаем как

DEBUG_PRINTLN(AlarmOff_K1) ;

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

b707 пишет:
вокруг каждого вывода в Сериал писать операторы условной компиляции

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

Katapuf
Offline
Зарегистрирован: 16.05.2018

ToRcH2565 пишет:

Дальше что мне не понятно, зачем вы расходуете ресурсы МК? если по незнанию то посмотрите описание оператора if, а точнее его полной версии if then else

А вот тут если можно то поподробней.

Это из-за того, что не использовал "else" или ....

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ToRcH2565 пишет:
Это я сказал по другой причине, вызов метода намного более тяжелая операция чем вызов функции.Поэтму если нет причин использовать класс - лучше использовать функцию.
Но чаще проблема не в тяжелости операции, а в написании и отладке программы, выявление более эффективной структуры. Удачная и эффективная структура больше экономит ресурсы МК, чем тяжесть операции. А потом уже можно методы поменять на легкие функции при уже рабочей программе. Но вот с функций переходить на методы тяжелее.Особенно если структура программы превращается в хаос.

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

Katapuf пишет:

А вот тут если можно то поподробней.

Это из-за того, что не использовал "else" или ....

if then else - да, из за того что вы его не использовали, хотя почему - не понятно, состояния у вас внутри конструкции не меняются настолько чтобы последовательно могли выполнится все if. 

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

Еще дальше было сказано что есть штука Switch case, почему не ее использовали? 

Давайте пройдемся по вашему коду..:

void ModuleKey()
{
  if(!(mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())) return;

  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
    uidDecTemp = mfrc522.uid.uidByte[i]; 
    uidDec = uidDec * 256 + uidDecTemp;  
  }

  if(!key1_1_State || !key1_2_State)
  {
    if (uidDec == keyBoss1_1 && !key1_1_State)
    {
      Serial.println("Первая половина ключа № 1 принята");
      POLOVINA_KLYUCHA(); key1_1_State = true;
      delay(200);
    }else
    if (uidDec == keyBoss1_2 && !key1_2_State)
    {
      Serial.println("Вторая половина ключа № 1 принята");
      POLOVINA_KLYUCHA(); key1_2_State = true;
      delay(200);
    }
  } 
  if (key1_1_State && key1_2_State && !alarmState)
  {
    digitalWrite(AlarmLED, HIGH); 
    alarmState = true; BUZ_KLYUCH(); uidDec = 0;
    key1_1_State = false; key1_2_State = false;
    Serial.println(AlarmOn_K1);
    sms.SendSMS(Nomer1, AlarmOn_K1);
  }else
  {
    digitalWrite(AlarmLED, LOW);
    alarmState = false; BUZ_KLYUCH(); uidDec = 0;
    key1_1_State = false; key1_2_State = false;
    Serial.println(AlarmOff_K1);
    sms.SendS
  }
}

Сравнивайте, это "на коленке" и не вдаваясь в подробности, больше чем уверен код можно сделать еще более воспринимаемым если вчитыватся...

ToRcH2565
Offline
Зарегистрирован: 16.05.2015

qwone пишет:

Но чаще проблема не в тяжелости операции, а в написании и отладке программы, выявление более эффективной структуры. Удачная и эффективная структура больше экономит ресурсы МК, чем тяжесть операции. А потом уже можно методы поменять на легкие функции при уже рабочей программе. Но вот с функций переходить на методы тяжелее.Особенно если структура программы превращается в хаос.

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

Но делать класс ради использования один раз одного метода из него за весь код проэкта - не хорошая идея.