Therefore, it is recommended to first (before set the EICRA) disable INTn by clearing its Interrupt Enable bit in the EIMSK Register - получается мы до EICRA должны выполнитьEIMSK |= 1; ?
When an INT[6;3:0] bit is written to one and the I-bit in the Status Register (SREG) is set (one) then interrupt is enabled. - получается SREG тоже надо заенаблить... а ну да это как раз sei(),reti()... получается они необходимы но они и так должны быть заенаблены поумолчанию, плюс у меня в коде это тоже было. значит этот пункт выполнен. остается непонятен первый выше
по совету Green сделал последовательную замену ардуино-стайла на регистры. На атмеге328 у меня все работает
const int btPin = 2; //int0!
const int ledPin = 13;
volatile bool flag;
void setup()
{
DDRD &= ~(1<< 2); PORTD |= (1<<2); //pinMode(btPin, INPUT_PULLUP);
DDRB |= (1<<5); //pinMode(ledPin, OUTPUT);
//attachInterrupt(digitalPinToInterrupt(btPin), pinChange, CHANGE);
EIMSK &= ~(1 << INT0); //INT0 is disabled to avoid false interrupts when mainuplating EICRA
EICRA |= (1 << ISC00); //External Interrupt Control Register A - configured to trigger on change
EIFR &= ~(1 << INTF0); //External Interrupt Flag Register -here it is cleared
EIMSK |= (1 << INT0); //Enable INT0
sei(); //Enable global interrupts
}
void loop()
{
if (flag) {
digitalWrite(ledPin, !digitalRead(ledPin)); //инвертируем LED
delay(500);
flag = false;
}
}
ISR(INT0_vect){
flag = true;
}
alexbnd - а теперь сравните со своим кодом в сообщении #26. И обратите внимание, насколько "неряшливый" код у вас и насколько более читабельный здесь. Здесь нет прямого присвоения значений целым регистрам и не используются магические числа, кроме номеров пинов. И я убежден, что именно в этом - причина ваших неудач
Therefore, it is recommended to first (before set the EICRA) disable INTn by clearing its Interrupt Enable bit in the EIMSK Register - получается мы до EICRA должны выполнитьEIMSK |= 1; ?
вы английский плохо понимаете? - написано - "disable INTn by clearing its Interrupt Enable bit". Выключить путем сброса соответвующего бита! А вы вместо этого что делаете? - EIMSK |= 1; ? устанавливаете бит!
тьфу блин просто удалилл reti и все сразу заработало. на простом колхозном, можете обьяснить что делал reti, точнее почему он блокировал повторное срабатывание?
@b707"А вы вместо этого что делаете? - EIMSK |= 1; " а вы тоже это делаете в 15 строчки :)
плюс у вас может получится trigger on RISING потому что вы не очистили регистр предварительно. или я не прав ?
плюс EIFR в мануале написано надо выставить в 1 для сброса а не в ноль как делаете вы, или я не прав ?
[off]и сравнивайте с 39 сообщением ане29, там мой правильный вчерашний код, только reti сегодня удалил ;) спасибо[/off]
тьфу блин просто удалилл reti и все сразу заработало. на простом колхозном, можете обьяснить что делал reti, точнее почему он блокировал повторное срабатывание?
reti() возвращает из прерыравания и разрешает прерыравания. Но не восстанавливает ни SREG ни контекст. Надо смотреть ассемблерный код. Скорее всего при входе в прерывание в стек пихается SREG в результате если его оттуда не вынуть, то по reti программа улетит хз куда. Т.е. похоже, что оно не на прерывания переставало реагировать, а висло.
тьфу блин просто удалилл reti и все сразу заработало.
я вам давно сказал, что reti() лишний. Возврат из прерывания происходит автоматически после завершения обработки ISR, поэтому повторная команда возврата перемещает указатель черти куда
Цитата:
@b707"А вы вместо этого что делаете? - EIMSK |= 1; " а вы тоже это делаете в 15 строчки :)
Disable от Enable не отличаете? Сначала в 12 строке выключаем прерывание, потом настраиваем, потом включаем обратно в строке15
Цитата:
плюс у вас может получится trigger on RISING потому что вы не очистили регистр предварительно. или я не прав ?
вы правы, мог бы, если эта настройка была в середине программы, но в данном случае все работает и так. Хотя соглашусь. что это такой же гавнокод, как у вас на прошлой странице
Цитата:
плюс EIFR в мануале написано надо выставить в 1 для сброса а не в ноль как делаете вы, или я не прав ?
Посомтрел из любопытства что делается в прерывании :
<__vector_1>:
push r1
push r0
in r0, 0x3f
push r0
eor r1, r1
push r24
ldi r24, 0x01
sts 0x0126, r24
reti
pop r24
pop r0
out 0x3f, r0
pop r0
pop r1
reti
Прога выпрыгивает не восстановив рабочие регистры и не высвободив стек.
Финал: даже мой код с самого первого поста прекрасно работал бы не засунь я туда reti()
а почему я засунул reti() ? читаем мануал - reti() Returns from an interrupt routine, enabling global interrupts. This should be the last command executed before leaving an ISR. и вот как понять их же мануал на их же камень бог их знает ? :/
b707 "вы английский плохо понимаете? - написано - "disable INTn by clearing" я конечно не шекспир, но отличить дизабл от енабл в состоянии. почему я на дизабл предположил EIMSK = 1 ? да потому что читаем опять мануал reset EIFR flag by clearing bit. и в даном случае как раз надо записать единицу. вас никогда ни что не вводило в заблуждение ? и вас сразу после этого отправляли учить blink или variables? ядуаю надо быть немного терпимее и вежливее к другдругу ;) но это IMHO
b707 "//INT0 is disabled to avoid false interrupts when mainuplating EICRA" осмелюсь утверждать что нет необходимости в отключение в 12 строке. а вот коентарий ложный. это вас не спасет если событие уже произошло.
asam пишут что всётаки enabling global interrupts но похоже что таки висло, хотя я не понимаю почему, мы же просто повторно активировали глобальные прерывания. если мы два раза запишем один и тот же бит ничего же страшного не происходит PORTB = b10000000; (2 раза).при чем тут перемещает указатель черти куда?
за наводку на reti всем спасибо! кто бы мог подумать :)
Вот если бы ТС вместо мудрёного reti() написал бы обычный рабоче-крестьянский return, компилятор бы отработал нормально и всё бы нормально восстанавливалось.
почему же они в мануале пишут should be the last command executed before leaving an ISR ?
Потому что это так и есть. Но Вы же пишете на С++, а на ассемблере. Компилятор вставит эту команду сам так, как ему нужно и там где ему нужно - не мешайте ему.
alexbmd пишет:
и если оно не нужно на самом деле, в какой гипотетической ситуации оно(reti) может пригодиться ?
Всегда, когда Вы по каким-то причинам не польуетесь компилятором, который делает это за Вас. Например, пишете на ассемблере.
alexbmd, Евгений уже ответил. Не понятно где вы вычитали про этот reti(), единственный случай, когда этот макрос может потребоваться -это при выполнении "голых" прерываний, но это обычным ардуинщикам никогда не пригодится, разве что для самых пытливых и просветлённых :) Я за несколько лет всего один раз его использовал.
EIFR |= 1; // clear flag INT0 for event fired before attachINT0
Например это, -так не стоит делать не убедившись, что там стоит единица. Ибо если её там нет, то вы этой командой её как раз установите. Обычно пишут EIFR=EIFR; Что устранит все единицы, если они там были.
DDRC = 0xFF; //output for Led PC7
Конечно на микре всего два бита в порту "С" но что б не дёргать 6-й бит, лучше поднять только 7-й бит DDRC|=1<<DDC7;
flag=0; flag = true;
Это конечно не ошибка, но лучше писать в каком-то одном стиле, либо текст либо цифры
EIFR |= 1; // clear flag INT0 for event fired before attachINT0
Например это, -так не стоит делать не убедившись, что там стоит единица. Ибо если её там нет, то вы этой командой её как раз установите.
ну там мне и нужна как раз единица (кторая делает clear если я правильно понял мануал) не взирая на то что там было до неё, разве не правильно ?
DDRC, flag, знаю но целью было прерывания остальное меня не волновало и стоит там лишь чтоб убедиться что они работают а так конечно надо делать как вы говорите ;)
sei - я же говорю что даже избыточно :) для подстраховки. без этого тоже будет работать и без коректного выхода ISR
alexbmd, все флаговые регистры в AVR имеют такую особенность - значение ячейки инвертируется при записи в неё единицы. Поэтому если там был ноль - то будет единица, и как только прерывание будет разрешено -оно сразу выполниться, вне зависимости было физическое событие или нет. Поэтому нужно либо проверить что там, либо сделать как я написал выше.
alexbmd, видимо нас не понял. Уж не знаю как ещё проще объяснить. У флаговых регистров AVR два основных принципа: - (1)он принимает только запись единицы, а на запись ноля не реагирует. (2) При записи в флаговый регистр единицы происходит инверсия содержимого. 0 + 1 = 1 и соответссно 1 + 1 =0
dimax, можно проще.) Чтобы сбросить флаг - нужно записать в него 1-цу. Это извращение АVR. Причём не обязательно читать-писать через |=, а именно =, т.к. запись 0 ни на что влияния не оказывает.
а как проверить что в EIFR? как его прочитать ? перерыл весь интернет , только - как записать.
Да обычным образом, читаешь и всё.)
dimax, исключающее ИЛИ здесь не канает!) Установить флаг программно записью 1 НЕЛЬЗЯ! Т.е., если флаг был 0, а мы пытаемся записать туда 1, надеясь на то что после этого он станет в 1 - получаем ФИГ ВАМ! Поэтому я и говорю что у АVR нет программных прерываний.) Только аппаратные!( Хочется программно - можно, но для этого нужно установить требуемый уровень на требуемой ноге, в данном случае на INT0. А установить этот уровень можно и программно.) Но для этого нужно настроить ногу на выход и установить требуемый уровень на этом выходе.
alexbmd, выходит что читать его не нужно, если конечно не собираетесь обрабатывать события без прерывания. Можно сбросить превентивно. EIFR=(1/2/3) или EIFR= EIFR&(1/2/3) Или EIFR=EIFR
У всех работает. А ТС читает каким-то никому неизвестным способом "читаешь и всё", и у него компилятор ругается.
alexbmd пишет:
"читаешь и всё" компилятор не распознаёт :(
alexbmd, Вы, пожалуйста, вместо стенаний типа
alexbmd пишет:
зачем кичиться если можно просто подсказать менее сведущему коллеги? если конечно знаете.
всегда публикуйте код! Ну откуда кому знать каким там "читаешь и всё" Вы его читали? Проблема настолько тривиальна, что никому непонятно, в чём она собственно состоит, и как Вы умудрились не прочитать. Этого действительно никто не понимает! Как, впрочем, никто не понимает, нафига Вам его читать, но это отдельный вопрос.
Публикуйте код и Вам всё подскажут.
И ещё
alexbmd пишет:
вот dimax даже на asm его не может прочитать
dimax что-то в этом контроллере не может прочитать? Давно так не смеялся. Вы бы поаккуратнее, а то все куры со смеху передохнут, из чего омлет делать-то будем? :)))
шутил же я конечно. так что не помрут куры. пробовал напрямую выводить. чёто не выходило. затупил. сори. щя попробую через переменную.
попробовал - тоже самое. точнее я её читал но там всегда нули вот я и подумал что неправильно как то читал. ан нет , как предложили выше тоже там всегда нули. хотел увидеть там единицу. чёто не получается.
вот запихал везде где можно принт а единицу всеравно не вижу
#include <avr/interrupt.h>
volatile boolean flag = 0;
uint8_t data = EIFR;
//mega32u4
void setup()
{
Serial.begin(115200);
while (!Serial);
delay(3000);
DDRD = 0; PORTD = 1; //input PULL-UP and default state is ‘1’ for INT0 PD0
DDRC = 0xFF; //output for Led PC7
PORTC &= ~(1 << 7);
Serial.println(data);
//attachInterrupt()
EIMSK &= ~1; // detachINT0
EICRA &= ~3; // clear existing INT0 flags
EICRA |= 1; // 0:LOW,1:CHANGE,2:FALLING,3:RISING for INT0
Serial.println(data);
EIFR = 1; // clear flag INT0 for event fired before attachINT0
Serial.println(data);
EIMSK |= 1; // attachINT0
Serial.println(data);
}
void loop()
{ Serial.println(data);
if (flag) {
PORTC ^= (1 << 7); //инвертируем состояние пина
flag = 0;
}
delay(2000);
Serial.println(data);
}
ISR(INT0_vect) { //execute ISR when fired
Serial.println(data);
//EIMSK &= ~1; // detachINT0 immediately after fired
flag = 1;
}
b707 вы идиот ?или просо у вас воспитания нет? "образование может быть средним, а воспитание должно быть высшим"
да затупил, с кем не бывает, когда на код остается 5 минут в день, еще и не такое бывает. при этом остальное время тоже не game of trone или line age2 смотрю. но вас еще ни разу не оскорбил. или вы такой умный отродясь? я до этого напрямую выводил всеравно нули. попробую еще.
b707 вы идиот ?или просо у вас воспитания нет? "образование может быть средним, а воспитание должно быть высшим"
Так! Это чо за херня?
Ты пришел с просьбой об объяснениях и помощи. Тем самым ты согласился быть в положении ниже знающих. Следовательно готов терпеть глум и унижения, ради знаний.
Не готов? Пи..дуй нахер в гугль, учиться самостоятельно.
#include <avr/interrupt.h>
volatile boolean flag = 0;
uint8_t * data = &( EIFR);
//mega32u4
void setup()
{
Serial.begin(115200);
while (!Serial);
delay(3000);
DDRD = 0; PORTD = 1; //input PULL-UP and default state is ‘1’ for INT0 PD0
DDRC = 0xFF; //output for Led PC7
PORTC &= ~(1 << 7);
Serial.println(*data);
//attachInterrupt()
EIMSK &= ~1; // detachINT0
EICRA &= ~3; // clear existing INT0 flags
EICRA |= 1; // 0:LOW,1:CHANGE,2:FALLING,3:RISING for INT0
Serial.println(*data);
EIFR = 1; // clear flag INT0 for event fired before attachINT0
Serial.println(*data);
EIMSK |= 1; // attachINT0
Serial.println(*data);
}
void loop()
{ Serial.println(*data);
if (flag) {
PORTC ^= (1 << 7); //инвертируем состояние пина
flag = 0;
}
delay(2000);
Serial.println(*data);
}
ISR(INT0_vect) { //execute ISR when fired
Serial.println(*data);
//EIMSK &= ~1; // detachINT0 immediately after fired
flag = 1;
}
А тут вывод монитора. 1 - когда касаешься проводком из пин3 к GND.
Если внимательно читать ДШ, то там написано, что EIFR чистится при исполнении прерывания. Поэтому посмотреть на него можно только в теле обработчика.
EIFR=EIFR обнуляет флаги если вызывать после точки срабатывания флага. если в плане просто вывести то единственое место где они светятся это внутри тела оброботчика. wdrakula правильно поправил меня с указателем . а то я в спешке начудил там. спасибо.
"Поэтому посмотреть на него можно только в теле обработчика." и таки смотриться да. А я по началу именно туда и не поставил вывод в монитор. почему? А если внимательно почитать даташит то пишут что в теле ни милис, ни сериал ни другие прерывания не работают. страно почему оно выводит таки в монитор...
wdrakula пишет:
Ты пришел с просьбой об объяснениях и помощи. Тем самым ты согласился быть в положении ниже знающих.
я разве сказал что мне ктото чем то обязан ? хотите помочь без оскарблений - помогите. упрекнуть меня в отсутсвии спасиба взамен вы не сможите. я не отрицаю что я в положении ниже знающих по _знаниям_, но не более! И терпеть помощь с унижениями не обязан в свою очередъ я.
А если внимательно почитать даташит то пишут что в теле ни милис, ни сериал ни другие прерывания не работают. страно почему оно выводит таки в монитор...
Ух ты, это в каком даташите пишут что в теле ни милис, ни сериал … не работают?
И вообще, смешались в кучу кони, люди. Милис и сериал это функции, а не прерывания. И они в прерывании работают, но с некоторыми ограничениями. И вообще работа в контексте прерывания накладывает много разных ограничений, поэтому новичкам и не рекомендуют туда лезть, пока опыта не наберутся.
Ты , это , поосторожнее в выражениях. То что они функции не мещает им использовать прерывания. Да,значения они возвращают, но если ты будешь ими пользоваться внутри своего прерывания для блинка то получишь облом, т.к. значения изменяться не будут,пока ты не выдешь из своего прерывания. Именно про это уже писали. Кроме того, если ты будешь жить в своём прерывании больше 8 микросекунд, то миллис и микросеконд будут накапливать ошибку и часики на их основе будут врать.
ua6em на талкнули меня на мысль.. попробую отпишусь
Arhat109 да леонардо. но если можете попробовать на мега тоже хорошо я от неё и отталкивался..
Green а может все дело в EIFR да так и попробую...
меня смущают эти две фразы
Therefore, it is recommended to first (before set the EICRA) disable INTn by clearing its Interrupt Enable bit in the EIMSK Register - получается мы до EICRA должны выполнить EIMSK |= 1; ?
When an INT[6;3:0] bit is written to one and the I-bit in the Status Register (SREG) is set (one) then interrupt is enabled. - получается SREG тоже надо заенаблить... а ну да это как раз sei(),reti()... получается они необходимы но они и так должны быть заенаблены поумолчанию, плюс у меня в коде это тоже было. значит этот пункт выполнен. остается непонятен первый выше
Уже не сегодня...
Леонардо с утра забрал с почты, вечер свободный (с 23), интересно, попробую
да хоть бы кто выложил рабочий код с 328 там дальше всё понятно...
[off]кое какие мысли есть после очередного внимательного прочтения шита[/off]
пока удалось добиться нормального начального состояния и разового тригера. повторно не тригериться :/
я не смогу...
совет, посмотри файл WInterrupts.c где сидит attachInterrupt
по совету Green сделал последовательную замену ардуино-стайла на регистры. На атмеге328 у меня все работает
const int btPin = 2; //int0! const int ledPin = 13; volatile bool flag; void setup() { DDRD &= ~(1<< 2); PORTD |= (1<<2); //pinMode(btPin, INPUT_PULLUP); DDRB |= (1<<5); //pinMode(ledPin, OUTPUT); //attachInterrupt(digitalPinToInterrupt(btPin), pinChange, CHANGE); EIMSK &= ~(1 << INT0); //INT0 is disabled to avoid false interrupts when mainuplating EICRA EICRA |= (1 << ISC00); //External Interrupt Control Register A - configured to trigger on change EIFR &= ~(1 << INTF0); //External Interrupt Flag Register -here it is cleared EIMSK |= (1 << INT0); //Enable INT0 sei(); //Enable global interrupts } void loop() { if (flag) { digitalWrite(ledPin, !digitalRead(ledPin)); //инвертируем LED delay(500); flag = false; } } ISR(INT0_vect){ flag = true; }alexbnd - а теперь сравните со своим кодом в сообщении #26. И обратите внимание, насколько "неряшливый" код у вас и насколько более читабельный здесь. Здесь нет прямого присвоения значений целым регистрам и не используются магические числа, кроме номеров пинов. И я убежден, что именно в этом - причина ваших неудач
меня смущают эти две фразы
Therefore, it is recommended to first (before set the EICRA) disable INTn by clearing its Interrupt Enable bit in the EIMSK Register - получается мы до EICRA должны выполнить EIMSK |= 1; ?
вы английский плохо понимаете? - написано - "disable INTn by clearing its Interrupt Enable bit". Выключить путем сброса соответвующего бита! А вы вместо этого что делаете? - EIMSK |= 1; ? устанавливаете бит!
тьфу блин просто удалилл reti и все сразу заработало. на простом колхозном, можете обьяснить что делал reti, точнее почему он блокировал повторное срабатывание?
@b707"А вы вместо этого что делаете? - EIMSK |= 1; " а вы тоже это делаете в 15 строчки :)
плюс у вас может получится trigger on RISING потому что вы не очистили регистр предварительно. или я не прав ?
плюс EIFR в мануале написано надо выставить в 1 для сброса а не в ноль как делаете вы, или я не прав ?
[off]и сравнивайте с 39 сообщением ане29, там мой правильный вчерашний код, только reti сегодня удалил ;) спасибо[/off]
тьфу блин просто удалилл reti и все сразу заработало. на простом колхозном, можете обьяснить что делал reti, точнее почему он блокировал повторное срабатывание?
reti() возвращает из прерыравания и разрешает прерыравания. Но не восстанавливает ни SREG ни контекст. Надо смотреть ассемблерный код. Скорее всего при входе в прерывание в стек пихается SREG в результате если его оттуда не вынуть, то по reti программа улетит хз куда. Т.е. похоже, что оно не на прерывания переставало реагировать, а висло.
Пихается и не только SREG .. видмо стек таки плыл..
тьфу блин просто удалилл reti и все сразу заработало.
я вам давно сказал, что reti() лишний. Возврат из прерывания происходит автоматически после завершения обработки ISR, поэтому повторная команда возврата перемещает указатель черти куда
Disable от Enable не отличаете? Сначала в 12 строке выключаем прерывание, потом настраиваем, потом включаем обратно в строке15
вы правы, мог бы, если эта настройка была в середине программы, но в данном случае все работает и так. Хотя соглашусь. что это такой же гавнокод, как у вас на прошлой странице
да, возможно.
Посомтрел из любопытства что делается в прерывании :
Прога выпрыгивает не восстановив рабочие регистры и не высвободив стек.
Посомтрел из любопытства что делается в прерывании :
Прога выпрыгивает не восстановив рабочие регистры и не высвободив стек.
dimax - это в случае лишнего reti() в конце, правильно я понимаю?
думаю в 10 строке выпрыгивает ))) этого ассемблера не знаю, сильно не пинать
b707, лишний reti в середине )) Это собссно был вот этот фрагмент:
ISR(INT0_vect){ //execute ISR when trigger flag = true; reti(); }Финал: даже мой код с самого первого поста прекрасно работал бы не засунь я туда reti()
а почему я засунул reti() ? читаем мануал - reti() Returns from an interrupt routine, enabling global interrupts. This should be the last command executed before leaving an ISR. и вот как понять их же мануал на их же камень бог их знает ? :/
b707 "вы английский плохо понимаете? - написано - "disable INTn by clearing" я конечно не шекспир, но отличить дизабл от енабл в состоянии. почему я на дизабл предположил EIMSK = 1 ? да потому что читаем опять мануал reset EIFR flag by clearing bit. и в даном случае как раз надо записать единицу. вас никогда ни что не вводило в заблуждение ? и вас сразу после этого отправляли учить blink или variables? ядуаю надо быть немного терпимее и вежливее к другдругу ;) но это IMHO
b707 "
//INT0 is disabled to avoid false interrupts when mainuplating EICRA" осмелюсь утверждать что нет необходимости в отключение в 12 строке. а вот коентарий ложный. это вас не спасет если событие уже произошло.b707 "что это такой же гавнокод" сейчас вы обидели весь коллектив arduino LLC :) по сути это просто репликация их примера https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ через регистры.
asam пишут что всётаки enabling global interrupts но похоже что таки висло, хотя я не понимаю почему, мы же просто повторно активировали глобальные прерывания. если мы два раза запишем один и тот же бит ничего же страшного не происходит PORTB = b10000000; (2 раза).при чем тут перемещает указатель черти куда?
качая одной рукой ребенка а второй накалякал максимально правильный (даже для подстраховки избыточный) код + важна очередность регистров + коректный вход и выход = http://arduino.ru/forum/programmirovanie/vnutrennie-preryvaniya#comment-444802
есть коментарии/улучшения :) ?
PS: кстати это самая полная и детальная версия из всех виденных мной в нете. Даже у Гамонна такой нету :)
От многих знаний, много печали.
Вот если бы ТС вместо мудрёного reti() написал бы обычный рабоче-крестьянский return, компилятор бы отработал нормально и всё бы нормально восстанавливалось.
reti() - точно не нужен, но конкретно в этом контексте мешать не должен.
Это он тебе не должен. А так-то мешает. Наверное, компилятор кривой. Или язык.
Прога выпрыгивает не восстановив рабочие регистры и не высвободив стек.
dimax а почему же они в мануале пишут should be the last command executed before leaving an ISR ?
и если оно не нужно на самом деле, в какой гипотетической ситуации оно(reti) может пригодиться ? при этом чтоб всё коректно востановилось
ну, я же говорил "от многих знаний, много печали"
почему же они в мануале пишут should be the last command executed before leaving an ISR ?
Потому что это так и есть. Но Вы же пишете на С++, а на ассемблере. Компилятор вставит эту команду сам так, как ему нужно и там где ему нужно - не мешайте ему.
и если оно не нужно на самом деле, в какой гипотетической ситуации оно(reti) может пригодиться ?
Всегда, когда Вы по каким-то причинам не польуетесь компилятором, который делает это за Вас. Например, пишете на ассемблере.
alexbmd, Евгений уже ответил. Не понятно где вы вычитали про этот reti(), единственный случай, когда этот макрос может потребоваться -это при выполнении "голых" прерываний, но это обычным ардуинщикам никогда не пригодится, разве что для самых пытливых и просветлённых :) Я за несколько лет всего один раз его использовал.
dimax Евнений наконец я понял а то за бугром детальной информацией особбо не разживешся спасибо!
dimax да много где упоминается даже в avr\interrupt.h :)
качая одной рукой ребенка а второй накалякал максимально правильный (даже для подстраховки избыточный) код + важна очередность регистров + коректный вход и выход = http://arduino.ru/forum/programmirovanie/vnutrennie-preryvaniya#comment-444802есть коментарии/улучшения :) ?
Да по мелочам докапаться можно :)
Например это, -так не стоит делать не убедившись, что там стоит единица. Ибо если её там нет, то вы этой командой её как раз установите. Обычно пишут EIFR=EIFR; Что устранит все единицы, если они там были.
Конечно на микре всего два бита в порту "С" но что б не дёргать 6-й бит, лучше поднять только 7-й бит DDRC|=1<<DDC7;
Это конечно не ошибка, но лучше писать в каком-то одном стиле, либо текст либо цифры
Функция setup() сама добавляет эту команду.
EIFR |= 1; // clear flag INT0 for event fired before attachINT0
Например это, -так не стоит делать не убедившись, что там стоит единица. Ибо если её там нет, то вы этой командой её как раз установите.
ну там мне и нужна как раз единица (кторая делает clear если я правильно понял мануал) не взирая на то что там было до неё, разве не правильно ?
DDRC, flag, знаю но целью было прерывания остальное меня не волновало и стоит там лишь чтоб убедиться что они работают а так конечно надо делать как вы говорите ;)
sei - я же говорю что даже избыточно :) для подстраховки. без этого тоже будет работать и без коректного выхода ISR
/ спасибо verifyed by dimax :)
alexbmd, все флаговые регистры в AVR имеют такую особенность - значение ячейки инвертируется при записи в неё единицы. Поэтому если там был ноль - то будет единица, и как только прерывание будет разрешено -оно сразу выполниться, вне зависимости было физическое событие или нет. Поэтому нужно либо проверить что там, либо сделать как я написал выше.
значение ячейки инвертируется при записи в неё единицы. Поэтому если там был ноль - то будет единица
чтото я запутался :)
правильно я так и хочу, если было 0 стало 1. если было 1 стало 1.
1 = сбросить флаг прерывания. чтобы как только прерывание было разрешено оно НЕ сработало. т.к. нету флага. в случае данного регистра нету = 1.
или я вас не понял ?
alexbmd, видимо нас не понял. Уж не знаю как ещё проще объяснить. У флаговых регистров AVR два основных принципа: - (1)он принимает только запись единицы, а на запись ноля не реагирует. (2) При записи в флаговый регистр единицы происходит инверсия содержимого. 0 + 1 = 1 и соответссно 1 + 1 =0
dimax, можно проще.) Чтобы сбросить флаг - нужно записать в него 1-цу. Это извращение АVR. Причём не обязательно читать-писать через |=, а именно =, т.к. запись 0 ни на что влияния не оказывает.
Поэтому нужно либо проверить что там
а как проверить что в EIFR? как его прочитать ? перерыл весь интернет , только - как записать.
а как проверить что в EIFR? как его прочитать ? перерыл весь интернет , только - как записать.
Да обычным образом, читаешь и всё.)
dimax, исключающее ИЛИ здесь не канает!) Установить флаг программно записью 1 НЕЛЬЗЯ! Т.е., если флаг был 0, а мы пытаемся записать туда 1, надеясь на то что после этого он станет в 1 - получаем ФИГ ВАМ! Поэтому я и говорю что у АVR нет программных прерываний.) Только аппаратные!( Хочется программно - можно, но для этого нужно установить требуемый уровень на требуемой ноге, в данном случае на INT0. А установить этот уровень можно и программно.) Но для этого нужно настроить ногу на выход и установить требуемый уровень на этом выходе.
Green, да про установку флага видимо фигню сморозил, в голове каша после stm32 :)
ооо arm впереди...
Коллеги так как же прочитать EIFR? "читаешь и всё" компилятор не распознаёт :(
alexbmd, выходит что читать его не нужно, если конечно не собираетесь обрабатывать события без прерывания. Можно сбросить превентивно. EIFR=(1/2/3) или EIFR= EIFR&(1/2/3) Или EIFR=EIFR
ооо arm впереди...
Коллеги так как же прочитать EIFR? "читаешь и всё" компилятор не распознаёт :(
Какой там ещё arm, если вы EIFR прочитать не можете!)
вот dimax даже на asm его не может прочитать, или Green владеет скрижалью всевидящего ока ;)
зачем кичиться если можно просто подсказать менее сведущему коллеги? если конечно знаете.
ооо arm впереди...
Коллеги так как же прочитать EIFR? "читаешь и всё" компилятор не распознаёт :(
А что, разве вот так не работает?
или Green владеет скрижалью всевидящего ока ;)
Green владеет Ржавой Секирой Ужоса...
Ну и программированием, маленько.
А что, разве вот так не работает?
У всех работает. А ТС читает каким-то никому неизвестным способом "читаешь и всё", и у него компилятор ругается.
"читаешь и всё" компилятор не распознаёт :(
alexbmd, Вы, пожалуйста, вместо стенаний типа
зачем кичиться если можно просто подсказать менее сведущему коллеги? если конечно знаете.
всегда публикуйте код! Ну откуда кому знать каким там "читаешь и всё" Вы его читали? Проблема настолько тривиальна, что никому непонятно, в чём она собственно состоит, и как Вы умудрились не прочитать. Этого действительно никто не понимает! Как, впрочем, никто не понимает, нафига Вам его читать, но это отдельный вопрос.
Публикуйте код и Вам всё подскажут.
И ещё
вот dimax даже на asm его не может прочитать
dimax что-то в этом контроллере не может прочитать? Давно так не смеялся. Вы бы поаккуратнее, а то все куры со смеху передохнут, из чего омлет делать-то будем? :)))
шутил же я конечно. так что не помрут куры. пробовал напрямую выводить. чёто не выходило. затупил. сори. щя попробую через переменную.
попробовал - тоже самое. точнее я её читал но там всегда нули вот я и подумал что неправильно как то читал. ан нет , как предложили выше тоже там всегда нули. хотел увидеть там единицу. чёто не получается.
вот запихал везде где можно принт а единицу всеравно не вижу
#include <avr/interrupt.h> volatile boolean flag = 0; uint8_t data = EIFR; //mega32u4 void setup() { Serial.begin(115200); while (!Serial); delay(3000); DDRD = 0; PORTD = 1; //input PULL-UP and default state is ‘1’ for INT0 PD0 DDRC = 0xFF; //output for Led PC7 PORTC &= ~(1 << 7); Serial.println(data); //attachInterrupt() EIMSK &= ~1; // detachINT0 EICRA &= ~3; // clear existing INT0 flags EICRA |= 1; // 0:LOW,1:CHANGE,2:FALLING,3:RISING for INT0 Serial.println(data); EIFR = 1; // clear flag INT0 for event fired before attachINT0 Serial.println(data); EIMSK |= 1; // attachINT0 Serial.println(data); } void loop() { Serial.println(data); if (flag) { PORTC ^= (1 << 7); //инвертируем состояние пина flag = 0; } delay(2000); Serial.println(data); } ISR(INT0_vect) { //execute ISR when fired Serial.println(data); //EIMSK &= ~1; // detachINT0 immediately after fired flag = 1; }вот запихал везде где можно принт а единицу всеравно не вижу
#include <avr/interrupt.h> volatile boolean flag = 0; uint8_t data = EIFR; //mega32u4 void setup() { Serial.begin(115200); while (!Serial); delay(3000); DDRD = 0; PORTD = 1; //input PULL-UP and default state is ‘1’ for INT0 PD0 DDRC = 0xFF; //output for Led PC7 PORTC &= ~(1 << 7); Serial.println(data); //attachInterrupt() EIMSK &= ~1; // detachINT0 EICRA &= ~3; // clear existing INT0 flags EICRA |= 1; // 0:LOW,1:CHANGE,2:FALLING,3:RISING for INT0 Serial.println(data); EIFR = 1; // clear flag INT0 for event fired before attachINT0 Serial.println(data); EIMSK |= 1; // attachINT0 Serial.println(data); } void loop() { Serial.println(data); if (flag) { PORTC ^= (1 << 7); //инвертируем состояние пина flag = 0; } delay(2000); Serial.println(data); } ISR(INT0_vect) { //execute ISR when fired Serial.println(data); //EIMSK &= ~1; // detachINT0 immediately after fired flag = 1; }Алекс, простите, вы идиот? Или это троллинг такой?
Вы СНАЧАЛА приравняли переменную data регистру, ПОТОМ в него записали единицу - и думаете в data сама собой тоже появится единица?????
какие там прерывания. когда вы просто программировать не умеете...
b707 вы идиот ?или просо у вас воспитания нет? "образование может быть средним, а воспитание должно быть высшим"
да затупил, с кем не бывает, когда на код остается 5 минут в день, еще и не такое бывает. при этом остальное время тоже не game of trone или line age2 смотрю. но вас еще ни разу не оскорбил. или вы такой умный отродясь? я до этого напрямую выводил всеравно нули. попробую еще.
до этого напрямую выводил всеравно нули. попробую еще.
попробуйте, если опять нули будут -приходите, будем разбираться.
Но так, как вы "попробовали" выше - ГАРАНТИРОВАНО работать не может, независмо от того, что читаете - "крутой" регистр или самую обычную переменную
b707 вы идиот ?или просо у вас воспитания нет? "образование может быть средним, а воспитание должно быть высшим"
Так! Это чо за херня?
Ты пришел с просьбой об объяснениях и помощи. Тем самым ты согласился быть в положении ниже знающих. Следовательно готов терпеть глум и унижения, ради знаний.
Не готов? Пи..дуй нахер в гугль, учиться самостоятельно.
#include <avr/interrupt.h> volatile boolean flag = 0; uint8_t * data = &( EIFR); //mega32u4 void setup() { Serial.begin(115200); while (!Serial); delay(3000); DDRD = 0; PORTD = 1; //input PULL-UP and default state is ‘1’ for INT0 PD0 DDRC = 0xFF; //output for Led PC7 PORTC &= ~(1 << 7); Serial.println(*data); //attachInterrupt() EIMSK &= ~1; // detachINT0 EICRA &= ~3; // clear existing INT0 flags EICRA |= 1; // 0:LOW,1:CHANGE,2:FALLING,3:RISING for INT0 Serial.println(*data); EIFR = 1; // clear flag INT0 for event fired before attachINT0 Serial.println(*data); EIMSK |= 1; // attachINT0 Serial.println(*data); } void loop() { Serial.println(*data); if (flag) { PORTC ^= (1 << 7); //инвертируем состояние пина flag = 0; } delay(2000); Serial.println(*data); } ISR(INT0_vect) { //execute ISR when fired Serial.println(*data); //EIMSK &= ~1; // detachINT0 immediately after fired flag = 1; }А тут вывод монитора. 1 - когда касаешься проводком из пин3 к GND.
Если внимательно читать ДШ, то там написано, что EIFR чистится при исполнении прерывания. Поэтому посмотреть на него можно только в теле обработчика.
Если внимательно читать ДШ ...
"Ну, ты, барин, задачи ставишь!"
а если сначала EIFR=EIFR а потом
data = EIFR; и далее вывести в сериал?EIFR=EIFR обнуляет флаги если вызывать после точки срабатывания флага. если в плане просто вывести то единственое место где они светятся это внутри тела оброботчика. wdrakula правильно поправил меня с указателем . а то я в спешке начудил там. спасибо.
"Поэтому посмотреть на него можно только в теле обработчика." и таки смотриться да. А я по началу именно туда и не поставил вывод в монитор. почему? А если внимательно почитать даташит то пишут что в теле ни милис, ни сериал ни другие прерывания не работают. страно почему оно выводит таки в монитор...
Ты пришел с просьбой об объяснениях и помощи. Тем самым ты согласился быть в положении ниже знающих.
я разве сказал что мне ктото чем то обязан ? хотите помочь без оскарблений - помогите. упрекнуть меня в отсутсвии спасиба взамен вы не сможите. я не отрицаю что я в положении ниже знающих по _знаниям_, но не более! И терпеть помощь с унижениями не обязан в свою очередъ я.
Раз просишь - это уже унижение. Так что нефиг изображать из себя оскорблённого. А нет - ну значит не спрашивай, ищи сам в Гугле. ИМХО.
А если внимательно почитать даташит то пишут что в теле ни милис, ни сериал ни другие прерывания не работают. страно почему оно выводит таки в монитор...
Ух ты, это в каком даташите пишут что в теле ни милис, ни сериал … не работают?
И вообще, смешались в кучу кони, люди. Милис и сериал это функции, а не прерывания. И они в прерывании работают, но с некоторыми ограничениями. И вообще работа в контексте прерывания накладывает много разных ограничений, поэтому новичкам и не рекомендуют туда лезть, пока опыта не наберутся.
Ты , это , поосторожнее в выражениях. То что они функции не мещает им использовать прерывания. Да,значения они возвращают, но если ты будешь ими пользоваться внутри своего прерывания для блинка то получишь облом, т.к. значения изменяться не будут,пока ты не выдешь из своего прерывания. Именно про это уже писали. Кроме того, если ты будешь жить в своём прерывании больше 8 микросекунд, то миллис и микросеконд будут накапливать ошибку и часики на их основе будут врать.