Еще раз мигаем светодиодом без Delay

Draghkon
Offline
Зарегистрирован: 17.09.2013

Такой вопрос мучает: 

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

К примеру - есть функция которая получает скорость вращения вентилятора, и задает её. И в ней есть такой момент, что если полученная скорость ниже определенного порога, то нужно дать толчек: задать скорость 255 на 500мс, а потом установить ту скорость которая нужна, иначе стоячий вентилятор не запустится на низких оборотах.

С delay это одна строчка delay(500);

но это вешает всю программу.  

Библиотека SimpeTimer имеет инструмент .SetTimeout но он требует в параметрах функцию, которую будет запускать, причем void без параметров.

Сама же функция задания скорости вентилятора запускается с интервалом 10сек, т.е. мы не можем просто написать проверку millis, потому что следующий проход будет через 10сек, а не через 500мс.

Вопрос как быть?

Дело в том, что отрезать часть фукнции исполняющуюся после паузы 500мс, и вызывать её через тот же .SetTimeout мы не можем, т.к. там фигурирует значение value полученное как параметр - значит придется объявлять эту переменную глобально? это плохо.. да и вообще плодить лишние функции не хорошо..

А учитывая что таких моментов в скетче наберется с десяток..

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

вот привожу пример функции

void fanCheck()
{

	if (tempAir.value >= thisSet.maxTemp && tempAir.lastst<tempAir.value){ //если темперарута  больеш рекомендуемой и растет
		fanPwr.value += FAN_STEP;//увечичиваем скорость на шаг

	}
	else if (tempAir.value <= thisSet.maxTemp && tempAir.lastst>tempAir.value){ //если меньше рекомендуемой и падает
		fanPwr.value -= FAN_STEP;//уменьшаем скорость на шаг
	};
	fanSetSpeed(fanPwr.value); //задаем скорость вращение
	//ждем новой проверки время fanPwr.interval
}

void fanSetSpeed(int value) //устанавливаем скорость вентилятора
	if (value < 100){ //если скорость ниже 100 - дать толчек
		fanMotor.setSpeed(120);
		//дать раскрутиться 500мс
	};
//устанавливаем полученное значение
	if (value > thisSet.fanMaxPwr){ fanPwr.value = thisSet.fanMaxPwr; } //но не более максимальной
	else if (value < thisSet.fanMinPwr){ fanPwr.value = thisSet.fanMinPwr; }; //но не менее минимальной
	fanMotor.setSpeed(value);

}

 

laser
Offline
Зарегистрирован: 20.02.2014

реально ли Вашим способом переделать такой код:

for(i=0; i<l; i++) {
    if (binOUT[i]==1) {
      digitalWrite(ledPin,HIGH);
      delay(950);
      digitalWrite(ledPin, LOW);
      delay(50);
    }
    else {
      digitalWrite(ledPin, HIGH);
      delay(450);
      digitalWrite(ledPin, LOW);
      delay(50);
      digitalWrite(ledPin, HIGH);
      delay(450);
      digitalWrite(ledPin, LOW);
      delay(50);
    }
  }

 

maksim
Offline
Зарегистрирован: 12.02.2012

Конечно.

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

Когда я вижу решения "мигания без задержки", меня всегда коробит... Ни разу не увидел, что бы кто то учел возможность перехода millis() через 0... Почему ? Ведь это колдовство может привести к тому, что "диод загориться" на  50 дней :)

maksim
Offline
Зарегистрирован: 12.02.2012

brokly пишет:

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

Потому что плохо смотрели. Именно в такой конструкции переполнение учтено:

  if(millis() - previousMillis > INTERVAL) 

 

Draghkon
Offline
Зарегистрирован: 17.09.2013

Ну при переходе через ноль, милис будет меньше чем предыдущее, и соотв. результат будет отрицательным и сравнение не выполнится.

Поэтому я сравниваю значение по модулю. Т.е. сравниваю с интервалом корень квадратный из квадрата разницы между millis() и previousMillis

maksim
Offline
Зарегистрирован: 12.02.2012

Draghkon пишет:

Ну при переходе через ноль, милис будет меньше чем предыдущее, и соотв. результат будет отрицательным и сравнение не выполнится.

Поэтому я сравниваю значение по модулю. Т.е. сравниваю с интервалом корень квадратный из квадрата разницы между millis() и previousMillis

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

leshak
Offline
Зарегистрирован: 29.09.2011

Вопрос уже поднимался выше по ветке.

Draghkon пишет:

Ну при переходе через ноль, милис будет меньше чем предыдущее, и соотв. результат будет отрицательным и сравнение не выполнится.

