Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AVR-IAR и внешнее прерывание
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
mr_ia
Добрый день уважаемые.
Имею очень простой вопрос, как в IAR обработать внешнее прерывание.
До этого програмил в CVAVR, но вот решил мигрировать.
Опишу задачу. Нужно обработать внешнее прерывание INT0, по нижнему уровню.
Посмотрел примеры, вопросы ответы, нашел более менее подходящий кусок по обработке прерывания при перемолнении таймера счетчика, кусок работает. Написал для обработки INT0- Не работает...

Привожу код.
CODE
#include <iom128.h>
#include <inavr.h>
#include <ina90.h>


//volatile char flag;

//Обработка прерывания INT0***
#pragma vector = 0x04
//#pragma type_attribute=__interrupt
//void my_handler(void)
__interrupt void INT0_ISR(void)
{
__disable_interrupt(); //отключаем глобальные прерывания
//flag=flag++;
PORTD_Bit6 = 0; //смотрим по состоянию ножки выполнилось ли прерывание
}

int main( void )
{
DDRD_Bit7 = 1; //конфигурируем биты
DDRD_Bit6 = 1;
PORTD_Bit6 = 1;

DDRE=0xFF; //конфигурируем порты
DDRF=0xFF;
DDRB=0xFF;


EIMSK|= 1<<0; //Разрешаем INT0
EICRA &= ~(1<<0); // по нижнему уровню
__enable_interrupt(); //разрешаем глобальные прерывания

while (1)
{
__delay_cycles(1000000);
PORTD_Bit7 = 1; //смотрим не виснет ли
__delay_cycles(1000000);
PORTD_Bit7 = 0;

PORTE=EIMSK; //смотрим текущее состояние
PORTF=SREG;
PORTB=EIFR;
}
}



Если закоментировать обработку прерывания, то:
Код
EIMSK=0x01;
SREG=0x82;
EIFR=0xF0;

P.S. Компилируется без ошибок. Моделирую в Proteuse, за неимением железа под рукой... Мб глюк протеуса, но врядли ибо аналогичное в CVAVR работает без проблем.
В чем я ошибся?
clpe
Цитата(mr_ia @ Feb 12 2009, 13:31) *
__interrupt void INT0_ISR(void)
{
__disable_interrupt(); //отключаем глобальные прерывания
//flag=flag++;
PORTD_Bit6 = 0; //смотрим по состоянию ножки выполнилось ли прерывание
}

А где потом __enable_interrupt(); в цикле обработке прерывания
aspID
Как минимум, в том, что прерывание отработает только один раз
Цитата
Код
__interrupt void INT0_ISR(void)
{
__disable_interrupt(); //отключаем глобальные прерывания
//flag=flag++;
PORTD_Bit6 = 0; //смотрим по состоянию ножки выполнилось ли прерывание
}


P.S. сорри, пока писал, оказалось что повторился.
mr_ia
если добавить
__enable_interrupt();
в обработку прерывания то результат не меняется.
Т.е. протеус, мб в нем конечно дело, не меняет PORTD_Bit6 в 0

т.е. думаю прерывание вообще не обрабатывается.
и на других ногах PORTF,E,B ничего не меняется с момента старта эмулирования.

Если обработку прерывания закомментировать то PORTF,E,B по крайней мере показывают состояние EIMSK, SREG, EIFR;
MrYuran
А ногу, на которой INT0, не забываете подёргать? Может, программно ей помахать?
Или это PORTD_Bit7?
Вообще я бы не стал серьёзно рассматривать работу в симуляторе. Гораздо продуктивнее общение с живым железом.
clpe
Цитата(mr_ia @ Feb 12 2009, 13:31) *
while (1)
{
__delay_cycles(1000000);
PORTD_Bit7 = 1; //смотрим не виснет ли
__delay_cycles(1000000);
PORTD_Bit7 = 0;

PORTE=EIMSK; //смотрим текущее состояние
PORTF=SREG;
PORTB=EIFR;
}

