Не могу избавиться от delay.

nezza_profi
Offline
Зарегистрирован: 26.08.2016

Здравствуйте. Перенес тему в данный раздел.  До этого тема было создана в разделе проекты.

Помогите избавиться от delay.

Из за delay пропускаю сигнал с сенсора подключенного к 4 пину.

   #define start 2 		// Кнопка старт.
   #define fault 3 		// Аварийная кнопка.
   #define sensor 4		// Пауза


   long previousMillis = 0;


   int startbuttonState = 0;
   int faultbuttonState = 0;
   int sensorState = 0;

   // Таймер для стартовой скорости.
   int timerstart = 0;
   int timerstartval = 0;           // переменная для хранения считываемого значения
   int timerstartvalmap = 0;


   // Скорость статровой скорости.
   int speedstart = 1;
   int speedstartval = 0;           // переменная для хранения считываемого значения
   int speedstartvalmap = 0;

   // Таймер для скорости укладывания.

   int timersecond = 2;
   int timersecondval = 0;           // переменная для хранения считываемого значения
   int timersecondvalmap = 0;

   // Скорость укладывания
   int speedsecond = 3;
   int speedsecondval = 0;           // переменная для хранения считываемого значения
   int speedsecondvalmap = 0;

   // Таймер для скорости возврата.

   int timerback = 4;
   int timerbackval = 0;           // переменная для хранения считываемого значения
   int timerbackvalmap = 0;

   // Скорость возврата.
   int speedback = 5;
   int speedbackval = 0;           // переменная для хранения считываемого значения
   int speedbackvalmap = 0;

   // Таймер для паузы.

   int timerpause = 6;
   int timerpauseval = 0;           // переменная для хранения считываемого значения
   int timerpausevalmap = 0;

   int pwmOut =  11;      


	 

   void setup() {

     pinMode(pwmOut, OUTPUT);
     
     pinMode(start, INPUT);
   }

   void loop() {
   //таймер стартовой скорости
   timerstartval = analogRead(timerstart);     // считываем значение
   timerstartvalmap = map(timerstartval, 0, 1023, 0, 2000);
   //стартовая скорость  
   speedstartval = analogRead(speedstart);     // считываем значение
   speedstartvalmap = map(speedstartval, 0, 1023, 0, 255); 

   //таймер скорости укладвания
   timersecondval = analogRead(timersecond);     // считываем значение
   timersecondvalmap = map(timersecondval, 0, 1023, 0, 2000);
   //скорость укладывания
   speedsecondval = analogRead(speedsecond);     // считываем значение
   speedsecondvalmap = map(speedsecondval, 0, 1023, 0, 255); 

   //таймер скорости возврата
   timerbackval = analogRead(timerback);     // считываем значение
   timerbackvalmap = map(timerbackval, 0, 1023, 0, 3000);
   //скорость возврата
   speedbackval = analogRead(speedback);     // считываем значение
   speedbackvalmap = map(speedbackval, 0, 1023, 0, 255); 
    
   //таймер паузы
   timerpauseval = analogRead(timerpause);     // считываем значение
   timerpausevalmap = map(timerpauseval, 0, 1023, 0, 5000); 
    
     startbuttonState = digitalRead(start);
     faultbuttonState = digitalRead(fault); 
     sensorState = digitalRead(sensor);
     
     if (startbuttonState == HIGH && faultbuttonState == LOW) {
      
     // При нажатии кнопки старт. Задать ШИМ сигнал равный переменной speedstartvalmap
     
     analogWrite(pwmOut, speedstartvalmap); 
     delay(timerstartvalmap);
     
     // По истечению времени таймера переменной timerstartvalmap. Задать ШИМ сигнал равный переменной speedsecondvalmap
     
     analogWrite(pwmOut, speedsecondvalmap); 
     delay(timersecondvalmap);
     
     // По истечению времени таймера переменной timersecondvalmap. Задать ШИМ сигнал равный переменной speedbackvalmap
     
     analogWrite(pwmOut, speedbackvalmap); 
     delay(timerbackvalmap); 
    
     // Держать заданный ШИМ сигнал равный переменной speedbackvalmap до того момента как сенсор не увидит препятствие.
     
     analogWrite(pwmOut, 0);   
     delay(timerpausevalmap);
     
     // Держать паузу таймера переменной timerpausevalmap
     
       }
     else {
       analogWrite(pwmOut, 0);
     }
     

     
   }

 

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

Не нужно избавляться от delay, нужно сразу писать программы без delay.

Нарисуйте блок схему Вашей нынешней программы.

Нарисуйте блок схему программы без delay.

Сравните эти две схемы и убедитесь, что они не имеют практически ничего общего.

