Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры Atmega AVR
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.91/64: Рейтинг темы: голосов - 64, средняя оценка - 4.91
drvtos
0 / 0 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
1

Аппаратный сброс флага прерывания

22.08.2010, 01:38. Просмотров 11674. Ответов 17
Метки нет (Все метки)

Интересную штуку накопал. Не совсем очевидную.

Работаю (мега48) с прерываниями по совпадению: COMP0A, COMP1A. Как написано в даташите, соответствующие флаги OCF0A и OCF1A сбрасываются аппаратно при входе в прерывание (если оно разрешено) или же нужно их сбрасывать записью туда "1". Ну, пока я работал без прерываний, то сбрасывал этим интересным способом, да и делов-то...

А когда завел прерывания. то сброс этот убрал, ИСТЕСНА. И нагрелся на день мучительного траханья! Дело в том, что в одном из прерываний (таймер0, хотя это и не принципиально), я с каждым вторым входом загружаю в OCR0A минимальное значение, единицу, для генерации самого короткого импульса. И что выходит: входя в совсем короткое прерывание, МК успевает щелкнуть таймером и перейти из нуля в 1, что и является в данный момент СОВПАДЕНИЕМ с OCR0A. Тут же, в прерывании, взводится флаг OCF0A. И никто его аппаратно уже не сбрасывает - мы же сидим в отработке прерывания.
Как только выходим из прерывания, тут же летим туда снова! Причем у меня разница между парным и непарным входом состоит в состоянии одного из битов регистра TCCR0A. И никто не успевает этот бит перекинуть. Поэтому влетаю в ISR, флаг OCF0A сбрасывается и снова успевает "встать" :)
Так и летаю в этом прерывании.

Поэтому получил урок: сбрасывается флаг аппаратно - очень хорошо. Но, если есть хоть малейшая вероятность того, что он может взвестись в середине ISR - не поленись сбросить его еще и программно.

Тестовый кусочек прилагаю:
Код
ISR (TIMER0_COMPA_vect)
{
TCCR0B &= ~RUN_T0;    // Stop (вынес сюда тоже для подстраховки)
if( CHBIT( TCCR0A, COM0A0))       // If COM0A0 is 1, it is the 2-nd interrupt
{
TCCR0A=(1<<COM0A1)|(0<<COM0A0)|(1<<WGM01);
TCNT0 = 0;
}
else                              // If COM0A0 is 0, it is the 1-st interrupt
{
TCCR0A=(1<<COM0A1)|(1<<COM0A0)|(1<<WGM01);
TCNT0 = 0;
OCR0A = 1;
TCCR0B |= RUN_T0;                           // Start Timer0
}
SEBIT( TIFR0, OCF0A);   // ВОТ ГЛАВНАЯ ШТУКА, предмет разговора!
}

ISR (PCINT0_vect)
{
FLBIT( PORTB, 6);
}