В начальном состоянии PORTD_Bit6 в 0 и в прерывании ты хочешь его установить в 0, а в цикле обратно в состояние 1 не возвращаешь.
Палыч
Цитата(mr_ia @ Feb 12 2009, 13:31) *
Моделирую в Proteuse, за неимением железа под рукой... Мб глюк протеуса, но врядли ибо аналогичное в CVAVR работает без проблем. В чем я ошибся?
В AVRStudio Ваш пример работает... Несколько замечаний по самой программе:
1. Запрешать прерывания в обработчике прерываний не имеет смысла: при входе в него - прерывания запрещены; при выходе - разрешаются вновь.
2. Устанавливать таким образом: EICRA &= ~(1<<0); уровень сигнала - несколько странно (уровень определяется двумя битами)
3. Если уровень ни INT0 стал низким и не меняется, то при выходе из прерывания - тут же произайдёт новое прерывание по INT0 (правда, успеет выполниться одна команда основного цикла). Т.е., обычно, в прерывании по уровню что-то делают с условием срабатывания.
4. Если меняете EICRA, то делают это до разрешения прерывания в EIMSK и очищают флаг прерывания (см. даташит).
mr_ia
Ногу дергаю кнопкой(в протеусе). изначально INT0 он же PORTD_0 притянут к 1, по схеме вопросов нет (сама простая да и код из CVAVR работает на ней без проблем). Т.е. думаю проблема в коде IARa. На счет преимущества готового железа это конечно, но его под рукой сейчас нет, и в ближайшее время не будет.


Почему PORTD_Bit6 в 0?
изначально устанавливаю его в 1, и перевожу в 0 ТОЛЬКО в прерывании.

