Временные задержки. Да, опять)

unisonic
Offline
Зарегистрирован: 09.01.2018

Представим, что есть следующая задача: выполнять некое действие в течение трёх секунд с перерывом в 7 секунд.

Придумал я, значит, вот такую конструкцию:

(cm-current millis, pm-previous millis, prValue - previous value и тд)

void prCalibration() //калибровка фоторезистора
{
  prValue = analogRead(0);
  if ((calibrationInterval < (cm - pmCalibration)) && ((cm - pmCalibration) < (calibrationInterval + calibrationTime)))
  {    
    if (prValue < prPrevValue - calibrationRounding || prPrevValue + calibrationRounding < prValue) //отбрасываем значения с фоторезистора в пределах точности, чтобы устранить дребезг
    {
      Serial.print(prValue); Serial.print(" записано в массив под номером "); Serial.println(prCounter);
      calibrationArray[prCounter] = prValue;
      prPrevValue = prValue;
      prCounter++;
    }  
  }
  if ((cm - pmCalibration) == (calibrationInterval + calibrationTime))
  {
    Serial.println("Начинаю считать среднее...");
    pmCalibration = cm;
    prMinValue = 1023;
    prMaxValue = 0;
    for (int i = 0; i <= (prCounter - 1); i++)
    {
      if (calibrationArray[i] < prMinValue)
      {
        prMinValue = calibrationArray[i];
      }
      if (calibrationArray[i] > prMaxValue)
      {
        prMaxValue = calibrationArray[i];
      }
    }
    Serial.print("Минимальное значение подачи "); Serial.println(prMinValue);
    Serial.print("Максимальное значение подачи "); Serial.println(prMaxValue);
    prAdjustedValue = (prMinValue + prMaxValue) / 2;
    Serial.print("Среднее значение подачи "); Serial.println(prAdjustedValue);
    prCounter = 0;
  }
}

То есть тело условия работает тогда, когда текущее millis находится в пределах от 7 до 10 секунд (calibrationInterval (7) + calibrationTime (3)).

А когда millis равно 10 секундам - происходит подсчёт, присвоение pmCalibration = cm и всё остальное очень нужное.

Всё работает, вот только через раз... Как я понял, иногда МК просто не обрабатывает эту строку тогда, когда millis равно 10000 мс. В итоге программа просто останавливается.

Внимание, вопрос. Можно ли как-то приложить в этой конструкции подорожник, или всё же нужно использовать RTC?

Вопрос два, как раз по поводу RTC. Вот хочу я в 14:42:55 выполнить какое-то действие. 

Если я просто напишу

if (dt.hour == 14 && dt.minute == 42 && dt.second == 55)

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

if (dt.hour == 14 && dt.minute == 42 && dt.second == 55 && flag == 0)
{
....
flag = 1
}

а потом еще придумать как бы его сбросить на 0.

Есть способ получше?

Вопрос номер три: в первом блоке кода видно такой массив calibrationArray[]. Количество элементов в нём неизвестно и каждый цикл замеров разное.

Так вот если я объявляю его int calibrationArray[6], то в массив запишется всего 10 значений в ячейки от 0 до 9. Если объявить calibrationArray[]={0}, то запишется всего 6 значений в ячейки от 0 до 5. В итоге объявляю его как calibrationArray[999] и всё работает, но резервировать столько памяти на массив - совсем не по фен-шую. Что я делаю не так?

 

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

RTC тут не надо. Если стоит задача делать что-то 3 секунды с промежутком в 7 секунд, то один из вариантов - ниже:

unsigned long past = 0;
enum
{
	WORK_3_SECONDS,
	IDLE_7_SECONDS
};

byte machineState = WORK_3_SECONDS;

void loop()
{
		unsigned long now = millis();
		
		switch(machineState)
		{
			case WORK_3_SECONDS:
			{
				if(now - past > 3000)
				{
					past = now;
					machineState = IDLE_7_SECONDS;
				}
			}
			break;
			
			case IDLE_7_SECONDS:
			{
				if(now - past > 7000)
				{
					past = now;
					machineState = WORK_3_SECONDS;
				}
			}
			break;
		}
}

 

unisonic
Offline
Зарегистрирован: 09.01.2018

Полежал, подумал, и понял, что достаточно будет просто в строке if ((cm - pmCalibration) == (calibrationInterval + calibrationTime)) поменять == на >. И тогда по первому вопросу всё ясно. Осталось еще два.
DIYman, Ваша конструкция по смыслу такая же, разве что применён switch-case и у меня все интервалы заменены переменными.

unisonic
Offline
Зарегистрирован: 09.01.2018

Полежал, подумал, и понял, что достаточно будет просто в строке if ((cm - pmCalibration) == (calibrationInterval + calibrationTime)) поменять == на >. И тогда по первому вопросу всё ясно. Осталось еще два.
DIYman, Ваша конструкция по смыслу такая же, разве что применён switch-case и у меня все интервалы заменены переменными.

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