int main( void)
{
...
TCCR0A=(1<<COM0A1)|(0<<COM0A0)|(1<<WGM01)|(0<<WGM00);
TCCR0B=(0<<WGM02)|(0<<CS02)|(0<<CS01)|(0<<CS00);       // CTC mode
OCR0A=OCR0B=0xFF;

TIMSK0 = (1<<OCIE0A);
PCICR = (1<<PCIE0);   // PCIE0 - any change on PCINT7..0 pins
PCMSK0=(1<<PCINT0);
PCIFR = (1<<PCIF0);   // Clear PCIF0 (flag)

sei();
while(1)
{
if(CHBIT( PINB, 0))
while(  CHBIT( PINB, 0)) ;
else while( !CHBIT( PINB, 0)) ;
OCR0A = 10;            // Timer0 test putsi duration
TCCR0B |= RUN_T0;
}
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.08.2010, 01:38
Ответы с готовыми решениями:

Вызов прерывания в обработке прерывания
В программе,нажатие кнопки вызывает прерывание,в котором оно...

Аппаратный I2C.
Пытаюсь собрать цифровой термометр. Вывод данных на жк экран уже освоил, а вот...

Аппаратный глюк
Ситуация такая. Надо было мне сделать платку, на ней три кнопки. По трем...

Аппаратный I2C master
Имеется МК otmyko328, работающий на частоте 18.432 Мгц. Необходимо общаться с...

Аппаратный SPI в 9 бит
Подключил Lcd от Nokia1616 к AtMega16a. Работает замечательно, но медленно!...

17
ishkymkot
0 / 0 / 0
Регистрация: 12.08.2010
Сообщений: 64
22.08.2010, 01:40 2
Спасибо. Довольно часто флаг может возникнутm вновь в прерывании.

Самое кондовое его сбросить в конце обработчика.
0
swk
0 / 0 / 0
Регистрация: 22.10.2015
22.08.2010, 12:24 3
Я всегда сбрасываю флаг перед самым выходом из обработчика. А прерывания по очень коротким событиям, типа приведенного с таймером, вообще стараюсь не использовать. Наверняка проще было ипользовать программную задержку для такого короткого интервала. Основное назначение прерываний - реакция на события, которые происходят достаточно редко и непредсказуемо, но требуют немедленной реакции. Остальное всегда можно сделать программным опросом или задержками. Обычно у меня главный цикл крутится достаточно быстро, просматривая флажки и выполняя параллельно кучу действий, кроме того, обычно делаю прерывание по таймеру с интервалом в 1мс - в нем организую кучу программных таймеров и опрос некоторых устройств (например, флага приемника USORT).
0
drvtos
0 / 0 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
22.08.2010, 13:49 4
Цитата Сообщение от SWK
Наверняка проще было ипользовать программную задержку для такого короткого интервала
Согласен.
Но тут вот какой случай: я же АВР начал использовать недавно и в этом девайсе впервые применил свойство таймера по совпадению кода не только генерить флаг (ну, и прерывание, если дозволено), но еще и аппаратно дергать вывод (PD.6 в данном случае). Мне понравилось. Вывод дергаю вниз и через конденсатор этот перепад открывает транзистор и далее через опторазвязку включается тиристор.
А потом нужно вывод поднять "обратно взад". Ну, не стал разбираться, как напрямую управлять битом порта, который используется в альтернативной функции (а, кстати, можно так сделать?), а увлекся иной идеей: я поднимаю его тем же самым способом, что и сбрасываю - по совпадению кода в счетчике. Только в первом прерывании я программирую счетчик так, чтобы вывод поднимался по сопадению, а во втором - чтобы падал. Красиво :)