int main( void )
{
DDRD_Bit7 = 1; //конфигурируем биты
DDRD_Bit6 = 1;
PORTD_Bit6 = 1;


//Обработка прерывания INT0***
#pragma vector = 0x04
//#pragma type_attribute=__interrupt
//void my_handler(void)
__interrupt void INT0_ISR(void)
{
__disable_interrupt(); //отключаем глобальные прерывания
//flag=flag++;
PORTD_Bit6 = 0; //смотрим по состоянию ножки выполнилось ли прерывание
}
clpe
DDRE=0xFF; //конфигурируем порты
DDRF=0xFF;
DDRB = 0xFF; - без этой строки работает
mr_ia
Цитата(Палыч @ Feb 12 2009, 15:33) *
В AVRStudio Ваш пример работает... Несколько замечаний по самой программе:
1. Запрешать прерывания в обработчике прерываний не имеет смысла: при входе в него - прерывания запрещены; при выходе - разрешаются вновь.
2. Устанавливать таким образом: EICRA &= ~(1<<0); уровень сигнала - несколько странно (уровень определяется двумя битами)
3. Если уровень ни INT0 стал низким и не меняется, то при выходе из прерывания - тут же произайдёт новое прерывание по INT0 (правда, успеет выполниться одна команда основного цикла). Т.е., обычно, в прерывании по уровню что-то делают с условием срабатывания.
4. Если меняете EICRA, то делают это до разрешения прерывания в EIMSK и очищают флаг прерывания (см. даташит).



Спасибо что попробовали в AVRStudio, но хочется то что бы в IAR заработало...
По пункту 2 полностью согласен.
По пункту 3 попрошу уточнить.
Если EICRA=0x00 т.е. 0 и 1 биты в 0. Как только разрешены глобальные прерывания, происходит соответсвенно обработка INT0, в теле обработки я например устанавливаю EIMSK 0 бит в 0, и запрещаю прерывания для INT0, тогда зацикливаться не будет? я правильно думаю?

Вообщем то пока писал проверил.
Добавил в обработку прерывания запрет для всех INT EIMSK=0x00;
В CVAVR помогло. В IAR нет...sad.gif



Цитата(clpe @ Feb 12 2009, 15:56) *
DDRE=0xFF; //конфигурируем порты
DDRF=0xFF;
DDRB = 0xFF; - без этой строки работает


Простите а Вы в чем компилировали/проверяли?
у меня нет sad.gif

DDRB = 0xFF; - без этой строки работает

совершенно безобидная на мой взгляд строка...
clpe
Нет всетаки виноват протеус... У меня работает: Proteus 7.4 sp3 iar5.11b. ваш код
CODE
#include <ioavr.h>
#include <inavr.h>
#include <ina90.h>

//Обработка прерывания INT0***
#pragma vector = 0x04

__interrupt void INT0_ISR(void)
{
PORTD_Bit6 = 0; //смотрим по состоянию ножки выполнилось ли прерывание
}

int main( void )
{
DDRD_Bit7 = 1; //конфигурируем биты
DDRD_Bit6 = 1;
PORTD_Bit6 = 1;

DDRE=0xFF; //конфигурируем порты
DDRF=0xFF;
DDRB = 0xFF;

EIMSK|= 1<<0; //Разрешаем INT0
EICRA &= ~(1<<0); // по нижнему уровню
__enable_interrupt(); //разрешаем глобальные прерывания

while (1)
{
__delay_cycles(1000000);
PORTD_Bit7 = 1; //смотрим не виснет ли
__delay_cycles(1000000);
PORTD_Bit7 = 0;

PORTE=EIMSK; //смотрим текущее состояние
PORTF=SREG;
PORTB=EIFR;
}
}
А на счет DDRB = 0xFF просто я запутался rolleyes.gif
Палыч
Цитата(mr_ia @ Feb 12 2009, 15:05) *
Спасибо что попробовали в AVRStudio, но хочется то что бы в IAR заработало...
Выше я говорил о том, что Ваша программа, оттранслированная IAR, нормально симулируется AVRStudio. Поскольку, аналогичная программа из CVAVR нормально симулируется в протеусе и Ваша программа, оттранслированная IAR у "чужих" тоже нормально симулируется, то, имхо, в настройках проекта IAR у Вас какая-то бяка...
zltigo
Цитата(mr_ia @ Feb 12 2009, 13:31) *
нашел более менее подходящий кусок по обработке прерывания при перемолнении таймера счетчика, кусок работает. Написал для обработки INT0- Не работает...


А кто будет делать:

EXTINT = EXTINT_EINT0; // Clear the EXT interrupt flag
VICVectAddr = 0; // Dummy write to signal end of interrupt

А вообще исходник бредовый, и разговоры об эмуляции периферийного железа всякими приблудами - тоже sad.gif  Вместо многочасового тыка в "эмуляторе" надежнее и проще уделить 15 минут чтению документации и со знанием дела, уверенно написать эти несколько строк. 
Палыч
Цитата(zltigo @ Feb 12 2009, 16:29) *
А кто будет делать:
EXTINT = EXTINT_EINT0; // Clear the EXT interrupt flag
VICVectAddr = 0; // Dummy write to signal end of interrupt
Имхо, это - "с другой оперы"... А, что работу перифирии проверять в симуляторе - плохо, тут я полностью согласен.
zltigo
Цитата(Палыч @ Feb 12 2009, 16:53) *
Имхо, это - "с другой оперы"... А, что работу перифирии проверять в симуляторе - плохо, тут я полностью согласен.

А!!! Чего-то привиделось, что LPC sad.gif. Тему перенес.
Atashi
глянул на схему и чет задумался о дребезгах всяких...
SysRq
Цитата(mr_ia @ Feb 12 2009, 13:31) *
Код
#pragma vector = 0x04

Может я не в тему, IAR'а у меня нет.. 0x04 - это правильное значение? С вектором INT0 не совпадает. Почему не использорвать вполне понятные символические имена констант из хедеров?..
clpe
Цитата(Atashi @ Feb 13 2009, 02:10) *
глянул на схему и чет задумался о дребезгах всяких...

Это-же для протеуса какие дребезги!?
Палыч
Цитата(SysRq @ Feb 13 2009, 03:02) *
0x04 - это правильное значение? С вектором INT0 не совпадает.
Это - в IAR'е такой прикол, чтобы всех запутать biggrin.gif . Адреса указываются в байтах, даже для памяти программ, чего нет у остальных трансляторов.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.