unisonic пишет:

Вопрос два, как раз по поводу RTC. Вот хочу я в 14:42:55 выполнить какое-то действие. 

В нормальном RTC есть Alarm, который может дёрнуть МК за пин внешнего прерывания. В обработчике взводите флаг, в лупе по обнаружению взведенного флага кормите рыб и флаг сбрасываете. По необходимости переставляете Alarm на новое время.

Logik
Offline
Зарегистрирован: 05.08.2014

unisonic пишет:
Осталось еще два.

Со вторым просто - флаг сбрасывать когда не выполняется if (dt.hour == 14 && dt.minute == 42 && dt.second == 55) , собственно просто по else. 

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

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

unisonic
Offline
Зарегистрирован: 09.01.2018

Logik пишет:

unisonic пишет:
Осталось еще два.

Со вторым просто - флаг сбрасывать когда не выполняется if (dt.hour == 14 && dt.minute == 42 && dt.second == 55) , собственно просто по else. 


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

"Нет массива-нет проблем" - это я почти сразу понял и выпилил его из кода. Но знать-то надо) И я удивлён, что нет возможности расширять массив. Я заподозрил неладное, когда он отказался объявить массив без размера и без элементов.

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

unisonic пишет:

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

Привыкай, ты не в сказку попал, а в чёрное царство чесного С.  Нету тут динамических массивов, пока сам не напишешь. 

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

unisonic пишет:
И я удивлён, что нет возможности расширять массив. Я заподозрил неладное, когда он отказался объявить массив без размера и без элементов.

Странно это...

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

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

unisonic
Offline
Зарегистрирован: 09.01.2018

Занял массив 4 байта. Место кончилось. В другом месте выделяется еще 4 байта и на него даётся указатель, мол там-то хранится продолжение. По аналогии с фрагментацией файлов на носителях. Так представляю) Но, очевидно, есть какие-то проблемы с таким способом, раз он не реализован.

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

4 байта с указателем в 2 байта? Это сколько ж вам нужно памяти в МК...

Никто вам не мешает намахать свой TList. Писателю на Си - это как два пальца... поэтому никто не заморачивается насчет библиотек.

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

.del нуего нахрен

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

unisonic пишет:
Logik пишет:

unisonic пишет:
Осталось еще два.

Со вторым просто - флаг сбрасывать когда не выполняется if (dt.hour == 14 && dt.minute == 42 && dt.second == 55) , собственно просто по else. 

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

по else - это значит if (dt.hour != 14 || dt.minute != 42 || dt.second != 55)

не хочешь по елсе - сделай явно if (dt.second != 55) flag = 0;

unisonic
Offline
Зарегистрирован: 09.01.2018

Я всё понял.

Logik
Offline
Зарегистрирован: 05.08.2014

Получится все. Смотрите, при проходах когда условие не выполняется  (dt.hour == 14 && dt.minute == 42 && dt.second == 55) уходим на ветку else с присвоением flag=0. Как только условие выполнится первый раз то окажемся на проверке флага, он нулевой, делаем дело по времени и ставим флаг в 1. На else  мы не попадаем. при следующем заходе снова условие  (dt.hour == 14 && dt.minute == 42 && dt.second == 55)  сработает, но проверка флага уже нет, флаг станет 0 только когда пройдет секунда. 

Знать надо. Низкоуровневое программирование близко к материальному миру. Мы же не можем купить бутылку 0,5 прийти домой и расширить её до 3 литров ))) Так и здесь - выделили память, значить столько же её и будет. В высокоуровневых языках расширяемость массивов обясняется тем, что внутренние механизмы интерпретатора делают то, что я писал. Но хороше скрывают это от нас. А расплата - снижением скорости работы.

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

unisonic пишет:
Я всё понял.

ок.

if (dt.hour == 14 && dt.minute == 42 && dt.second == 55 && flag == 0) flag = 1;
else                                                                  flag = 0;

 

unisonic
Offline
Зарегистрирован: 09.01.2018

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

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

unisonic пишет:

Занял массив 4 байта. Место кончилось. В другом месте выделяется еще 4 байта и на него даётся указатель, мол там-то хранится продолжение. По аналогии с фрагментацией файлов на носителях. Так представляю) Но, очевидно, есть какие-то проблемы с таким способом, раз он не реализован.

Это называется список. Давно известная (и многократно реализованная) структура, нативно поддерживаемая С++. Если Вам не подходят массив и вектор, можете использовать список. Но по части расходуемых ресурсов он опережает их оба.

В общем, повторюсь: используйте то, что считаете наиболее удобным, вариантов - масса.

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

Массив у тебя на скока элементов? Меньше 256?

unisonic
Offline
Зарегистрирован: 09.01.2018

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

unisonic
Offline
Зарегистрирован: 09.01.2018

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

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

Фоторезистор-то чего делает? Может есть способ проще...