Внутренние прерывания

asam
Offline
Зарегистрирован: 12.12.2018

nik182 пишет:
Ты , это , поосторожнее в выражениях. То что они функции не мещает им использовать прерывания.

Миллис не использует прерывания напраямую. Она просто возвращает счетчик. Кстати можно и для блинка в прерывании использовать, если очень надо. Достаточно разрешить глобальные прерывания. Но тут надо хорошо понимать возможные последствия. Serial.print() прерывания используют, но первый байт начинает передаваться сразу, а остальные когда прерывания разрешаются.

Цитата:
Кроме того, если ты будешь жить в своём прерывании больше 8 микросекунд, то миллис и микросеконд будут накапливать ошибку и часики на их основе будут врать.

Прерывания для апдейта счетчика миллис случаются раз в 1024 микросекунды. То есть можно "жить в cвоем прерывании" около 2 миллисекунд без нарушения работы "часиков".  

 

 

 

nik182
Offline
Зарегистрирован: 04.05.2015

Понимаешь ли, прерывания авр устроены так, что из прерывания нельзя вызвать другое прерывание, как бы глобально оно не было разрешено. Только флаги прерываний поднимаются и по выходу из прерывания выполняется сразу прерывание с поднятым флагом и максимальным приоритетом. Миллис прерываний не использует. Он только использует щетчик которым рулит микросеконд. Так что всё же 8 микросекунд в прерывании это критическое время внесения ошибки в функции тайминга. 

nik182
Offline
Зарегистрирован: 04.05.2015

Всё, сдаюсь. Если разрешить глобальные прерывания внутри прерывания, то таки да, другое прерывание вызовется. Вот только уверенности как то нет, что при этом всё потом вернётся правильно на круги своя. Не гробнется стек или не вызовется снова первое прерывание. Очень надо быть внимательным делая такое. Иначе можно получить источник очень трудно прогнозируемых ошибок. 

asam
Offline
Зарегистрирован: 12.12.2018

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

В принципе, при правильном дизайне ничего страшного не случится если в процессе выполнения прерывания оно же вызовется опять. Главное, что бы они дальше не вкладывались. Иначе стек быстро переполняется и привет.

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

как хорошо, всёже, что по-умолчанию, при входе в обрабоччик, прерывания запрещаются, и, если понимаешь что делаешь, их надо разрешать мануально. 

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

DetSimen пишет:

как хорошо, всёже, что по-умолчанию, при входе в обрабоччик, прерывания запрещаются, и, если понимаешь что делаешь, их надо разрешать мануально. 

для реентерабельности я вывешивал флаг и увеличивал счётчик им и определял глубину стека

Green
Онлайн
Зарегистрирован: 01.10.2015

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

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

Наверное потому что это не соответствует концептуальной модели системы с прерываниями?

alexbmd
Offline
Зарегистрирован: 15.01.2016

--- вслучае дефолтного поведения ---

nik182, т.е. если передовать просто текст через сериал то это без проблем а если переменную то она не будет менять свое значения внутри обработчика, правильно я понял ?

кстати по поводу 8 микросекунд - после накопления ошибки , МК имеет какието встроенные функции для коректировки времени/ошибки ?  или этот сдвиг по фазе будет продолжаться вплоть до сброса МК ?

 

Green
Онлайн
Зарегистрирован: 01.10.2015

sadman41 пишет:

Наверное потому что это не соответствует концептуальной модели системы с прерываниями?


Ну да, согласен. Модели - моделями, но не обязательно ограничивать себя рамками.

asam
Offline
Зарегистрирован: 12.12.2018

alexbmd пишет:

--- вслучае дефолтного поведения ---

nik182, т.е. если передовать просто текст через сериал то это без проблем а если переменную то она не будет менять свое значения внутри обработчика, правильно я понял ?


Нет, не правильно.
Цитата:
>кстати по поводу 8 микросекунд - после накопления ошибки , МК имеет какието встроенные функции для коректировки времени/ошибки ?  или этот сдвиг по фазе будет продолжаться вплоть до сброса МК ?

 


Нет не имеет. Сдвиг будет продолжаться. Но 8 микросекунд тут ни причем если мы говорим о миллис.