Отсюда вывод: чтобы избавитьсяч от delay, нужно полностью переписать программу заново. 

Можно оставить блок описания переменных (но все равно его придется редактировать) и функцию setup. А вот loop нужно переписывать полностью - в соответствии с новой блок-схемой.

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

Но, тут надо либо переписывать программу целиком, либо сделать самогонный delay и в нём читать дачтик (и, видимо, если что-то интересное прочиталось, то прерывать delay). Тогда просто всё delay заменить на этот самогонный.

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

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

... либо сделать самогонный delay ...

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

nezza_profi
Offline
Зарегистрирован: 26.08.2016

Можете показать небольшой пример? А дальше я постараюсь добраться до истины сам. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Это чтобы суть передать:

uint8_t sensorPin = 4;
uint32_t delayTime = 1000;
uint32_t startTime = millis();

while (millis() - startTime < delayTime) {
     if digitalRead(sensorPin) { break; }
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

Самый простой путь обсуждали недавно. Делай имеет подрограмму уелд. Если в неё повесить копию строк 92, 113 и между ними if на sensorState то всё будет останавливаться сразу по сенсору, но всё равно ждать окончания делэй.

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

nezza_profi пишет:

Можете показать небольшой пример? А дальше я постараюсь добраться до истины сам. 

Чуть позже, сегодя. Заходите в тему. Сейчас не могу.

nezza_profi
Offline
Зарегистрирован: 26.08.2016

Все еще  ни как не могу додумать)) как заставить держать ШИМ сигнал равной переменной speedbackvalmap до того момента пока не поступит сигнал на 4 пин.

Пробывал уже и так)) 


  unsigned long backcurrentMillis = millis();
      while (millis() - backcurrentMillis < timerbackvalmap)
      
  {
  analogWrite(pwmOut, speedbackvalmap); 
  }
  sensorState = digitalRead(sensor);
  
  
while (sensorState == HIGH)
{
analogWrite(pwmOut,0);
break;
}

 

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

Вот пример самогонного delay. Испольуете вместо обычного и проверяете как она закончилась - по истечению  интервала или по другому событию. В зависимости от этого что-то там у себя делаете.

//
// Пример прерываемого delay
// Ждет period миллисекунд или пока на пине 2 не появится HIGH (что вперёд)
// Возвращает true если истёк период времени или false, если на пине 2 появился HIGH
//
bool myDelay(const uint32_t period) {
	for (const uint32_t start = millis(); millis() - start < period; ) {
		if (digitalRead(2)) return false;
	}
	return true;
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Кстати, вопрос: for() вместо while() - это как чередование макарон и картошки в питании или всё же какой-то способ однозначно выигрышней в применении, которое выше проиллюстрированно?

nezza_profi
Offline
Зарегистрирован: 26.08.2016

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

sadman41
Offline
Зарегистрирован: 19.10.2016

nezza_profi пишет:

но я что то совсем не могу сообразить как это работает.

А вы всегда себя на место комплюктора ставьте. Как бы вы действовали в заданных вами обстоятельствах?

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

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

const uint32_t start = millis(); 
while (millis() - start < period) {
    ...
}

до конца функции

Можно, конечно, написать и так

{
    const uint32_t start = millis(); 
    while (millis() - start < period) {
        ...
    }
}

но это как-то вычурно и надумано.

А вообще, я об этом (об областях видимости) не думаю. Я в программировании почти сорок лет - надумался уже - теперь само делается :)

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

nezza_profi пишет:

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

А чего тут соображать? Выполняет строчку 8 снова и снова до тех пор пока интервал времени не истечёт.

nezza_profi
Offline
Зарегистрирован: 26.08.2016

Сейчас мое чудо работает так.

Задается ШИМ сигнал с переменной speedstartvalmap

держет ее опреденное количество времени из переменной timerstartvalmap

задает ШИМ сигнал с переменной speedsecondvalmap ждет истечение времени заданной перемменной timerbackvalmap

и задает ШИМ сигнал с переменной speedbackvalmap и по кругу. Не могу остановить на ШИМ сигнале равной speedbackvalmap до тех пор пока не придет сигнал с 4 пина и сбросить его на 0. Если попасть во время сигналом с 4 пина то могу задать ШИМ значением 0 и отправить его на delay.

#define start 2 // Кнопка старт.
#define fault 3 // Аварийная кнопка.
#define sensor 4 // Пауза

long startpreviousMillis = 0;
long secondpreviousMillis = 0;
long backpreviousMillis = 0;
long pausepreviousMillis = 0;


int startbuttonState = 0;
int faultbuttonState = 0;
int sensorState = 0;

// Таймер для стартовой скорости.
int timerstart = 0;
int timerstartval = 0;           // переменная для хранения считываемого значения
long timerstartvalmap = 0;