И еще одно. Мне никогда не нравилось отрабатывать паузы программно. Вот в этом проекте я уже 3 раза изменял тактовую частоту. При коротких задержках на Си такие изменения подстановкой дефинированных констант не уберешь. Да и вообще, не кашерно, и все тут :)
0
Yurkom
0 / 0 / 0
Регистрация: 23.05.2007
Сообщений: 792
22.08.2010, 15:59 5
А зачем такой короткий импульс на симистор? Насколько я понял - один тик таймера без предделителя?!
0
qbyt
0 / 0 / 0
Регистрация: 13.08.2010
Сообщений: 58
22.08.2010, 20:43 6
Цитата Сообщение от YurkoM
А зачем такой короткий импульс на симистор? Насколько я понял - один тик таймера без предделителя?!
Мне то же не понятно, и вызывает изумление..., в общем, прошу прощения, drvtos, поймал сам себя за я**а. Ели это ШИМ, то с не так надо работать, иначе я не понимаю зачем такой огород городить.
0
DY HOTT
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 4,000
22.08.2010, 21:12 7
Чето я тебя не понял. Т.е. ты хочешь сказать, что у тебя прерывание успевает вызываться в своем же обработчике прерывания и потому ты из него не выходишь? Ну так оно же очевидно -- они генеряться быстрей чем обрабатываются :) И сброс флага тут не причем, он сбрассывается при входе в прерывание. А так, получается, по логике ты второе прерывание принудительно зануляешь, словно его и не было вообще. Так может вообще тогда таймер тут не заводить? Че он зря щелкает.
0
DY HOTT
0 / 0 / 0
Регистрация: 22.01.2010
Сообщений: 4,000
22.08.2010, 21:15 8
И коли уж надо такой короткий тик, то зачем его делать в прерывании по ОСР? Может проще вставить один NOP? Не помню только как он в winavr пишется вроде бы volatile asm("nop"); как то так. И делаешь потом свой дрыг. А то у тебя на сях прогруз в стек, при вызове обработчкика даст тактов 20, если не больше, вместо положенного одного :)
0
qbyt
0 / 0 / 0
Регистрация: 13.08.2010
Сообщений: 58
22.08.2010, 21:18 9
Цитата Сообщение от DY HOTT
Чето я тебя не понял. Т.е. ты хочешь сказать, что у тебя прерывание успевает вызываться в своем же обработчике прерывания и потому ты из него не выходишь?
Да алгоритм у него кривой, никто так не работает, если априорно известно, что прерывания вырвбвтываются быстрее нежели сама обработка.
2 drvtos
Что вообще хотел сделать, может подскажем в каком напраление лучше двигаться...
0
drvtos
0 / 0 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
22.08.2010, 22:38 10
Цитата Сообщение от qbyt
Да алгоритм у него кривой, никто так не работает, если априорно известно, что прерывания вырвбвтываются быстрее нежели сама обработка.
2 drvtos
Что вообще хотел сделать, может подскажем в каком напраление лучше двигаться...
Ну, коллеги, ввас на минуту нельзя оставить. За водкой сходил, а тут уже приговор без аппеляции :)

Рассказываю. С конца, ИСТЕСНА.

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

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

Теперь с оргвопросами покончено. Переходим к технике. Я, наверное, плохо сформулировал единственный непонятный в данной теме вопрос: можно ли дрыгать ногой порта, если эта нога работает выходом таймера? Вы все похерили именно этот вопрос. Кто скажет?
Уточню: мега48. Таймер0. Выход OC0A суть порт PORTD.6. Задача? отработать регулируемую паузу 1...10 мс и дрыгнуть выход в ноль. После отработки паузы (я не хочу ее ждать в программе, запускаю таймер и знаю, что порт упадет, когда таймер сравняется с OCR0A) запускается тиристор с с этим вопрос решен. Задача только в том, чтобы ВЕРНУТЬ вывод в исходное состояние. Я и спрашиваю - так делается? Ну, можно таймер распрограммировать, порт, так сказать, освободить и сконфигурировать на выход. Но как-то это не греет.
Поэтому запускаю таймер еще раз - на этот раз не на 1...10 мс, а на 2 такта работы таймера (при его частоте это 128 мкс). И программирую, чтобы выход таймера OC0A теперь поднимался в единицу. Когда событие наступит, выход поднимется. а я в этом прерывании тупо останавливаю таймер и все. Когда придет следующий стартовый переход сетевого напряжения, я в основной программе загружу таймер паузой, запрграммирую на переход выхода OC0A в ноль и запущу.

Все прекрасно работает и, на мой взгляд, вполне правильно. Есть петля, она себе опрашивает кнопочки, сигналы упраления, а все временнЫе вещи работают в прерываниях. Ну зачем мне останавливать петлю и ждать те же 128 мкс?

Наконец, по поводу возникновения условия прерывания в ходе самого прерывания. Нужно же оценивать, мешает ли это или нет. В моем случае, когда я отрабатываю 128 мкс импульс, это может возникнуть, но мне это не мешает. Поэтому я с брасываю флаг на выходе ISR. И вам советую :)
0
Yurkom
0 / 0 / 0
Регистрация: 23.05.2007
Сообщений: 792
22.08.2010, 22:58 11
Цитата Сообщение от drvtos
2 такта работы таймера (при его частоте это 128 мкс)
А на какой же частоте МК работает, что за 64мкс не успевает прерывание обработать???
Если такой длинный обработчик, то он сводит на нет весь этот геморрой с аппаратным дёрганьем выхода..