alexbmd
Offline
Зарегистрирован: 15.01.2016

asam , ну то что милис не будет обновляться это точно :) . ок. а почему тогда нельзя использовать serial внутри isr ?

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

кстати пока я експерементировал с флагами то заметил что


volatile uint8_t * data = &( EIFR);

const byte ledPin = 13;
const byte interruptPin = 3;
volatile byte state = LOW;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  delay(3000);
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
  digitalWrite(ledPin, state);
}

void blink() {
  Serial.println(*data);
  state = !state;
}

attach оказывается не сбрасывает флаг и обработчик как минимум один раз срабатывает даже если мы его не вызывали. это баг arduino ide или фича, если фича как по логике ардуины тогда мы должны решить эту проблему ?

asam
Offline
Зарегистрирован: 12.12.2018

alexbmd пишет:
asam , ну то что милис не будет обновляться это точно :) . ок. а почему тогда нельзя использовать serial внутри isr ?

Использовать можно, нормально работать не будет. Аппаратный USART имеет буфер в один байт. Когда ты используешь serial.print первый байт начинает передаваться сразу, когда он передался вызывается прерывание по которому из программного буфера в аппаратный передается следующий байт. Внутри прерывания все прерырывания, по-умолчанию, запрещены. И больше одног байта, в итоге, не передастся. Пока прерывания опять не разрешат. А разрешение происходит или автоматически по возврату из обработчика или можно внутри обработчика разрешить вручную. Поэтому если хочется делать отладочный serial,print внутри прерывания, то лучше делать его из одного символа и именно serial.print а не serial.println

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

alexbmd, 12 строка - внутренний Pull_Up не гарантирует, что вход прерывания не попытается принимать "радиосигнал с марса" ) Повторите эксперимент с жёстко соединённым входом к земле или питанию.

asam
Offline
Зарегистрирован: 12.12.2018

alexbmd пишет:

attach оказывается не сбрасывает флаг и обработчик как минимум один раз срабатывает даже если мы его не вызывали. это баг arduino ide или фича,

Это фича. Но срабатывает только тогда, если условия для прерывания были выполнены когда-либо до того. 

Цитата:
если фича как по логике ардуины тогда мы должны решить эту проблему ?

Сбрасывать флаг "вручную" до attachInterrupt

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbmd пишет:

а почему тогда нельзя использовать serial внутри isr ?

Можно. С чего нелья-то?

Если знать и понимать что делает, то многое можно.

alexbmd
Offline
Зарегистрирован: 15.01.2016

asam пишет:

Сбрасывать флаг "вручную" до attachInterrupt

я так и делал , но думал идеология ардуины на этот счёт более изысканная :)

кстати генерит его имено атач и сброс до не работает. сброс флагового регистра после - помогал. во всяком случае у меня так/ надо будет попробовать железный пул-ап. хотя у программного точно не сигнал марса а логика такая имхо. оно всегда ровно один раз срабатывает. скорее "внутрений" шум. ну это так мысли по древу.

 

Евгений вас вечно бросает в крайности ;). если знать что и для чего то ардуина вообще не нужна. можно вообще на асм который нам преподовали в далекие 90ые. я всегда расматриваю ситуацию стандартную. усредненно-обобщеную.

nik182
Offline
Зарегистрирован: 04.05.2015

Залез в вайринг. Таймер 0 настроен на 4 микросекунды. Миллис получается внутри этого прерывания путем подсчета 256 прерываний и вычитания лишнего. Т.е. своего прерывания у миллис нет. И соответственно ошибка от пропуска прерывания таймера 0 будет накапливаться как микросеконд так и миллис.

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

nik182 пишет:

Таймер 0 настроен на 4 микросекунды. 

4 мкс тик или переполнение? 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbmd пишет:

Евгений вас вечно бросает в крайности ;). если знать что и для чего то ардуина вообще не нужна. можно вообще на асм который нам преподовали в далекие 90ые. я всегда расматриваю ситуацию стандартную. усредненно-обобщеную.

Это Вас бросает верить всем подряд, а также верить в какие-то мифические сверхспособности какого-то розового невидимого единорога асма.