Это ложное утверждение. Скетч из сообщения #18 доказывает обратное.

Draghkon пишет:

Поэтому я сравниваю значение по модулю. Т.е. сравниваю с интервалом корень квадратный из квадрата разницы между millis() и previousMillis

Если посмотреть в справочник, то можно найти готовую функцию "модуль" http://arduino.ru/Reference/Abs

Не столь тяжелую (кстати, интерестно как вы без танцев с бубуном возведете в квадрат, скажем число 4294967295).

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

 

 

 

Kontra
Offline
Зарегистрирован: 10.07.2013

Уважаемый Леший, подскажите пожалуйста, как я могу по кнопке менять параметр

#define  BLINK_INTERVAL  5000UL  // интервал между включение/выключением светодиода (5 секунд)

?

Если задавать этот параметр как

int  BLINK_INTERVAL  5000  // интервал между включение/выключением светодиода (5 секунд)

то код не работает.

Спасибо!

maksim
Offline
Зарегистрирован: 12.02.2012
leshak
Offline
Зарегистрирован: 29.09.2011

Araris пишет:

leshak, с возвращением ?

К сожалению, пока еще нет. Но я надеюсь...

Piskunov
Offline
Зарегистрирован: 13.02.2014

А чем плох такой вариант:

digitalWrite(LED_BUILTIN, (millis() % 1000ul) / 500ul);

 

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

Народ, можете объяснить, почему все всегда определяют

#define LED_PIN  13

когда есть заранее определённая (в системе) константа

LED_BUILTIN

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

Для чего дублировать системную константу? Не могу понять почему, но раз все так делают, должна же быть какая-то причина?

vk007
Offline
Зарегистрирован: 16.06.2015

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

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

1 - я про неё даже и не знал :)
2 - типерь знаю , но всё равно буду применять-определять свои - #define ledPinOK 9 , #define ledPinErr A0 , #define ledPinClk 7
...... просто я так хочу и мне удобнее ( а компилятор сам решит что включать в код - дублирования не будет )

причина - личное дело-мнение каждого :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

vk007 пишет:

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

аха :)

Клапауций 999
Offline
Зарегистрирован: 06.06.2015

потревожу избитую и всем понятную тему оптимизации кода мигания без делау.

но, чёрт возьми, почему

static unsigned long previousMillis = 0;        // храним время последнего переключения светодиода

если в реальности

static unsigned long previousMillis = millis();

 

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

Draghkon пишет:

Сама же функция задания скорости вентилятора запускается с интервалом 10сек, т.е. мы не можем просто написать проверку millis, потому что следующий проход будет через 10сек, а не через 500мс.

Вопрос как быть?

Встречный вопрос, а почему бы следующий проход не сделать 0.5 сек?

Притом, реализовыать это можно, минимум,двумя способами:

1. Цикл ВСЕГДА 0.5 сек, но внутри такого цикла есть дополнительная проверка на 10 сек, по результатам которой и выполняется 10-секундный код.

2. Длину интервала между проходами можно хранить в переменной, которая обычно равна 10000 мс, но иногда переопредлеляется на 500.

Цитата:

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

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

Если же нужно сделать именно так: программа работает до определенной границы, затем прерывается, а потом начинает выполнение с этой границы, то нужно ввести переменную состояния. При одном значении состояния выполняется код от начала loop до границы, а при другом - от границы до конца loop. В конце первого блока переменная переводится во второе состояние,  в конце второго - возвращается в первое. Ну а интервал времени, в течение которого прерывается выполнение программы, реализуется так же, как и "мигаем светодиодом без delay".

Zahar
Zahar аватар
Offline
Зарегистрирован: 16.11.2013

leshak спасибо за #32 пост. Очень помогло в написании кода.

Maxim Z.
Offline
Зарегистрирован: 12.01.2016

leshak пишет:

Молодчина.

Спасибо за простые и понятные разъяснения!

PM007
Offline
Зарегистрирован: 09.05.2016

Здравствуйте,

Подскажите как мигнуть без задержки 1-2 раза при определеном условии

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

PM007 пишет:

Подскажите как мигнуть без задержки 1-2 раза при определеном условии

if (определенное условие)
{
  // мигаем первый раз
  digitalWrite(LEDpin, HIGH);
  digitalWrite(LEDpin, LOW);

  // мигаем второй раз
  digitalWrite(LEDpin, HIGH);
  digitalWrite(LEDpin, LOW);
}

Как Вы и написали - без задержки и по определённому условию. Но мигание это Вы не увидите, т.к. слишком быстро.