// Скорость статровой скорости.
int speedstart = 1;
int speedstartval = 0;           // переменная для хранения считываемого значения
int speedstartvalmap = 0;

// Таймер для скорости укладывания.

int timersecond = 2;
int timersecondval = 0;           // переменная для хранения считываемого значения
long timersecondvalmap = 0;

// Скорость укладывания
int speedsecond = 3;
int speedsecondval = 0;           // переменная для хранения считываемого значения
int speedsecondvalmap = 0;

// Таймер для скорости возврата.

int timerback = 4;
int timerbackval = 0;           // переменная для хранения считываемого значения
long timerbackvalmap = 0;

// Скорость возврата.
int speedback = 5;
int speedbackval = 0;           // переменная для хранения считываемого значения
int speedbackvalmap = 0;

// Таймер для паузы.

int timerpause = 6;
int timerpauseval = 0;           // переменная для хранения считываемого значения
long timerpausevalmap = 0;

int pwmOut =  11;      


      

void setup() {

  pinMode(pwmOut, OUTPUT);
  
  pinMode(start, INPUT);
}

void loop() {


//unsigned long pausecurrentMillis = millis();

//таймер стартовой скорости
timerstartval = analogRead(timerstart);     // считываем значение
timerstartvalmap = map(timerstartval, 0, 1023, 0, 2000);
//стартовая скорость  
speedstartval = analogRead(speedstart);     // считываем значение
speedstartvalmap = map(speedstartval, 0, 1023, 0, 255); 

//таймер скорости укладвания
timersecondval = analogRead(timersecond);     // считываем значение
timersecondvalmap = map(timersecondval, 0, 1023, 0, 2000);
//скорость укладывания
speedsecondval = analogRead(speedsecond);     // считываем значение
speedsecondvalmap = map(speedsecondval, 0, 1023, 0, 255); 

//таймер скорости возврата
timerbackval = analogRead(timerback);     // считываем значение
timerbackvalmap = map(timerbackval, 0, 1023, 0, 3000);
//скорость возврата
speedbackval = analogRead(speedback);     // считываем значение
speedbackvalmap = map(speedbackval, 0, 1023, 0, 255); 

//таймер паузы
timerpauseval = analogRead(timerpause);     // считываем значение
timerpausevalmap = map(timerpauseval, 0, 1023, 0, 10000); 

  startbuttonState = digitalRead(start);
  faultbuttonState = digitalRead(fault); 
  

  unsigned long startcurrentMillis = millis();
  
  if (startbuttonState == HIGH && faultbuttonState == LOW) 
  {
      while (millis() - startcurrentMillis < timerstartvalmap)
      
  {
  analogWrite(pwmOut, speedstartvalmap); 
  }
  
  unsigned long secondcurrentMillis = millis();
      while (millis() - secondcurrentMillis < timersecondvalmap)
      
  {
  analogWrite(pwmOut, speedsecondvalmap); 
  }
  unsigned long backcurrentMillis = millis();
      while (millis() - backcurrentMillis < timerbackvalmap)
      
  {
  analogWrite(pwmOut, speedbackvalmap); 
  }
  sensorState = digitalRead(sensor);
  
  
if (sensorState == HIGH)
{
analogWrite(pwmOut,0);
delay(timerpausevalmap);
}
  
  

 }
} 

 

 

sadman41
Offline
Зарегистрирован: 19.10.2016

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

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

Ну, ежели оно всё равно в функции висит, то далеко видно не будет. 

Значит это просто паттернализм. Я думал, что ускорение в пятьсот раз происходит или типа того.

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

sadman41 пишет:

Ну, ежели оно всё равно в функции висит, то далеко видно не будет. 

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

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

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

const везде, где можно.

Почему компилятор не выдаёт никаких предупреждений на строку

const volatile int n = 0;

Ведь маразм же? Такого сочетания не должно быть.

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

Ворота пишет:

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

const везде, где можно.

Почему компилятор не выдаёт никаких предупреждений на строку

const volatile int n = 0;

Ведь маразм же? Такого сочетания не должно быть.

Почему?

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

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Ну, какая может быть волатильность у константы? Кто её может изменить, да ещё и "неожиданно"?

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

Ворота пишет:

Ну, какая может быть волатильность у константы? Кто её может изменить, да ещё и "неожиданно"?

Было бы желание...

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

Ворота пишет:

Ну, какая может быть волатильность у константы? Кто её может изменить, да ещё и "неожиданно"?

1- const это не константа, а нет записи в данном месте, только чтение.

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