Я утверждаю, что именно в стандартной ситуации это делать можно. А проблемы и глюки, которые возникают у некоторых "специалистов" связаны с общим неумением работать с прерываниями, а вовсе не с особенностями сериала.

Вот Вам пример. Исправно печатает текст раз в секунду. И что в нём нестандартного?

static bool setupIsCompleted = false;

void intHandler(void) {
	if (setupIsCompleted) Serial.println("Urbi et orbi!");
}

void setup(void) {
	Serial.begin(57600);
	pinMode(2, OUTPUT);
	attachInterrupt(0, intHandler, RISING);
	setupIsCompleted = true;
}

void loop(void) {
	digitalWrite(2, !digitalRead(2));
	delay(500);
}
nik182
Offline
Зарегистрирован: 04.05.2015

4 мкс тик. Собственно это точность получения микросекундных интервалов.

asam
Offline
Зарегистрирован: 12.12.2018

nik182 пишет:

Залез в вайринг. Таймер 0 настроен на 4 микросекунды. Миллис получается внутри этого прерывания путем подсчета 256 прерываний и вычитания лишнего. Т.е. своего прерывания у миллис нет. И соответственно ошибка от пропуска прерывания таймера 0 будет накапливаться как микросеконд так и миллис.

вы путаете теплое с мягким. Тик 4 микросекунды. А вот прерывание случается по переполнению. То есть раз в 256 тикоы. Что составляет 1024 микросекунды. Когда прерывания запрещены таймер все равно тикает и точность микрос никуда не девается если прерывания были запрещены на меньшее время. Дальше: счетчик миллис обновляется по этому прерыванию которое случется прмерно раз в миллисекунду. Если переполнение таймера случится когда прерывания запрещены, то миллис не проапдейтится, но флаг взведется. И как только прерывания разрешаться , то миллис таки проапдейтится и точность в миллисикундах  мы не потеряем. Нотвот если прерывания будут запрещены больше чем на 2 миллисекунды, то случиться еще переполнение, которое будет потеряно.

nik182
Offline
Зарегистрирован: 04.05.2015

Да. Пересмотрел. Действительно TIMER0_OVF_vect. 

asam
Offline
Зарегистрирован: 12.12.2018

nik182 пишет:

Да. Пересмотрел. Действительно TIMER0_OVF_vect. 

 

Вообще-то про это я уже здесь писал. Но мои сообщения потерли.

asam
Offline
Зарегистрирован: 12.12.2018

asam пишет:

nik182 пишет:

Да. Пересмотрел. Действительно TIMER0_OVF_vect. 

 

Вообще-то про это я уже здесь писал. Но мои сообщения потерли. Nik182 это ты потер?

nik182
Offline
Зарегистрирован: 04.05.2015

У меня нет админских прав что то тереть.

bwn
Offline
Зарегистрирован: 25.08.2014

asam пишет:

Вообще-то про это я уже здесь писал. Но мои сообщения потерли. Nik182 это ты потер?

Нет, не он. Глюк странный был. Было два Ваших сообщения, я одно убил, насмерть, а исчезло оба. К сожалению, не восстановить.((((

alexbmd
Offline
Зарегистрирован: 15.01.2016

ЕвгенийП пишет:

Это Вас бросает верить всем подряд, 

каюсь, грешен. чёрт дернул поверить Нику и не только ему одному.  Ник пишет:

-Don't attempt to delay, eg: delay (100);
-You can get the time from a call to millis, however it won't increment, so don't attempt to delay by waiting for it to increase.
-Don't do serial prints (eg. Serial.println ("ISR entered"); )
-Don't try to do serial reading.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbmd пишет:
Ник пишет:

Правильно пишет. Если бы Вы меня спросили можно ли это делать, я бы Вам тоже ответил "нельзя". Но Вы же не спрашивали, Вы утверждали :)

Ник, как и все остальные, задолбался, наверное, объяснять каждому чайнику почему именно в данном конкретном случае у него что-то не работает. А возможностей накосячить там вагон и тележка. И глюков наловишь столько, что никакой глюкометр на поможет.

Гораздо проще на вопрос "можно ли?" ответить "нет!" просто потому, что это требует определённой квалификации и понимания, которых у спрашивающего, очевидно, нет (иначе бы не спрашивал). Уверяю Вас, сам Ник, если ему вдруг понадобится вывести что-то в Serial из обработчика прерывания, не испытает никаких затруднений.

Вы мой пример запустили? Работает? А хотите, я там одну строчку добавлю  (тоже вполне стандартную), и глючить начнёт?

Вот, как-то так.

alexbmd
Offline
Зарегистрирован: 15.01.2016

кстати код у вас красивый. интересно наблюдать за умными дядьками :)

конечно хочу чтоб вы добавили одну строчку . никогда не устану самооброзовываться.

кстати, для ясности картины, правильно я понимаю что в строчке 4 у нас передается только "U" а в строчки 15 уже остальная часть текста ?

это в связи с пояснением asam что в обработчике только первый байт выводиться

Green
Онлайн
Зарегистрирован: 01.10.2015

Только комплименты могут растопить суровое сердце программера-мужчины!)

asam
Offline
Зарегистрирован: 12.12.2018

alexbmd пишет:

кстати, для ясности картины, правильно я понимаю что в строчке 4 у нас передается только "U" а в строчки 15 уже остальная часть текста ?

Остальная часть текста выдается когда попало, но после выхода из прерывания.

Как работает Serial.print():

Если размер сообщения меньше выделенного для Seral буфера (для Uno, Nano. Mini, Micro это 64 байт ), то сообщение заталкивается в буффер, запускается передача, управление возращается на следующий оператор после Serial.print(). Дальше передача идет асинхронно. Как только байт передался, вызывается прерывание и из буффера передачи вытаскивается следующий байт и запихивается в передатчик. Прерывание заканчивается.

Если прерывание запрещены, то слудующий байт, соответсвенно, никуда не передается. Если при этом вызвать Serial.print() еще раз, то он попытается запихнуть новое сообщение в тот же 64 байтный буффер. И если места там нет, то будет ждать пока место не освободится.

Почему говорят, что "нельзя использовать Serial.print() в прерывании"? Потому что если попытаться передать больше 64  байт, то прерывание "зависнет" с первого раза. Если передавать меньше, но прерывания вызываются чаще чем освобождается буффер, то прерывание опять зависнет, но не на первом разе, а когда буффер переполнится.

Если же передавать за раз меньше размера буффера, и между вызовами прерывания времени достаточно, что бы буффер освободился, то работать будет. Но надо учитывать, что на заполнение буффера будут влиять и другие Serial.print() вызываемые вне прерывания. Поэтому если в код Евгения добавить, куда нибудь что-то вроде 

Serial.print("very f....ng long string to overflow serial buffer and destry whole system");

то все зависнет.

alexbmd
Offline
Зарегистрирован: 15.01.2016

dimax пишет:

"радиосигнал с марса" 

больше похоже просто баг IDE

вот код из Winterrupt.h

EICRA = (EICRA & ~((1<<ISC00) | (1<<ISC01))) | (mode << ISC00);
EIMSK |= (1<<INT0); 

флага нет :)

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

alexbmd, непойму,  вы попробывали как я сказал жёстко посадить вход на + или Gnd ??

asam
Offline
Зарегистрирован: 12.12.2018

.

alexbmd
Offline
Зарегистрирован: 15.01.2016

dimax, еще до железа не дошел, обезательно попробую, сори. пока только попробовал hard-coded сбрасывать флаг сразу после строчки attachInterrupt и ложного срабатывания не происходит. 

asam, все предельно понятно, спасибо.

Господа, интернет не даёт однозначного ответа, если 

-мы уходим в глубокую спячку, просыпаемся по врерыванию, нужно опять делать

Serial.begin(57600);
While(!Serial);

?

Green
Онлайн
Зарегистрирован: 01.10.2015

dimax, а по моему до жопы. Нужно просто сбросить флаг до аттача и всё, не? 

asam
Offline
Зарегистрирован: 12.12.2018

alexbmd пишет:

Господа, интернет не даёт однозначного ответа, если 

-мы уходим в глубокую спячку, просыпаемся по врерыванию, нужно опять делать

Serial.begin(57600);
While(!Serial);

?

Не смотрел как там для Ардуино с USB CDC (Leonardo, micro), а вот для "обычных" - Uno/Nano etc
Serial.begin() делать не надо. Там просто настраиваются параметры порта которые при уходе в спячку не сбрасываются.

While(!Serial); для таких плат не  нужен вообще никогда. Это только для тех, что с USB SDC

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Green, флаг то сбросить можно(кстати он вскакивает после аттача, судя по тому, что писал alexbmd) Тут вопрос в том, что бы понять почему появляется этот флажок, ведь по логике вещей его не должно быть.  Моя версия, что нога прерывания ловит наводку несмотря на внутренний Pull-Up. Кстати были мнения, что внутренний pull-up в отличии от внешнего "усиливает" ловлю помех :)

Green
Онлайн
Зарегистрирован: 01.10.2015

Судя... Никому нельзя верить.) Пока сам не проверишь.)
Я не понимаю этих чудес, этих мнений. Внутренний pullup - это порядка 40 ком резистор, и что? Чем это плохо? Ну да, для каких то элетромагнитных пускателей это ерунда, но у нас то этого нет! Поэтому и не стоит забивать себе голову этой ерундой.)

Я могу конечно проверить все эти ситуации с аттачамим, но стоит ли? Помойму и так всё ясно.) И логично.

alexbmd
Offline
Зарегистрирован: 15.01.2016

asam, для USB точно нужно делать деатач/атачUSB (деатач кстати надо вручную править макрос) если нужен usb монитор но вот begin не понятно. оно как бы работает и так но это не значит что правильно. ладно забью :)

a pullup проверю как железо будет. +флаг всегда можно сбросить :)

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

alexbmd пишет:

a pullup проверю как железо будет.

То есть всё это было  не на реальном МК? А как вы узнали что флаг возникает, протеус показал?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dimax пишет:

(кстати он вскакивает после аттача, судя по тому, что писал alexbmd)

Сдаётся мне, что alexbmd на самом деле пробовал не на живом железе, а на кривом симуляторе и теперь выносит нам мозг кривизной симулятора, забыв упомянуть о такой мелочи.

Вот Вам код,

#include <Printing.h>

static inline void printEIFR(const uint8_t num) { printf("%u. EIFR=%u\r\n", num, (uint8_t)EIFR); }

static void dummyHandler(void) {}

void setup(void) {
	Serial.begin(57600);
	printEIFR(1);	// Печатаем ДО attachInterrupt
	attachInterrupt(0, dummyHandler, RISING);
	printEIFR(2);	// Печатаем ПОСЛЕ attachInterrupt
}

void loop(void){}

попробуйте его на живой железяке. Получите:

1. EIFR=0
2. EIFR=0

А теперь, тоже самое запускаем в протеусе. Результат:

1. EIFR=3
2. EIFR=2

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

dimax пишет:

alexbmd пишет:

a pullup проверю как железо будет.

То есть всё это было  не на реальном МК? А как вы узнали что флаг возникает, протеус показал?

МЛЯ! Пока я писал свой тест, всё именно так и оказалось???

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbmd,

торжественно вручаю!

 

 

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

Это же неважно. Тыжардуинщик - должен сразу понять и решить проблему.

Скажите спасибо, что он не вавгад запускал в портеусе своем.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так я и решил. А после этого медалькой ТС наградил.

Тем более и решить-то было несложно, по этим граблям мы уже топтались :) некоторого времени потребовало написать пример и перепроверить всё перед постом :)

alexbmd
Offline
Зарегистрирован: 15.01.2016

dimax пишет:

То есть всё это было  не на реальном МК? 

на реальном.  но чтобы пулап железо сделать надо добраться до него. сори что запутал вас.

я пишу с трех разных компов и двух телефонов. везде разные куски. проверки. грубо говоря на коленке. когда минутка высвобождается.

ЗЫ: ах вот о какой медали речь.... спасибо за скороспешные выводы.

ЗЫЫ протеуса и морфиуса в глаза не видывал. но кому какое дело

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

Друг, не надо писать на коленке. Так ты не только свое время зря тратишь, а еще и десятка других человек. Заслужили они такое отношение или нет? Подумай над этим.