PM007
Offline
Зарегистрирован: 09.05.2016

:))) 

Так и я умею...

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

Может 1,2,3 Гц

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

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

PM007 пишет:

:для человека.. так что он должен заметить..

1мс вполне заметно. Проверено.

PM007
Offline
Зарегистрирован: 09.05.2016

Я думаю это не принципиальный вопрос... но думаю надо хоть 100 мс

Мне надо просто при наступлении события моргнуть один два раза

И желательно использовать мо меньше процессорного времени..

Я не могу позволить себе потерять на задержку 100 мс

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Ясно, я просто неправильно понял. Вам нужно без delay(), но с millis(). Хорошо, в чём конкретно у Вас возникла проблема? Где Ваш скетч?

PM007
Offline
Зарегистрирован: 09.05.2016

Да все верно...

Я принимаю данные  и хотелось сделать индикацию приема...

Но вот куда это примостить .. данные принимаются по рпириванию

Пробовал примостить за функцией записи в память

Так те варианты которые есть работают не корректно

то включат то выключат светодиод... а хотел 4 раза мигнуть..

for (int i=0; i <= 4; i++){
           if(millis() - previousMillis > INTERVAL) {   
              previousMillis = millis();                        
              digitalWrite(LED_PIN,!digitalRead(LED_PIN));   
             }                                                
          }  
Jatixo
Offline
Зарегистрирован: 13.01.2016






byte modeLed = 0;


if(надо моргнуть)
	modeLed = 1;


if(modeLed != 0 && millis() - previousMillis > INTERVAL) {
	previousMillis = millis();
	digitalWrite(LED_PIN, !digitalRead(LED_PIN));
	if(modeLed < 4)
		modeLed++;
	else
		modeLed = 0;
}

Ну тут правда, если например интервал 5 секунд, то первые 5 секунд после загрузки моргание не будет срабатывать, если конечно не задать какой-нибудь огромный previousMillis, вместо 0, так-то можно постараться все учесть, но думаю при Ваших 100 мс, ничего страшного.

Здесь 2 раза мигнет, если надо 4, то 4 надо исправить на 8. И вообще весь if-else можно заменить на



modeLed = ++modeLed%4;

И получится

if(modeLed != 0 && millis() - previousMillis > INTERVAL) {
	previousMillis = millis();
	digitalWrite(LED_PIN, !digitalRead(LED_PIN));
	modeLed = ++modeLed%4;
}

 

PM007
Offline
Зарегистрирован: 09.05.2016

Спасибо большое...

Завтра попробую

Вот вопрос а что означает 

modeLed = ++modeLed%4;

Оно взаимо зменяемо с

modeLed++

Какую роль играет %

Хотя если я правильно понял по условию

modeLed должно превратится в 0...

Jatixo
Offline
Зарегистрирован: 13.01.2016

Это заменяет if-else, при первом проходе переменная изменяется с 1 на 2, при втором с 2 на 3, затем с 3 на 0 и мигание прекращается до следующего запуска, кстати если попадет так, что светодиод светится в процессе мигания, а где-то в коде сработает modeLed = 1; то цикл закончится на включенном светодиоде, это можно избежать проверкой не идет ли уже мигание при присваивании = 1 или сам код изменять, чтобы в конце всегда заканчивалось на выключении.

++ прибавляет +1. Если находится перед переменной, то сначала переменная изменяется (+1), а затем возвращается уже измененная, а если после переменной ++, то сначала возвращается текущее значение, а потом прибавляется +1. Поэтому не взаимозаменяемо.












modeLed  = 1;

value = ++modeLed; // value будет равно 2, modeLed тоже 2



modeLed  = 1;

value = modeLed++; // value будет равно 1, а modeLed 2

% - остаток от деления, то есть / делит, а % - это остаток, значит 1%4 = 1, 2%4=2, 3%4=3, 4%4=0 (5%4=1, 6%4=2, 7%4=3, 8%4=0)

PM007
Offline
Зарегистрирован: 09.05.2016

Спасибо

Я очень благодарен за информацию...

Буду завтра делать :)

PM007
Offline
Зарегистрирован: 09.05.2016

Да получается что мигает но не совсем так...

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

Как заставить доработать до конца?

PM007
Offline
Зарегистрирован: 09.05.2016

Этот код корректно выполняется только один раз...

При повторных вызовах от сбивается и работает не корректно... modeLed принимает такие значения..

modeLed  2   mode  1
modeLed  2   mode  2
modeLed  2   mode  3
modeLed  2   mode  4
modeLed  2   mode  5
modeLed  3   mode  6
modeLed  0   mode  7
 

 

