sf9 0 19 сентября, 2008 Опубликовано 19 сентября, 2008 · Жалоба Всем моё почтение. Прошу помощи в изучени прерываний и их обработке. Как их использовать,для чего в основном? Начал работу с ATmega128. Среда разработки WinAVR(AVR-GCC). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alliv 0 19 сентября, 2008 Опубликовано 19 сентября, 2008 · Жалоба простыми словами - прерывания (точнее код, который вы пишите для обработки соответствующего прерывания) используются для быстрой реакции на соответствующие запрограммированные ранее события. Например в начале программы вы инициализируете определённый таймер, чтобы этот таймер досчитывал до числа 1000, и после этого происходило прерывание сравнения данного канала таймера. А в обработчике прерывания для данного канала таймера вы пишите код, который выполняет, например, переключение лампочек на гирлянде :-). то же самое можно проделать и для всего остального, у микроконтроллеров богатая периферия, которая при установке соответствующих режимов будет генерить соответствующие прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
west329 0 19 сентября, 2008 Опубликовано 19 сентября, 2008 (изменено) · Жалоба Всем моё почтение. Прошу помощи в изучени прерываний и их обработке. Как их использовать,для чего в основном? Начал работу с ATmega128. Среда разработки WinAVR(AVR-GCC). Для WinAVR надо немного подправить синтаксис, но сама суть таже. [size=2]//ICC-AVR application builder : 19.09.2008 15:07:18 // Target : M128 // Crystal: 4.0000Mhz #include <iom128v.h> #include <macros.h> void port_init(void) { PORTA = 0x00; DDRA = 0x00; PORTB = 0x00; DDRB = 0x00; PORTC = 0x00; //m103 output only DDRC = 0x00; PORTD = 0x00; DDRD = 0x00; PORTE = 0x00; DDRE = 0x00; PORTF = 0x00; DDRF = 0x00; PORTG = 0x00; DDRG = 0x00; } //TIMER0 initialize - prescale:64 // WGM: Normal // desired value: 5KHz // actual value: 5,208KHz (4,0%) void timer0_init(void) { TCCR0 = 0x00; //stop ASSR = 0x00; //set async mode TCNT0 = 0xF4; //set count OCR0 = 0x0C; TCCR0 = 0x04; //start timer } #pragma interrupt_handler timer0_ovf_isr:iv_TIM0_OVF void timer0_ovf_isr(void) { TCNT0 = 0xF4; //reload counter value } //TIMER1 initialize - prescale:8 // WGM: 0) Normal, TOP=0xFFFF // desired value: 25Hz // actual value: 25,000Hz (0,0%) void timer1_init(void) { TCCR1B = 0x00; //stop TCNT1H = 0xB1; //setup TCNT1L = 0xE0; OCR1AH = 0x4E; OCR1AL = 0x20; OCR1BH = 0x4E; OCR1BL = 0x20; OCR1CH = 0x4E; OCR1CL = 0x20; ICR1H = 0x4E; ICR1L = 0x20; TCCR1A = 0x00; TCCR1B = 0x02; //start Timer } #pragma interrupt_handler timer1_ovf_isr:iv_TIM1_OVF void timer1_ovf_isr(void) { //TIMER1 has overflowed TCNT1H = 0xB1; //reload counter high value TCNT1L = 0xE0; //reload counter low value } //SPI initialize // clock rate: 31250hz void spi_init(void) { SPCR = 0xC3; //setup SPI SPSR = 0x00; //setup SPI } #pragma interrupt_handler spi_stc_isr:iv_SPI_STC void spi_stc_isr(void) { //byte in SPDR has been sent/received } //UART0 initialize // desired baud rate: 57600 // actual: baud rate:62500 (7,8%) // char size: 8 bit // parity: Disabled void uart0_init(void) { UCSR0B = 0x00; //disable while setting baud rate UCSR0A = 0x00; UCSR0C = 0x06; UBRR0L = 0x03; //set baud rate lo UBRR0H = 0x00; //set baud rate hi UCSR0B = 0xF8; } #pragma interrupt_handler uart0_rx_isr:iv_USART0_RXC void uart0_rx_isr(void) { //uart has received a character in UDR } #pragma interrupt_handler uart0_udre_isr:iv_USART0_UDRE void uart0_udre_isr(void) { //character transferred to shift register so UDR is now empty } #pragma interrupt_handler uart0_tx_isr:iv_USART0_TXC void uart0_tx_isr(void) { //character has been transmitted } //Comparator initialize // trigger on: Falling output edge void comparator_init(void) { ACSR = ACSR & 0xF7; //ensure interrupt is off before changing ACSR = 0x8A; } #pragma interrupt_handler ana_comp_isr:iv_ANA_COMP void ana_comp_isr(void) { //analog comparator compare event } //ADC initialize // Conversion time: 208uS void adc_init(void) { ADCSRA = 0x00; //disable adc ADMUX = 0x00; //select adc input 0 ACSR = 0x8A; ADCSRA = 0x8E; } #pragma interrupt_handler adc_isr:iv_ADC void adc_isr(void) { //conversion complete, read value (int) using... // value=ADCL; //Read 8 low bits first (important) // value|=(int)ADCH << 8; //read 2 high bits and shift into top byte } #pragma interrupt_handler int0_isr:iv_INT0 void int0_isr(void) { //external interupt on INT0 } //call this routine to initialize all peripherals void init_devices(void) { //stop errant interrupts until set up CLI(); //disable all interrupts XDIV = 0x00; //xtal divider XMCRA = 0x00; //external memory port_init(); timer0_init(); timer1_init(); spi_init(); uart0_init(); comparator_init(); adc_init(); MCUCR = 0x00; EICRA = 0x00; //extended ext ints EICRB = 0x00; //extended ext ints EIMSK = 0x01; TIMSK = 0x05; //timer interrupt sources ETIMSK = 0x00; //extended timer interrupt sources SEI(); //re-enable interrupts //all peripherals are now initialized } // void main(void) { init_devices(); //insert your functional code here... } [/size] Изменено 19 сентября, 2008 пользователем west329_ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 19 сентября, 2008 Опубликовано 19 сентября, 2008 · Жалоба Как их использовать, для чего в основном? Ну вот вы смотрите фильм по тв, вдруг бац фильм прерывается, начинается реклама, потом она заканчивается и фильм продолжается именно с того места, где он прервался. Теперь представьте, что фильмом и рекламой должен управлять микроконтроллер. Известен размер фильма, но ни длительность рекламы, ни время её появления не известны...как быть? Тут на помощь может придти прерывание..А вообще, всю тему надо смещать в начинающие. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bloodden 0 19 сентября, 2008 Опубликовано 19 сентября, 2008 · Жалоба Это вроде параллельности выполнения задач: то что в прерываниях - более приоритетное, нежели в основном цикле. В основном цикле пусть себе лопатит, а, например, пришел байт по уару, в прерывании его считали с уарта и записали в буфер, и дальше поехали. Вот, типа того :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sf9 0 22 сентября, 2008 Опубликовано 22 сентября, 2008 · Жалоба :a14: Ребят,спасибо огромное,что простыми словами и быстро разъяснили. :a14: Буду понимать далее. А тема,действительно,должна повисеть в этой рубрике. Если можно,выложите примеры с-кодов с функциями обработки прерываний. :smile3046: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DogPawlowa 0 22 сентября, 2008 Опубликовано 22 сентября, 2008 · Жалоба Если можно,выложите примеры с-кодов с функциями обработки прерываний. :smile3046: Каких прерываний? Обычно даже в простенькой системе есть "системное" прерывание - от таймера, который тикает постоянно, прерывая основной цикл. У меня оно выглядит так: #pragma vector = TIMER0_COMP_vect __interrupt void TC0_int_handler ( void ) { ON_LED; BackgroundService(); __enable_interrupt(); InternalAdcService(); MotorsService(); FanControlService(); OFF_LED; } В нем даже вложенные прерывания разрешаются. И такие бывают :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NikitoS-86 0 22 сентября, 2008 Опубликовано 22 сентября, 2008 · Жалоба Добрый день. Дабы не плодить новых тем, спрошу здесь... Я как и автора занялся изучением AVR, использую так же как и автора AVRStudi в связке с WinAVR. И у меня тоже появились затруднения определённого плана. Я имею представление о том, что есть прерывание, что есть стек, указатель команд и вообще считаю хорошее знание касательно теории... Но дошло дело до практики... И попытался я написать простейший код... Итак ситуация: в качестве входа АЦП использоваться ADC7, надо будет на 3 выхода (PB0..2) выдавать адрес на мультиплексер, который будет переключать свои входы, на входв АДС7 будет как раз приходить сигнал с демультеплексора, АЦП должен оцифровать и записать эти данные в массив... Вот примерный код: #include <avr/io.h> #include <avr/signal.h> #include <avr/interrupt.h> void port_B_settings (void); void ADC_settings (void); void port_C_settings (void); int help_reg=0; ISR (ADC_vect) { help_reg = 1; } void main (void) { int Ubat[4]; int Tbat[4]; int Icur; port_B_settings(); ADC_settings(); for (int i=0;i<3;i++) { ADCSRA = 0xC8; sei(); while (!help_reg) {} Ubat = help_reg; } } void port_B_settings (void) { DDRB = 0x07; //PB0..1 - outputs } void ADC_settings (void) { ADMUX = 0x07; //ADC7 ADCSRA = 0x88; //ADEN=1 | ADIE = 1 } В нём правда ещё не выдаётся адрес никуда и т.д. Не суть... А суть в том, что у меня по-левому работает прерывание. Я хочу, чтобы после начала прерывания шло ожидание прерывания, после чего его обработка и после чего запись..., а у меня выходит всякая ересь и в симуляторе вконце концов вообще после первого "прохода" получается бесконечный цикл....=/ Что я делаю неправильно? Вопрос касательно языка С - можно ли обрабатывать прерывание не по этому макросу, а что называется ручками... Просто я не знаю как мне в такой обработчик прерывания отправить например указатель на мой массив, чтобы прям в обработчике осуществлять запись в массив, а не вводить для этого пресловутый help_reg=/ И ещё вопрос: я перед запуском АЦП настраиваю только его вход в ADMUX, а надо ли настраивать ещё первые байты, которые отвечают за настройку напряжения если не ошибаюсь... Вообще если можно, то посвятите немного о том, как настраивать и запускать АЦП, поскольку из даташита к сожалению не всё понял на английском, например мне не понятно немного что такое некий "непрерывный режим работы" АЦП, который настраивается через запись бита ADATA в регистре ADCSRA... Ах да, последнее: речь идёт о ATmega48 Заранее огромное спасибо ответившим, просто уже 2 дня мучаюсь с этим АЦП=/ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
NikitoS-86 0 22 сентября, 2008 Опубликовано 22 сентября, 2008 · Жалоба сообщение можно удалить Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mandrew 0 22 сентября, 2008 Опубликовано 22 сентября, 2008 (изменено) · Жалоба Если можно,выложите примеры с-кодов с функциями обработки прерываний. Ниже пример программы, показывающий как во время выполнения программы (мигание 1-ым светодиодом) зажечь 2-ой светодиод по нажатию кнопки. Короче говоря, показан обработчик внешнего прерывания. Компилятор - avr-gcc. #include <avr/io.h> #include <avr/interrupt.h> volatile uint8_t led2IsOn = 0; int main(void) { uint8_t led1IsOn = 0; // Конфигурируем порт на выход. DDRB |= (1 << DDB6) | (1 << DDB5); // Настраиваем порт на котором висит кнопка на вход. DDRE &= ~(1 << DDE6); PORTE |= (1 << PORTE6); // Прерывание по возрастающий фронту сигнала. EICRB = (1 << ISC61) | (1<< ISC60); sei(); // Глобальное разрешение прерываний. EIMSK |= (1 << INT6); // Разрешаем внешнее прерывание, заведенное на PORTE6. // Бесконечный цикл. while(1) { uint16_t i; // Задержка. for(i = 65535; i != 0; i--); if(led1IsOn) { led1IsOn = 0; PORTB &= ~(1 << PORTB5); // Выключаем светодиод 1. } else { led1IsOn = 1; PORTB |= (1 << PORTB5); // Включаем светодиод 1. } } } // Обработчик прерывания. SIGNAL(SIG_INTERRUPT6) { if(led2IsOn) { led2IsOn = 0; PORTB &= ~(1 << PORTB6); // Выключаем светодиод 2. } else { led2IsOn = 1; PORTB |= (1 << PORTB6); // Включаем светодиод 2. } } Изменено 22 сентября, 2008 пользователем mandrew Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sf9 0 23 сентября, 2008 Опубликовано 23 сентября, 2008 · Жалоба Вот,нашёл толковый сайт,где автор описывает работу с прерываниями,таймерами/счётчиками. Довольно толково и для чайников,на мой взгляд,весьма полезно: http://www.pcports.ru/articles/avr2.php Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sf9 0 24 сентября, 2008 Опубликовано 24 сентября, 2008 · Жалоба Работа с таймерами/счётчиками в AVR очень хорошо описана в этом AN: AVR130.pdf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться