Циклы в Arduino без delay

VitalikNic
Offline
Зарегистрирован: 14.03.2015

Возможно уже были вопросы по поводу реализации циклов без
Delay, но я не нашел для себя подходящих ответов для реализации
данного функционала (если было то удалите тему).
Требуется за данный промежуток времени изменять значение с 0 до 100,
или наоборот с 100 до 0, но мне допустим нужно изменить параметр конечный
100 на 250 или на 1000, то нужно пересчитывать в цикле задержку.
Вопрос есть решения по данному поводу? 

Чтобы получая данные допусти за 10 секунд значения равномерно изменялись

с 0 до 100, (10 сек = 10000 миллисекунд, то прирост на одно значение

соответствует 100 миллисекунд) но при этом программа выполняла остальной код.
Пробовал библиотеку SimpleTimer, но опять-таки нужно производить
предварительные расчеты..

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

И какие проблемы с предварительными расчетами?

Нет, действительно, совершенно непонятно, в чем Вы видите проблему.

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

VitalikNic пишет:
но опять-таки нужно производить предварительные расчеты..
Я бы даже сказал жестче. Перед тем как начать программировать надо предварительно научиться это делать.

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

VitalikNic, у Вас изначально порочный подход. Вы сразу уперлись в циклы. Зачем? Как раз с циклом Вы здесь ничего разумного не сделаете. Попробуйте решать задачу, а не плясать с бубном вокург конструкции, которая здесь малоприменима.

Подсказка: у Вас уже есть цикл - функция loop вызывается в бесконечном цикле. И никакие другие циклы для Вашей задаче не нужны - они только мешают.

VitalikNic
Offline
Зарегистрирован: 14.03.2015

Я задал вопро возможно уже существует решение по поводу

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

у меня их несколько то становится проблематично, сечас решаю

данную задачу через библиотеку SimpleTimer

timer.setTimer(100, DriverStep, 100); где функкция DriverStep

взывается 100 раз через каждые 100 миллисекунд. В самой

DriverStep я повышаю на одно деление при каждом вызове данной функции

или понижай в зависмости от полученных данных.

 

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

VitalikNic пишет:
сечас решаю
Не вижу Вашего решения. Хрустальные шары здесб запрещены.

VitalikNic
Offline
Зарегистрирован: 14.03.2015
if  (sub.payload_string() == "0")  {      //проверяю условие выполнения если выполняется 
      timer.setTimer(100,DriverStep, 100);   //то выполняем функцию DriverStep с периодом 
}                                            // 100 миллсек 100 раз 


 void DriverStep()         // функция которая вызывается 100 раз                        
{
  static int i = 1;
  static int flagRoute = 0;
  switch (flagRoute) {
    case 0:
      if (i < 99) {
        flagRoute = 1;
      }
      i = 0;
      break;
    case 1:
      if (i > 99) {
        flagRoute = 0;
        break;
      }
      pwm.setPWM(0, 0, i);
      i++;
  }
}


 

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

Это что? Если код, то он неполный и совершенно непонятный.

VitalikNic
Offline
Зарегистрирован: 14.03.2015

Как обяснить, я не знаю что, было понятно

Я думаю надо удальть данную тему...

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

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

VitalikNic
Offline
Зарегистрирован: 14.03.2015

Секрета нет

 https://drive.google.com/open?id=11c2osSAeD3TMKMYiNBT5IQru1ZZsq2QM

полный код он работает у меня но пока не все реализованно

он собран со всего интернета :) 

 

 

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

Ему на ходу скорость мотора менять надо по команде, похоже...

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

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

Гриша
Offline
Зарегистрирован: 27.04.2014

VitalikNic ,пришли просить помоши, не парьте мозги людям - выкладывайте код полностью. Алгоритм, который вы описываете, мне лично почти непонятен. Посмотрите темы  " класс титановый велосипед для delay без delay().   "  Можно еще с таймерами познокомиться если требуется  МКшная суперточность. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

код на коленке, в работе не проверял. не исключаю косяки

int Var = 100;                // изменяемая переменная 
int TargetVal = 1000;         // целевое значение переменной
bool flagCycle = 0;           // флаг запуска "цикла" 
uint32_t prevTimer = 0;       // переменная таймера "цикла"
uint32_t iterationTime =0;    // время задержки между итерациями "цикла", мс