PM007
Offline
Зарегистрирован: 09.05.2016
  if ( Условие или без условия ){
       if (modeLed == 4) {
           modeLed = 0;
          }
   }  
  
  
  if (modeLed < 4 && millis() - previousMillis > INTERVAL) {
          previousMillis = millis();
          digitalWrite(LED_PIN, !digitalRead(LED_PIN));
          modeLed++; 
          }
   
    

Все гениальное просто :) Спасибо за идею...

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

Jatixo
Offline
Зарегистрирован: 13.01.2016

Упс... там раньше не  modeLed = ++modeLed%4;, а  modeLed = ++modeLed%5; иначе будет включенным оставаться и когда не часто, а чтобы и при часто работало, то так:




byte modeLed = 0;


if(надо моргнуть)
	modeLed = 1;


if(modeLed != 0 && millis() - previousMillis > INTERVAL) {
	previousMillis = millis();
	bool stateLed = digitalRead(LED_PIN);
	digitalWrite(LED_PIN, !stateLed);
	if(!(modeLed == 4 && stateLed == LOW))
		modeLed = ++modeLed%5;
}

Попробуйте, должно быть идеально =)

PM007
Offline
Зарегистрирован: 09.05.2016
if(!(modeLed == 4 && stateLed == LOW))

Эта строчка что бы не остался включенным, за следующим кругом погасит?  

Jatixo
Offline
Зарегистрирован: 13.01.2016

Да

sashamass
Offline
Зарегистрирован: 20.09.2016

Помогите начинающему.

Запутался с миллис. Задача контроля исполнения функции за промежуток времени.

Т.е. после сработки датчика1 происходит цикл действий и система возвращается к датчику1, так вот если время цикла заняло больше 30 секунд включаем светодиод  об аварийной ситуации, если менее 30 секунд обнуляем  миллис и цикл продожается.

PM007
Offline
Зарегистрирован: 09.05.2016

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

И я так понял что это надо делать в цыкле....

jahmal
Offline
Зарегистрирован: 01.06.2016

Всем добрых суток времени.

У меня такой вопрос.

Можно ли в этой функции заменить стандартную конструкцию c использованием

	previous = millis();

, на пример от leashak?

int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout)
{
	uint8_t x = 0, answer = 0;
	char response[100];
	unsigned long previous;
	memset(response, '\0', 100); // Initialice the string
	delay(100);
	
	while( Serial2.available() > 0) Serial2.read(); // Clean the input buffer
	Serial2.println(ATcommand); // Send the AT command
	x = 0;
	previous = millis();

// this loop waits for the answer
	do
	{
// if there are data in the UART input buffer, reads it and checks for the asnwer
		if(Serial2.available() != 0)
		{
			response[x] = Serial2.read();
			if (x < sizeof(response) - 1) x++;
// check if the desired answer is in the response of the module
			if (strstr(response, expected_answer) != NULL)
			{
				answer = 1;
			}
		}
// Waits for the asnwer with time out
	}
	while((answer == 0) && ((millis() - previous) < timeout));
	Serial.println(response);
	return answer;
}

 

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

jahmal пишет:

Можно ли в этой функции

В какой "этой"?

jahmal
Offline
Зарегистрирован: 01.06.2016

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

jahmal пишет:

Можно ли в этой функции

В какой "этой"?

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

Ну, тогда поясняйте что на что Вы хотите заменить

jahmal
Offline
Зарегистрирован: 01.06.2016

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

Ну, тогда поясняйте что на что Вы хотите заменить

Я желаю чтобы не происходило переполнение перменной previous, тут как бы вся тема этому посвященна...

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

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

jahmal
Offline
Зарегистрирован: 01.06.2016

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

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

Зарание извеняюсь! Тупость с моей стороны...

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

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

Если программа работает нормально, а потом вдруг перестаёт, я бы посмотрел на памятьЮ особенно динамическую. В одном месте по крйней мере она у Вас используется явно неоправданно. Я имею в виду строку 437. Почему бы вместо

Serial2.println("AT+HTTPPARA=\"URL\",\"gsmserver.esy.es/get.php?i=" + String((char*)commandbuffer) + "\"");

не написать

Serial2.print("AT+HTTPPARA=\"URL\",\"gsmserver.esy.es/get.php?i=");
Serial2.print(commandbuffer);
Serial2.println("\"");

и избавиться от динамического запроса памяти при создании экземпляра String?

