Почему используют две переменные 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% скетчей, с которыми приходят на форум - рассинхронизация является последним, что в них следует исправить ))
? if(currentTime-loopTime >= 5){У Вас сколько мошонок? Вы не видите разницы между "обратиться один раз" и "обращаться несколько раз"?
Вот тут, если можно, разжуйте.
В каждом лупе первого скетча мы обращаемся к миллису и гоним его содержимое в переменную. Дальше сравниваем значение этой переменной со значением второй переменной.
В более коротком варианте - вроде, то же самое, только без перемещения значения миллис в первую переменную, а просто сравниваем миллис со второй переменной. Короче же. Не врублюсь никак, в чем подвох?
И еще: это правда, что частое обращение к миллису портит процессор? Я знаю, что эпрон имеет конечное количество циклов "запись-перезапись". А тут та же ситуация?
В более коротком варианте - вроде, то же самое, только без перемещения значения миллис в первую переменную, а просто сравниваем миллис со второй переменной. Короче же. Не врублюсь никак, в чем подвох?
Я это уже писал, но повторю ещё раз и медленно: в Вашем втором скетче 2 (ДВА) обращения к millis. Первое в операторе if строке № ХЗ (вставляйте скетчи как положено), а второе в операторе присваивания в строке № ХЗ.
Вы понимаете, что за время выполнения программы от строки №ХЗ до строки №ХЗ миллисекунда могла перещёлкнуться, и второе обращение к millis вернёт не тоже самое, что вернуло первое? В этом и есть разница между подходами. Большинству скетчей это пофиг, некоторым - нет. Вот и всё.
И еще: это правда, что частое обращение к миллису портит процессор?
Это троллинг для новичков, типа как молодых матросов заставляют якоря точить. На деле - бред сивой кобылы.
Спасибо, разъяснение вполне понятно. Действительно, в зависимости от задачи, перещелк миллиса или имеет значение или пофиг. Теперь разберусь со свими убогими (пока) скетчами.
[/quote]
Это троллинг для новичков, типа как молодых матросов заставляют якоря точить. На деле - бред сивой кобылы.
[/quote]
Я так и знал. И чуть не повелся, хоть уже вся грудь седая, а все как мальчик верю всякому вздору.
А еще копирование значения из переменной происходит заметно бытрее, чем обращение к функции. Поэтому если миллис требуется несколько раз, то эффективнее сохранить ее значение в переменной, а потом с ней работать.
Прошу прощения, сделал что-то не так. Продолжу.
В сектче объявлены две переменные типа long: currentTime и loopTime, которые участвуют в процедуре опроса.
Почему не прим енено нечто с одной переменной? Например:
If (millis()-loopTime=5)
{
//Что-то делаем
loopTime=millis();
}
Зачем две переменные, ведь память же жрем?
Здесь есть два момента:
1. Если мы обращаемся к millis() один раз и запоминаем результат, мы тем самым обеспечиваем выбранный интервал. Хотя бы в среднем. А при многократных вызовах millis() мы можем лишь гарантировать, что интервал будет не менше выбранного. В каких-то случаях лучше одно, в каких-то - другое. Но следует помнить, что это разные варианты.
2. Запоминая время в переменной мы расходуем немного больше оперативной памяти, но экономим на памяти программной, а заодно и экономим вычислительный ресурс. Если производительность для нас важна, либо программная память заканчивается, это может оказаться существенным. Опять же: получается, что это разные варианты, в каких-то случаях целесообразнее выбрать один, а в каких-то другой.
В коллекцию неоднозначностей, полагаю, стоит добавить такой пример:
uint32_t nowTime = millis(); if (nowTime - prevActionOneTime > 1000) { // Делаем что-то с неоднозначной задержкой. Открываем газ или разливаем бензин. // ... // ... uint8_t doRandomDelay = (random(100) > 98); delay (doRandomDelay ? 5000 : 0); prevActionOneTime = nowTime; } if (nowTime - prevActionTwoTime > 500) { // Делаем что-то иное. Например - даём искру. // ... prevActionTwoTime = nowTime; }Как можно заметить - моментом начала выполнения первого и второго условия с точки зрения МК скорее всего будет одна и та же миллисекунда. Для внешнего наблюдателя, в большинстве случаев, это может быть точно так же (если нет постоянной задержки в блоке первого условия) и при отладке он не увидит странного поведения. Но, когда по закону подлости, устройство собрано и установлено на газовый котёл, с вероятностью в... первое условие значительно задерживает исполнение алгоритма. И это видит (либо слышит шипение выходящего газа) внешний наблюдатель. Однако МК продолжает "думать", что условия проверяются так же быстро и последовательно, как и ранее, не фиксируя проблем. Искра, ещё искра...И снится нам не рокот космодрома...
А еще копирование значения из переменной происходит заметно бытрее, чем обращение к функции. Поэтому если миллис требуется несколько раз, то эффективнее сохранить ее значение в переменной, а потом с ней работать.
А вот этот момент важен. Спасибо!
Здесь есть два момента:
1. Если мы обращаемся к millis() один раз и запоминаем результат, мы тем самым обеспечиваем выбранный интервал. Хотя бы в среднем. А при многократных вызовах millis() мы можем лишь гарантировать, что интервал будет не менше выбранного. В каких-то случаях лучше одно, в каких-то - другое. Но следует помнить, что это разные варианты.
2. Запоминая время в переменной мы расходуем немного больше оперативной памяти, но экономим на памяти программной, а заодно и экономим вычислительный ресурс. Если производительность для нас важна, либо программная память заканчивается, это может оказаться существенным. Опять же: получается, что это разные варианты, в каких-то случаях целесообразнее выбрать один, а в каких-то другой.
Спасибо, понял, ибо разъяснение предельно конкретное. Обязательно приму к сведению. Первый пункт - весьма важен, ибо мне будет нужно это учитывать. По второму пункту - все понял, но в конкретно моей задаче производительность не критична. Однако и это "на корочку" записал.
шаблон работы с millis
now - переменная отоматическая, при выходе из функции - растворица в стеках
шаблон работы с millis
now - переменная отоматическая, при выходе из функции - растворица в стеках
Спасибо, логика шаблона понятна. Но для меня (поскольку еще в ардуинопрограммировании дуб дубом) удобнее все-таки заменить "<" на ">" и производить действа внутри If. Исключительно из соображений, чтоб потом не запутаться. И еще вопросик: "uint_32" в данном случае = "long", насколько я понимаю?
using uint32_t = unsigned long;
using uint32_t = unsigned long;
Спасибо, усёк :)
А еще копирование значения из переменной происходит заметно бытрее, чем обращение к функции. Поэтому если миллис требуется несколько раз, то эффективнее сохранить ее значение в переменной, а потом с ней работать.
А вот этот момент важен. Спасибо!
2. Запоминая время в переменной мы расходуем немного больше оперативной памяти, но экономим на памяти программной, а заодно и экономим вычислительный ресурс. Если производительность для нас важна, либо программная память заканчивается, это может оказаться существенным.
По второму пункту - все понял, но в конкретно моей задаче производительность не критична. Однако и это "на корочку" записал.
Вы уж определитесь: "важный момент" или "не критично". )))))))))
Важный момент - с точки зрения методологии. Не критично - мой конкретный случай.