ПС: Компилятор считает константы перемемеными, но если в нее никакие силы не пишут ничего, то и выделять на нее память в ОЗУ нет необходимости. Пусть будет в памяти флеша, то есть константы.

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

Вы исходите из в общем-то правильного (во многих случаях), но сильно упрощённого понимания смысла ключевых слов const и volatile

Когда говорят, что (A) volatile означает, что переменная всегда хранится в памяти и к ней обеспечивается атомарный доступ, чаще всего это верно (хотя и не всегда - стандарт не устанавливает места её хранения). Также обычно верно то, что (Б) объект, описанный с применением const является константой. Но так пишут в книгах для начального изучения языка. На самом деле семантика этих слов куда глубже и "хранение в памяти" и "константность" – это следствие этой семантики, а вовсе не определение этих ключевых слов.

Если бы всё ограничивалось только (А) и (Б), то абсолютно не имели бы права на существование. Например, вот такие конструкции:

volatile void a(void) {
	digitalWrite(13, HIGH);
}

const void b(void) {
	digitalWrite(13, HIGH);
}

Ну, какое тут нафиг хранение в памяти и константность, если они void, да ещё и функции? В этом тривиальном случае они, конечно, никакого смысла не имеют, что написал - что нет (но допустимо). Однако, есть ситуации, когда такое сочетание не только допустимо, но и имеет смысл.

Чтобы закончить разговор, отмечу, что в стандарте ISO/IEC 14882:2017, в п. 10.1.7 (стр. 177) прямо указывается, что и volatile, и const совместимы с любыми спецификаторами типа, кроме самих себя.

(2.1) — const can be combined with any type specifier except itself.
(2.2) — volatile can be combined with any type specifier except itself.

А значит, совместимы и между собой (и с void), почему бы нет?

-------------------

Вот простой пример, когда "volatile const" неободимо.

Если написать функцию, типа такой

void dw2(const int & n) {
	digitalWrite(2, n);
}

то ей можно передавать любой int, но ни в коем случае не volatile

void setup() {
	int n;
	dw2(n);	// Нормально
	volatile int vn;
	dw2(vn);	// Ошибка - низзя!
}

Чтобы можно было передавать всё, что угодно, включая и volatile, надо слово volatile добавить в описание параметра

void dw2(volatile const int & n) {
	digitalWrite(2, n);
}

Теперь приведённый setup будет нормально компилироваться.

Это, конечно, "не про эффективность", но это пример, когда сочетание "volatile const" оправдано и без него не работает.

sadman41
Offline
Зарегистрирован: 19.10.2016

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

Когда говорят, что (A) volatile означает, что переменная всегда хранится в памяти и к ней обеспечивается атомарный доступ, чаще всего это верно (хотя и не всегда - стандарт не устанавливает места её хранения).

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

Т.е. volatile не обязательно означает, что компилятор к ней приделает атомарный доступ или мне приснилось?

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

Ну, я же писал, что «атомарный доступ» - упрощенный поход. На самом деле, как любят писать в фейсбучных статусах девочки-малолетки, – «всё сложно».

По конкретике без кода ничего не скажешь. Многобайтовые типы разные бывают. Даже между, скажем int n и uint8_t n2[2] – дистанция огромного размера в поведении const и volatile, а уж если там замешан union (или любая другая разновидность класса), то там вообще чёрт ногу сломит. Например, ни const, ни volatile не имеют никакого эффекта во время выполнения конструктора и деструктора (всей цепочки конструкторов и деструкторов). А если к ним добавить ещё и mutable (например, объект – const volatile, а его метод/свойство – mutable), то без поллитры там делать вообще нечего.

Да и в целом, эти вещи оставлены на откуп реализации («The semantics of an access through a volatile glvalue are implementation-defined» стр. 167). И там же изложены две цели для чего это вводилось: «volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation» и даже «for some implementations, volatile might indicate that special hardware instructions are required to access the object».

Давайте завязывать, разговор явно выходит за рамки ардуино. Если интересно, то см. стандарт С (С++ по семантике volatile отсылает к С). Сейчас, кстати, новый С вышел - ISO/IEC 9899:2018.

sadman41
Offline
Зарегистрирован: 19.10.2016

Никаких юнионов/массивов. Простой счетчик кол-ва прерываний на типе uint32_t.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Посмотрел стандарт С. Нашёл прямо пример про const volatile

EXAMPLE 1 An object declared

extern const volatile int real_time_clock;

might be modifable by hardware, but cannot be assigned to, incremented, or decremented.

В целом, понятно для чего это.

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

sadman41 пишет:

Никаких юнионов/массивов. Простой счетчик кол-ва прерываний на типе uint32_t.

Ну, я говорю, без кода непонятно, а так, см. п. 5.1.2.3 стандарта Си 2018-го года.