Глюки функции Millis()
- Войдите на сайт для отправки комментариев
Пнд, 21/03/2016 - 14:33
Добрый день!
Коллеги, в казалось бы простом скетче где-то закралась странная ошибка.
Суть скетча в упрощенном варианте:
1. зажали концевик,
2. выполнили некую работу,
3. отпустили концевик,
4. подождали 1,5 секунды,
5. вывели результат.
И вроде все по коду замечательно, но временами функция millis() возвращает некорректные значения.
Скетч:
const int tohnichi=8; const int koncevik=7; const int resetkey=6; const int greenlight=5; const int redlight=4; const int MaxWaitingTime=1500; //in milliseconds const int MaxTorquesNumber=5; // интересующее количество затяжек // начальное состояние системы int koncevikFlag=0; int resetkeyFlag=0; int tohnichiFlag=0; int processStart=0; // работа запрещена int tohnichiCount=0; // затяжек нет unsigned long previousMillis = 0; // will store last time unsigned long previousMillisToh = 0; // will store last time void setup() { Serial.begin(9600); for (int i=6;i<9;i++) { pinMode(i,INPUT_PULLUP); } pinMode(redlight, OUTPUT); pinMode(greenlight, OUTPUT); digitalWrite(greenlight,LOW); // гасим зеленый свет digitalWrite(redlight,LOW); // гасим красный свет } void ProcessStarted() { unsigned long currentMillis = millis(); if(digitalRead(koncevik)==LOW&&koncevikFlag==0)//если пришел сигнал от концевика и переменная koncevikFlag равна 0 и красный сигнал не горит, то ... { // начинаем работу koncevikFlag=1; // указали, что концевик зажат Serial.println("Koncevik zaghat"); processStart=1; // разрешаем работу Serial.println("processStart=1"); tohnichiCount=0; // обнуляем счетчик затяжек digitalWrite(greenlight,LOW); // гасим зеленый и красный свет digitalWrite(redlight,LOW); if (previousMillis==0) { previousMillis=millis(); } } if(digitalRead(koncevik)==HIGH&&koncevikFlag==1)//если нет сигнала от концевика и переменная koncevikFlag равна 1 ,то ... { // отжат концевик if((currentMillis - previousMillis) >= MaxWaitingTime) { Serial.println(String(currentMillis)+"-"+String(previousMillis)); //ошибка наблюдается здесь koncevikFlag=0;//обнуляем переменную koncevikFlag Serial.println(String(tohnichiCount)); tohnichiCount=0; // обнуляем счетчик затяжек processStart=0; // запретили работу previousMillis=0; if (tohnichiCount==MaxTorquesNumber) { // если количество затяжек равно заданному digitalWrite(greenlight,HIGH); // зажигаем зеленый свет Serial.println("GREEN on"); digitalWrite(redlight,LOW); // гасим красный свет Serial.println("RED off"); } else // если количество затяжек не совпало { digitalWrite(greenlight,LOW); // гасим зеленый свет Serial.println("GREEN off"); digitalWrite(redlight,HIGH); // зажигаем красный свет Serial.println("RED on"); } } } }
Вот пример работы сего скетча :(
Koncevik zaghat processStart=1 9149-7538 0 GREEN off RED on resetkey resetkey pressed Koncevik zaghat processStart=1 14483-12069 0 GREEN off RED on resetkey resetkey pressed Koncevik zaghat processStart=1 16824-16825 -- вот функция millis() вернула значение 16824 0 GREEN off RED on Koncevik zaghat processStart=1 22082-16862 0 GREEN off RED on
Автора не смущает тот факт, что previousMillis время от времени обнуляется в скетче (строка 68), затем - получается currentMillis (строка 39), затем - заполняется previousMillis (строка 53)? При таком подходе вполне вероятен сценарий, когда previousMillis будет больше currentMillis. Это так - что заметил навскидку.
Зачем вообще обнулять previousMillis - не пойму. Эти испуги с переходом через ноль и якобы неправильным подсчётом промежутков связаны лишь с тем, что люди не знакомы с беззнаковой арифметикой. Те, кто знает - не парятся :)
Ну почему же неправильно, всё правильно, давай проанализируем код:
1. Строка 39, фиксируем текущий millis в currentMillis, это "0", точка отсчета, дальше время будет увеличиваться. Запомним это.
2. Строка 53, фиксируем текущий millis в previousMillis, при этом миллис уже укатился вперед, тем более там два вывода в Сериал, короче миллис стал чуть больше, чем был в 39 строке.
3. Строка 61, закономерный результат, currentMillis меньше, чем previousMillis.
Разумеется это происходит не каждый раз, потому что нужно чтобы карты сложились и это может происходить, например, когда идет дребезг концевика. Можешь сказать, что этого нет, потому что по монитору этого не видно, так тут везде еще есть вывод в Сериал, а это не мало по времени выполнения.
Для начала, попробуй в 53 строке присваивать не millis, а currentMillis, ситуация немного измениться, во всяком случае такого уже не будет, но будет что-нибуль другое. Но это совсем другая история.
vde69,
Спасибо за процедуру.
DIYMan,
меня не смущает обнуление previousMillis.
Смущение вызвало то, что
1. в
currentMillis записалось значение меньшее чем в previousMillis
2. контроллер пропустил сравнение
if
((currentMillis - previousMillis) >= MaxWaitingTime).
Т.е.
16824)-(currentMillis (
16825)) >=1500 позволило напечатать это в лог.previousMillis(
kisoft,
Да, я исправил
previousMillis=millis(); на previousMillis=currentMillis; и проблема пока не возвращается
не надо учитавать переход ( переполнение ) миллис() ! давно уже обсуждено.....
Коллеги,
всем спасибо. Разобрался. Тему можно закрывать
ты разобрался , молодец....
а тем , кто на такие грабельки наступит , оставь пояснения , код с комментами....
...как знаешь :)
vde69,
Спасибо за процедуру.
DIYMan,
меня не смущает обнуление previousMillis.
Смущение вызвало то, что
1. в
currentMillis записалось значение меньшее чем в previousMillis
2. контроллер пропустил сравнение
if
((currentMillis - previousMillis) >= MaxWaitingTime).
Т.е.
16824)-(currentMillis (
16825)) >=1500 позволило напечатать это в лог.previousMillis(
Про беззнаковую арифметику рассказать?
Для интереса - проверь ;)
ещё бы и результат увидеть.....
DIYMan , для интересса - какое у тибя должно быть значение m3 ?
какое предполагаешь ?
Там будут все единицы, т.е. число много больше, чем 1500.
UPD: единицы - в смысле все биты будут равны 1. Т.е. это максимальное число, которое можно вписать в unsigned long.
DIYMan , для интересса - какое у тибя должно быть значение m3 ?
какое предполагаешь ?
Да всё просто - все биты в единичку, мы же беззнаковыми числами оперируем ;)