Ну если уж хочеться именно аппаратно, то можно было выбрать режим PWM, когда по совпадению выход падает, а по достижению TOP - поднимается, и TOP задать больше OCRn на величину определяющую ширину импульса. А в прерывании по переполнению тормозить таймер. Т.е. получим режим PWM, но только один проход. Вроде должно работать..

зы: Для таймера 0 меги48 это mode7. TOP задаём в OCR0A, совпадение - в OCR0B. Выход берём с OC0B.
0
drvtos
0 / 0 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
22.08.2010, 23:44 12
Цитата Сообщение от YurkoM
А на какой же частоте МК работает, что за 64мкс не успевает прерывание обработать???
Если такой длинный обработчик, то он сводит на нет весь этот геморрой с аппаратным дёрганьем выхода..
Не-е, тут другое. Я ж говорил как-то, мне очень по душе эти новые МК с их примочками по экономии потребления. Прикинул здесь, обработка простая, арифметику использовал исключительно целочисленную (я много работал с арифметиками, так что изгалился по-взрослому). КАРОЧИ, если управляемая пауза работает в таймере (а не ждется основной прогой, то мне вполне хватает частоты процессора 250 кГц. Вот и не успевает, представь себе! Но, прелесть в том, что меня это не волнует. Это второе событие возникает именно тогда, когда таймер уже отработал короткий импульс и я соираюсь его отсановить до следующего раза (когда основная прога его запустит с долгим ипульсом).

Цитата Сообщение от YurkoM
можно было выбрать режим PWM, когда по совпадению выход падает, а по достижению TOP - поднимается, и TOP задать больше OCRn на величину определяющую ширину импульса. А в прерывании по переполнению тормозить таймер. Т.е. получим режим PWM, но только один проход. Вроде должно работать..
Я думал об этом. Но мне нужно быть готовым к новому циклу ДОВОЛЬНО БЫСТРО. Т.е., сразу по окончании короткой паузы (на 2 такта таймера) желательно быть готовым к тому, что ща придет синхроимпулсь и нужно снова генерить. А ты предлагаешь ждать до переполнения - оно наступит через 16 мс, что уже поздно.
Другое дело: использовать и OCR0A и OCR0В. Оба эти совпадения могут вызывать прерывание в одном цикле? Я что-то не разобрался. Если так, то действительно можно "разовый ШИМ" закрутить. Спасибо, тезка!
0
drvtos
0 / 0 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
23.08.2010, 00:18 13
Цитата Сообщение от YurkoM
Для таймера 0 меги48 это mode7. TOP задаём в OCR0A, совпадение - в OCR0B. Выход берём с OC0B.
Ну, почитал. Вроде как таки да. Можно. Получается, в OCR0B задаем рабочее значение длительности импульса (большое), а в OCR0А - на 1 больше. И по совпадению с OCR0B прерывание вообще не разрешаем - довольствуемся тем, что выход OC0B падает. А по следующему состоянию счетчика выход сам поднимается и возникает прерывание по достижению ТОР (флаг TOV0) и в нем мы таймер тупо останавливаем. Следующий синхроимпулсь распознает основной цикл, обнулит таймер0, запишет в OCR0B новое значение длительности импульса - и пустит таймер.
Красиво! Одно плохо - у меня в платах вывод 6 порта Д разведен на тиристор, а вывод 5 (как раз OC0B) - на индикатор. Резать некрасиво...

Спсибо еще раз! Я подумаю
0
qbyt
0 / 0 / 0
Регистрация: 13.08.2010
Сообщений: 58
23.08.2010, 02:53 14
Цитата Сообщение от drvtos
...мне очень по душе эти новые МК с их примочками по экономии потребления
...мне вполне хватает частоты процессора 250 кГц.
А оно того стоило уходить на тактовую частоту 250кГц, много удалось сэкономить, например, если бы была тактовая частота, скажем, на порядок больше? От силы экономия 1-2мА. Как я понимаю, схема относится к силовой электроники и в этом случае экономить копейки в потреблении не серьёзно. Опять же, скорее всего на управлении тем же тиристором ток для управления загоняется не меньше и светодиоды, возможно в схеме есть, а они кушают ещё больше.
Моё мнение, экономить на тактовой частоте контроллера ради уменьшения потребления не стоит, тут надо в комплексе рассматривать решение, опять же, тиристорное управление для этого не совсем удачное решение.
0
drvtos
0 / 0 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
23.08.2010, 22:17 15
Цитата Сообщение от qbyt
Моё мнение, ... надо в комплексе рассматривать решение, опять же, тиристорное управление для этого не совсем удачное решение.
Согласен! Я и рассмотрел в комплексе.
Во-первых, зачем? У меня питание 12 В (задано без вариантов, девайс идет в работающие изделия, которых сотни уже работают). На входе мостик, остается около 5,5 В на стабилизатор. Ну, может и надо было поставить, как рекомендует уважаемый SWK, преобразователь. Но поставил линейный 7805, а он греется на 150 мА - ого-го!
Поэтому ответ: чтобы не греть стабилизатор и не ставить радиатор.

Во-вторых, что урезать? Более всего тянул индикатор (3 цифры, светодиодный, динамический), а также сам процессор. Урезал индикатор - вместо привычных 150 Ом поставил 2 К - вполне достаточно для того, чтобы разглядывать эту (служебную) инфо.
Урезал частоту процессора.
В результате ток упал до 40-50 мА, стабилизатор чуть теплый. Лепота!

В-третьих, тиристор тянет от Vcc очень и очень мало. На него подается импульс скважностью около 50 - и ток в первичной цепи оптрона там, ориентировочно, миллиамперы. Размазанный в 50 раз - понимаешь, что выходит?

Так что силовая электроника может быть и экономной :) Я же не общее потребление по сети 220 В минимизирую...
0
qbyt
0 / 0 / 0
Регистрация: 13.08.2010
Сообщений: 58
24.08.2010, 22:02 16
Цитата Сообщение от drvtos
...У меня питание 12 В...На входе мостик, остается около 5,5 В на стабилизатор.
Это получается, что на твоём мосту падает 12В-5,5В=6,5В !!!, бред, не верю! Не может на мосту падать 6,5В.