void setup() {

// просто для примера запуск "цикла" из setup
// так запускаем цикл. Целевое значение, время "цикла",мс 
//                            \/              \/            
                 StartCycle (2000,          15000);

}

void loop() 
{
//  тут остальной код
CycleChangeVar();
}

             
void StartCycle (int TargetVal_, uint32_t TimeCycle) 
  {
   prevTimer = millis();                           // сбрасываем таймер "цикла" 
   TargetVal = TargetVal_;                         // целевое значение переменной 
   iterationTime = TimeCycle/abs(TargetVal - Var); // подсчёт задержки между итерациями
   flagCycle = 1;                                  // взводим флаг работы "цикла"
  }


void CycleChangeVar()  
 {
  // если флаг взведён и таймер кончился, делаем очередную итерацию "цикла"
     if (flagCycle && millis()- prevTimer > iterationTime)    
       {
     if (Var == TargetVal) flagCycle = 0;  // заканчиваем "цикл" если достигли цели
else if (Var < TargetVal) Var++;           // достигаем цель
else if (Var > TargetVal) Var--;           // достигаем цель
    
        prevTimer = millis();              // сброс таймера после итерации
        }
 }   

 

VitalikNic
Offline
Зарегистрирован: 14.03.2015

MaksVV-код на коленке, в работе не проверял. не исключаю косяки

слегка дописал и получил то что требовалось

//#include <Adafruit_PWMServoDriver.h>

//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

int Var = 1;                // изменяемая переменная 
int TargetVal = 100;         // целевое значение переменной
int TargeVar = 1;
bool flagCycle = 0;           // флаг запуска "цикла" 
uint32_t prevTimer = 0;       // переменная таймера "цикла"
uint32_t iterationTime =0;    // время задержки между итерациями "цикла", мс
int inter=0;


void setup() {
	
	// просто для примера запуск "цикла" из setup
	// так запускаем цикл. Целевое значение, время "цикла",мс 
	//                            \/              \/            
	//StartCycle (100,          1000);
	
}

void loop() 
{
	//  тут остальной код
	if(digitalRead(5)==HIGH)  {
		StartCycle (100, 1, 1000);
		Cukl();
	}
	
	
}

void StartCycle (int TargetVal_, int TargeVar_, uint32_t TimeCycle) 
{
	prevTimer = millis();                           // сбрасываем таймер "цикла" 
	TargetVal = TargetVal_;                           // целевое значение переменной 
	TargeVar = TargeVar_;
	if (TargetVal > Var) { 
		iterationTime = TimeCycle/abs(TargetVal - Var); // подсчёт задержки между итерациями
		flagCycle = 1;                                  // взводим флаг работы "цикла"
	}
	else {
		iterationTime = TimeCycle/abs(TargetVal - TargeVar); // подсчёт задержки между итерациями
		flagCycle = 1;   
	}
	
}


void CycleChangeVar()  
{
	// если флаг взведён и таймер кончился, делаем очередную итерацию "цикла"
	if (flagCycle && millis()- prevTimer > iterationTime)    
	{
		if (Var == TargetVal) flagCycle = 0;  // заканчиваем "цикл" если достигли цели
			else if (Var < TargetVal) Var++;      // достигаем цель
				else if (Var > TargetVal) Var--;           // достигаем цель
					prevTimer = millis();    // сброс таймера после итерации
		
	}
}   

void CycleChangeVar_()  
{
	// если флаг взведён и таймер кончился, делаем очередную итерацию "цикла"
	if (flagCycle && millis()- prevTimer > iterationTime)    
	{
		if (Var == TargeVar) flagCycle = 0;  // заканчиваем "цикл" если достигли цели
			else if (Var > TargeVar) Var--;      // достигаем цель
				else if (Var < TargeVar) Var++;           // достигаем цель
					prevTimer = millis();    // сброс таймера после итерации
		
	}
}   


void Cukl ()
{
	
	if (TargetVal > Var) {
		
		while (flagCycle==1)  
		{	CycleChangeVar();
			inter = Var;  
		}
	}
	else {  
		while (flagCycle==1)  
		{	CycleChangeVar_();
			inter = Var;  
		}
		
		
	}   
} 

Но ! Время выполнения на устройсте отличается от заданного, не кретично 

но все же ...

MaksVV
Offline
Зарегистрирован: 06.08.2015

