Почему используют две переменные long вместо одной?
- Войдите на сайт для отправки комментариев
Пт, 14/06/2019 - 15:16
В статье про энкодеры на нашем сайты прведен следующий код:
01 int brightness = 120; // яркость LED, начинаем с половины 02 03 int fadeAmount = 10; // шаг изменения яркости LED 04 05 unsigned long currentTime; 06 07 unsigned long loopTime; 08 09 const int pin_A = 12; // pin 12 10 11 const int pin_B = 11; // pin 11 12 13 unsigned char encoder_A; 14 15 unsigned char encoder_B; 16 17 unsigned char encoder_A_prev=0; 18 19 void setup() { // declare pin 9 to be an output: 20 21 pinMode(9, OUTPUT); // устанавливаем pin 9 как выход 22 23 pinMode(pin_A, INPUT); 24 25 pinMode(pin_B, INPUT); 26 27 currentTime = millis(); 28 29 loopTime = currentTime; } 30 31 void loop() { 32 33 currentTime = millis(); 34 35 if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц) 36 37 encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера 38 39 encoder_B = digitalRead(pin_B); // считываем состояние выхода А энкодера 40 41 if((!encoder_A) && (encoder_A_prev)){ // если состояние изменилось с положительного к нулю 42 43 if(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке 44 45 // увеличиваем яркость, не более чем до 255 46 47 if(brightness + fadeAmount <= 255) brightness += fadeAmount; } 48 49 else { // выход В в 0 сост., значит вращение против часовой стрелки 50 51 // уменьшаем яркость, но не ниже 0 52 53 if(brightness - fadeAmount >= 0) brightness -= fadeAmount; } 54 55 } 56 57 encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла 58 59 analogWrite(9, brightness); // устанавливаем яркость на 9 ножку 60 61 loopTime = currentTime; } 62 63 }
Прошу прощения, сделал что-то не так. Продолжу.
В сектче объявлены две переменные типа long: currentTime и loopTime, которые участвуют в процедуре опроса.
Почему не прим енено нечто с одной переменной? Например:
If (millis()-loopTime=5)
{
//Что-то делаем
loopTime=millis();
}
Зачем две переменные, ведь память же жрем?
Это вопрос веры. Кто-то верит, что частый вызов millis() протирает дыру в МК и вообще плохо на него влияет. Поэтому перегружают значение в переменную, ожидая, что это будет работать быстрее или меньше тревожить стек. Но наврядли думают о том, как компилятор распорядится с тем и другим способом получения миллисекунд.
Кто-то верит, что частый вызов millis() протирает дыру в МК...
Прости, старик, вот этого не понял. Чтобы слить что-то из миллиса в переменную, надо же к нему все равно обратиться? Та же мошонка, только в профиль. Или я чушь порю? Но самое главное в моем недоумении: нет ли в "моем" способе каких-либо капканов? Скетч-то мой с "моей" конструкцией работает пока (?).
Для того, чтобы в строке №61 переменной looptime присвоить то самое значение, которое использовалось в сравнении в строке 35 (millis то мог и измениться между строками 35 и 61).
Иногда это нужно и важно. Нужно ли это в данном коде - не знаю, внимательно не смотрел. Вы его так вставили, что смотреть невозможно. Номера какие-то левые.
Кстати, в строке №35 опасность глюка при переполнении millis
У Вас сколько мошонок? Вы не видите разницы между "обратиться один раз" и "обращаться несколько раз"? Так вот как раз при "нескольких обращениях" значение может успеть измениться.
Согласен с ЕвгенийП по поводу "синхронизации" через доп. переменную. Но, как показывают мои наблюдения, в 90% скетчей, с которыми приходят на форум - рассинхронизация является последним, что в них следует исправить ))
У Вас сколько мошонок? Вы не видите разницы между "обратиться один раз" и "обращаться несколько раз"?
Вот тут, если можно, разжуйте.
В каждом лупе первого скетча мы обращаемся к миллису и гоним его содержимое в переменную. Дальше сравниваем значение этой переменной со значением второй переменной.
В более коротком варианте - вроде, то же самое, только без перемещения значения миллис в первую переменную, а просто сравниваем миллис со второй переменной. Короче же. Не врублюсь никак, в чем подвох?
И еще: это правда, что частое обращение к миллису портит процессор? Я знаю, что эпрон имеет конечное количество циклов "запись-перезапись". А тут та же ситуация?
В более коротком варианте - вроде, то же самое, только без перемещения значения миллис в первую переменную, а просто сравниваем миллис со второй переменной. Короче же. Не врублюсь никак, в чем подвох?
Я это уже писал, но повторю ещё раз и медленно: в Вашем втором скетче 2 (ДВА) обращения к millis. Первое в операторе if строке № ХЗ (вставляйте скетчи как положено), а второе в операторе присваивания в строке № ХЗ.
Вы понимаете, что за время выполнения программы от строки №ХЗ до строки №ХЗ миллисекунда могла перещёлкнуться, и второе обращение к millis вернёт не тоже самое, что вернуло первое? В этом и есть разница между подходами. Большинству скетчей это пофиг, некоторым - нет. Вот и всё.
И еще: это правда, что частое обращение к миллису портит процессор?
Это троллинг для новичков, типа как молодых матросов заставляют якоря точить. На деле - бред сивой кобылы.
Спасибо, разъяснение вполне понятно. Действительно, в зависимости от задачи, перещелк миллиса или имеет значение или пофиг. Теперь разберусь со свими убогими (пока) скетчами.
[/quote]
Это троллинг для новичков, типа как молодых матросов заставляют якоря точить. На деле - бред сивой кобылы.
[/quote]
Я так и знал. И чуть не повелся, хоть уже вся грудь седая, а все как мальчик верю всякому вздору.
А еще копирование значения из переменной происходит заметно бытрее, чем обращение к функции. Поэтому если миллис требуется несколько раз, то эффективнее сохранить ее значение в переменной, а потом с ней работать.
Прошу прощения, сделал что-то не так. Продолжу.
В сектче объявлены две переменные типа long: currentTime и loopTime, которые участвуют в процедуре опроса.
Почему не прим енено нечто с одной переменной? Например:
If (millis()-loopTime=5)
{
//Что-то делаем
loopTime=millis();
}
Зачем две переменные, ведь память же жрем?
Здесь есть два момента:
1. Если мы обращаемся к millis() один раз и запоминаем результат, мы тем самым обеспечиваем выбранный интервал. Хотя бы в среднем. А при многократных вызовах millis() мы можем лишь гарантировать, что интервал будет не менше выбранного. В каких-то случаях лучше одно, в каких-то - другое. Но следует помнить, что это разные варианты.
2. Запоминая время в переменной мы расходуем немного больше оперативной памяти, но экономим на памяти программной, а заодно и экономим вычислительный ресурс. Если производительность для нас важна, либо программная память заканчивается, это может оказаться существенным. Опять же: получается, что это разные варианты, в каких-то случаях целесообразнее выбрать один, а в каких-то другой.
В коллекцию неоднозначностей, полагаю, стоит добавить такой пример:
Как можно заметить - моментом начала выполнения первого и второго условия с точки зрения МК скорее всего будет одна и та же миллисекунда. Для внешнего наблюдателя, в большинстве случаев, это может быть точно так же (если нет постоянной задержки в блоке первого условия) и при отладке он не увидит странного поведения. Но, когда по закону подлости, устройство собрано и установлено на газовый котёл, с вероятностью в... первое условие значительно задерживает исполнение алгоритма. И это видит (либо слышит шипение выходящего газа) внешний наблюдатель. Однако МК продолжает "думать", что условия проверяются так же быстро и последовательно, как и ранее, не фиксируя проблем. Искра, ещё искра...И снится нам не рокот космодрома...
А еще копирование значения из переменной происходит заметно бытрее, чем обращение к функции. Поэтому если миллис требуется несколько раз, то эффективнее сохранить ее значение в переменной, а потом с ней работать.
А вот этот момент важен. Спасибо!
Здесь есть два момента:
1. Если мы обращаемся к millis() один раз и запоминаем результат, мы тем самым обеспечиваем выбранный интервал. Хотя бы в среднем. А при многократных вызовах millis() мы можем лишь гарантировать, что интервал будет не менше выбранного. В каких-то случаях лучше одно, в каких-то - другое. Но следует помнить, что это разные варианты.
2. Запоминая время в переменной мы расходуем немного больше оперативной памяти, но экономим на памяти программной, а заодно и экономим вычислительный ресурс. Если производительность для нас важна, либо программная память заканчивается, это может оказаться существенным. Опять же: получается, что это разные варианты, в каких-то случаях целесообразнее выбрать один, а в каких-то другой.
Спасибо, понял, ибо разъяснение предельно конкретное. Обязательно приму к сведению. Первый пункт - весьма важен, ибо мне будет нужно это учитывать. По второму пункту - все понял, но в конкретно моей задаче производительность не критична. Однако и это "на корочку" записал.
шаблон работы с millis
now - переменная отоматическая, при выходе из функции - растворица в стеках
шаблон работы с millis
now - переменная отоматическая, при выходе из функции - растворица в стеках
Спасибо, логика шаблона понятна. Но для меня (поскольку еще в ардуинопрограммировании дуб дубом) удобнее все-таки заменить "<" на ">" и производить действа внутри If. Исключительно из соображений, чтоб потом не запутаться. И еще вопросик: "uint_32" в данном случае = "long", насколько я понимаю?
using uint32_t = unsigned long;
using uint32_t = unsigned long;
Спасибо, усёк :)
А еще копирование значения из переменной происходит заметно бытрее, чем обращение к функции. Поэтому если миллис требуется несколько раз, то эффективнее сохранить ее значение в переменной, а потом с ней работать.
А вот этот момент важен. Спасибо!
2. Запоминая время в переменной мы расходуем немного больше оперативной памяти, но экономим на памяти программной, а заодно и экономим вычислительный ресурс. Если производительность для нас важна, либо программная память заканчивается, это может оказаться существенным.
По второму пункту - все понял, но в конкретно моей задаче производительность не критична. Однако и это "на корочку" записал.
Вы уж определитесь: "важный момент" или "не критично". )))))))))
Важный момент - с точки зрения методологии. Не критично - мой конкретный случай.