В место 7805 используй либо LDO стабилизаторы, например, LP2989 или SPX1117, либо понижающие (Step Down) DC-DC, например, MC34063A
0
Yurkom
0 / 0 / 0
Регистрация: 23.05.2007
Сообщений: 792
24.08.2010, 22:16 17
Цитата Сообщение от qbyt
Цитата Сообщение от drvtos
...У меня питание 12 В...На входе мостик, остается около 5,5 В на стабилизатор.
.....Не может на мосту падать 6,5В.

Имеется в виду, что на входе 12, на выходе 5, стаб рассеивает остальное, т.е. около 7.
0
drvtos
0 / 0 / 0
Регистрация: 25.05.2010
Сообщений: 3,610
27.08.2010, 22:22 18
Цитата Сообщение от YurkoM
Имеется в виду, что на входе 12, на выходе 5, стаб рассеивает остальное, т.е. около 7.
Угу. Только еще 1,5 В забирает мостик на входе. Бережет схему от неправильного подключения питания, ну, и мощность немного рассеивает :)

Уважаемому qbyt: да уже вопрос (в этом проекте) не обсуждается. Есть партия плат, есть 7805. И, после моих мер по снижению потребления, она и не греется (на ней порядка 0,25 ВА всего осталось).

Спасибо всем участливым!
0
27.08.2010, 22:22
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
27.08.2010, 22:22

Зачем на PIC18F4550 аппаратный SPI?
Зачем на PIC18F4550 аппаратный SPI? У него же нет ни одного заметного...

Не запускается аппаратный TWI в ATmega128.
Пытаюсь соединить две ATmega128 через TWI. Что бы я ни делал, интерфейс никак...

Помогите запустить аппаратный TWI на AVRmega
Есть распаяная макетка ATmega88PA, в нее зашита программа на Си в AVRStudyo 5.0...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru