Сбой программного таймера.
- Войдите на сайт для отправки комментариев
Пт, 23/03/2018 - 14:47
Добрый день Форум!
В силу своих скромных возможностей в программировании, не могу понять проблему
сбоя программного таймера. Суть проблемы в том, что по непонятным мне причинам
периодически происходит выполнение условия if, которое в данный момент не должно выполнятся.
Из-за этого период программного таймера становится короче. Это наглядно видно в мониторе порта.
IDE 1.8.5, Arduino Nano, бутлодырь - Оптибут. Как проблему победить, парни?
uint32_t Tim_old;
volatile uint16_t isrCnt =0; //счетчик тиков от таймера2
void setup() {
// перенастройка таймера2 с периодом прерывания около 4 мс
cli();//stop interrupts
TCCR2A = 0;
TCCR2B = 0;
TIMSK2 = 0;
TCCR2B |= ((1<<CS21)|(1<<CS22)); // предделитель на 256
TIMSK2 |= (1<<TOIE2); // разрешаю прерывание по переполнению T2
sei();//allow interrupts
Serial.begin(115200); // инициализируем порт
pinMode(LED_BUILTIN, OUTPUT); // initialize digital pin LED_BUILTIN as an output.
Tim_old = millis();
}
//*******************************************************
void loop() {
if (isrCnt >= 300) {
Serial.print(isrCnt);
isrCnt = 0;
Serial.print(" ");
Serial.println(millis()-Tim_old);
Tim_old = millis();
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //мигание LED
}
}
//********************************************************
// обработчик прерывания по переполнению T2 4,096 мс
ISR(TIMER2_OVF_vect) {
isrCnt++;
}Монитор порта: первая ц. значения счетчика прерываний, вторая период в мс.
300 1228 300 1229 300 1229 300 1229 300 1229 256 1048 сбой 300 1229 300 1229 300 1229 300 1228 300 1229 300 1229 300 1229 300 1229 300 1228 300 1229 300 1229 300 1229 300 1229 256 1048 сбой 300 1229 300 1229 300 1229 300 1228 300 1229 256 1049 сбой 300 1229 300 1228 300 1229 300 1229 300 1229 256 1048 сбой 300 1229 300 1229
Прерывания тонкая вещь.
Например, представьте себе такую ситуацию: после строки 22 Вас прервали (сериал, например, решил чего-то там поделать, он же неблокирующий). Пока он там занимался чем-то посторонним, переменная уже isrCnt "убежала". В итоге, когда Вы ёё собрались печатать в строке 23, она уже совсем не та, что была в строке 22.
Точно придумывать сценарий при котором получилось именно так, как у Вас мне просто неохота, но дело именно в этом - в том, что Вас прервали между проверкой и присвонием нуля. Как-то так. Вас пррвали и Вам от этого поплохело.
Чтобы убедиться в том, что это так и есть (независимо от конкретного сценария) попробуйте заменить свой loop на вот такой. Уверен, что ни одного сбоя Вы не увидите.
void loop() { cli(); if (isrCnt >= 300) { const uint16_t cnt = isrCnt; isrCnt = 0; sei(); Serial.print(cnt); Serial.print(" "); Serial.println(millis() - Tim_old); Tim_old = millis(); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //мигание LED } else sei(); }Jaeger, для корректного вычисления в лупе if (что-то меняющееся в прерывании) перед этим вычислением нужно прерывания запретить.
Ну не могу я понять это желание постоянно запретить прерывания. То есть понятно, что это проще всего, и "работает же" но есть же и правильные способы без запрета.
В классной книге "Art of multirocessing programming" есть немало решений подобных задач.
Если Вы про Хёрлихи и Шэвита, то книга-то конечно неплохая, но не для данной задачи. Задача вырожденная и потому здесь будет как в старом анекдоте:
Само же по себе её изучение ... ну, не знаю, профессионалу (или профильному студенту) необходимо, а хоббисту - по-моему излишество, тем более, для своего понимания она требует определённого уровня IT-культуры, которым 99% любителей просто не владеют. Т.е. для того, чтобы эту книгу понять, им потребуется изучить много чего предварительно.
GarryC, ну так привели бы хоть один пример, если их немало. В той же функции millis() первая команда -cli
dimax, если хотите посмотреть книгу, "их есть у меня". Только в применении к данной задаче, см. мой комментарий выше.
dimax, если хотите посмотреть книгу, "их есть у меня".
Английский вариант в свободном доступе лежит, первая же ссылка в Гугле по названию.
Только GarryC название привёл немного неправильно. Но, впрочем, да, найти нетрудно.
Кстати, есть вполне приличные книги на эту тему и на русском (в смысле отечественных авторов). Причём многие из них более строгие и точные (более глубокие), чем обсуждаемая.
Евгений, а что из русскоязычных посоветуете ?
Особенно, если они более глубокие - для меня и эта оказалась кладезем мудрости, было бы неплохо пополнить.
https://parallel.ru/info/books_rus.html