Ошибка стаблильна? Или каждый раз в новом месте? Если не знаете. понаставьте во все функции печати при входе и при выходе и следите за прохождением программы. Так Вы обнаружите в каком месте беда впервые проявляется. Может оглядитесь повнимательнее и поймёте причину.

Опять же не помешает иногда печатать отчёт о расходовании памяти. Если расход накапливается - значит стопудово ломается при переполнении - надо искать причину переполнения.

jahmal
Offline
Зарегистрирован: 01.06.2016

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

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

Если программа работает нормально, а потом вдруг перестаёт, я бы посмотрел на памятьЮ особенно динамическую. В одном месте по крйней мере она у Вас используется явно неоправданно. Я имею в виду строку 437. Почему бы вместо

Serial2.println("AT+HTTPPARA=\"URL\",\"gsmserver.esy.es/get.php?i=" + String((char*)commandbuffer) + "\"");

не написать

Serial2.print("AT+HTTPPARA=\"URL\",\"gsmserver.esy.es/get.php?i=");
Serial2.print(commandbuffer);
Serial2.println("\"");

и избавиться от динамического запроса памяти при создании экземпляра String?

Ошибка стаблильна? Или каждый раз в новом месте? Если не знаете. понаставьте во все функции печати при входе и при выходе и следите за прохождением программы. Так Вы обнаружите в каком месте беда впервые проявляется. Может оглядитесь повнимательнее и поймёте причину.

Опять же не помешает иногда печатать отчёт о расходовании памяти. Если расход накапливается - значит стопудово ломается при переполнении - надо искать причину переполнения.

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

Нашел такую библиотеку, получается мне надо выводить кол-во свободной памяти в каждой функции или можно в одном месте loop()?

понаставьте во все функции печати при входе и при выходе - Это при помощи Serial.print? Просто совсем далек от программирования, а помидорки хочется :D

 

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

jahmal пишет:

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

Дело даже не в том, что много, а в том, что часто. Вот посмотрите, я только сегодня пример приводил как часто она дергает память.

jahmal пишет:
Нашел такую библиотеку, получается мне надо выводить кол-во свободной памяти в каждой функции или можно в одном месте loop()?

Думаю, для начала в loop и посмотреть не растёт ли расход, ну и сколько там всего свободной. Если надо будет. то в другие места потом можно вставить.

jahmal пишет:
Это при помощи Serial.print?

Ну, да. Просто чтобы понимать "вошла сюда", "вышла отсюда" и следить за её путём. Это обычная практика.

 

vinam
Offline
Зарегистрирован: 19.03.2016

Здравствуйте.

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

Хочу чтоб работало так:

сигнал с концевика есть - на 2 сек. двигатель включился вперед и выключился,

нет сигнала - на 2 сек. двигатель включился назад и выключился,

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

// Назначения пинов колес
#define LeftWheelForward 2		// Левое Колесо Вперед
#define LeftWheelBack 3			// Левое Колесо Назад

#define RightWheelForward 4		// Правое Колесо Вперед
#define RightWheelBack 5		// Правое Колесо Назад

#define LeftGerkon 14			// Левый концевик Аналоговый вход А0
#define RightGerkon 15			// Правый концевик Аналоговый вход А1

#define TimeOpCl	2000UL		// Время


void setup()	{
	pinMode(LeftWheelForward, OUTPUT);
	pinMode(LeftWheelBack, OUTPUT);
	pinMode(RightWheelForward, OUTPUT);
	pinMode(RightWheelBack, OUTPUT);

	pinMode(LeftGerkon, INPUT);
	pinMode(RightGerkon, INPUT);

}


void loop()	{

	LeftMotorOn();
//	LeftMotorOff();

}


// Функция вкл. левого мотора
void LeftMotorOn()	{
	static unsigned long previousMillis = 0;	// храним время последнего переключения

	if(digitalRead(LeftGerkon) == LOW)	{	
		digitalWrite(LeftWheelForward, HIGH);
		digitalWrite(LeftWheelBack, LOW);
			if(millis() - previousMillis > TimeOpCl)	{
				previousMillis = millis();
				digitalWrite(LeftWheelForward, LOW);
				digitalWrite(LeftWheelBack, LOW);
			}
	}

	else if(digitalRead(LeftGerkon) == HIGH)	{			
		digitalWrite(LeftWheelForward, LOW);
		digitalWrite(LeftWheelBack, HIGH);
			if(millis() - previousMillis > TimeOpCl)	{
				previousMillis = millis();
				digitalWrite(LeftWheelForward, LOW);
				digitalWrite(LeftWheelBack, LOW);
		}
	}
}