и какой смысл использовать whilе?  С таким же успехом можно и delay поставить. While точно также будет тормозить остальной код. 

VitalikNic
Offline
Зарегистрирован: 14.03.2015

MaksVV пишет:

и какой смысл использовать whilе?  С таким же успехом можно и delay поставить. While точно также будет тормозить остальной код. 

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

MaksVV
Offline
Зарегистрирован: 06.08.2015

код #14  не подходит? если время исполнения не точно , можно вместо millis применить micros - будет точнее. На устройстве? итоговый код какой? Подозреваю что вы хотите начинать  "цикл" по нажатию кнопки, но не правильно её опрашиваете. 

Morroc
Offline
Зарегистрирован: 24.10.2016

VitalikNic пишет:

Но ! Время выполнения на устройсте отличается от заданного, не кретично 

но все же ...

Если приблизительно +/- iterationTime то так и должно быть - это погрешность такой реализации. Код в #14 выглядит лучше - он не работает что ли ?

 

VitalikNic
Offline
Зарегистрирован: 14.03.2015

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

Но прекрасно понимаю? что в основном цикле с #14 реализовано также как у меня в цикле while 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

реализовано не также. В вашем цикле while пока все итерации не пройдут остальной код не будет выполняться. Это тоже самое что сделать цикл for. А, собственно, сабж как раз как от этого избавиться или нет?

вот код на micros (),  он точнее немного. (погрешность в 20 мс примерно). 

дак в #14 же показано в setup() как запускается функция? ну поставил ещё пример как из лупа запусить. 

int Var = 100;                // изменяемая переменная 
int TargetVal = 1000;         // целевое значение переменной
bool flagCycle = 0;           // флаг запуска "цикла" 
uint32_t prevTimer = 0;       // переменная таймера "цикла"
uint32_t iterationTime =0;    // время задержки между итерациями "цикла", мс

void setup() {
Serial.begin(115200);
// вот вам пример запуска "цикла" из setup
// так запускаем цикл. Целевое значение, время "цикла",мс 
//                            \/              \/            
                 StartCycle (1,          4000); 

}

void loop() 
{
//  тут остальной код

if (кнопка нажата) StartCycle (50, 2000); // вот вам пример вызова "цикла" из луп (50 - это цель переменной, 2000 - это время изменения, мс)

CycleChangeVar();
}

             
void StartCycle (int TargetVal_, uint32_t TimeCycle) 
  {
   prevTimer = micros();                                // сбрасываем таймер "цикла" 
   Serial.print (F("START Cycle  ")); Serial.println(millis());
   TargetVal = TargetVal_;                              // целевое значение переменной 
   iterationTime = TimeCycle*1000/abs(TargetVal - Var); // подсчёт задержки между итерациями
   flagCycle = 1;                                       // взводим флаг работы "цикла"
  }


void CycleChangeVar()  
 {
  // если флаг взведён и таймер кончился, делаем очередную итерацию "цикла"
     if (flagCycle && micros()- prevTimer > iterationTime)    
       {
     if (Var == TargetVal) {flagCycle = 0; Serial.print (F("END Cycle  ")); Serial.println (millis());}  // заканчиваем "цикл" если достигли цели
else if (Var < TargetVal) Var++;           // достигаем цель
else if (Var > TargetVal) Var--;           // достигаем цель
    
        prevTimer = micros();              // сброс таймера после итерации
        }
 }   

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

Morroc
Offline
Зарегистрирован: 24.10.2016

VitalikNic пишет:

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

Но прекрасно понимаю? что в основном цикле с #14 реализовано также как у меня в цикле while

Фиг знает что вам собственно нужно :) но навскидку вам Cukl() надо вызывать безо всяких событий, постоянно, а проверять flag в нем не нужно (а скорее Cukl вообще не нужно и надо просто вызывать CycleChangeVar_() ,ожидая flag == 0 в основном цикле).

Общая концепция программ "без delay" заключается в прозрачности исполнения кода чтоли... что бы там ни случилось - не надо никаких зацикливаний, кроме самого loop. Случилось что то - отреагировали и тут же пошли дальше, не случилось - тоже пошли дальше (случилось / не случилось - это if или case). Вот и все ваши функции так должны работать - вы её вызвали, она что то сделала или не сделала и сразу завершилась, все равно скоро её снова вызовут.