Перейти к содержанию
    

Прерывания в ATmega128

Всем моё почтение.

Прошу помощи в изучени прерываний и их обработке.

Как их использовать,для чего в основном?

Начал работу с ATmega128. Среда разработки WinAVR(AVR-GCC).

:help:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Например в начале программы вы инициализируете определённый таймер, чтобы этот таймер досчитывал до числа 1000, и после этого происходило прерывание сравнения данного канала таймера. А в обработчике прерывания для данного канала таймера вы пишите код, который выполняет, например, переключение лампочек на гирлянде :-).

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем моё почтение.

Прошу помощи в изучени прерываний и их обработке.

Как их использовать,для чего в основном?

Начал работу с ATmega128. Среда разработки WinAVR(AVR-GCC).

:help:

 

 

Для 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]

Изменено пользователем west329_

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как их использовать, для чего в основном?

Ну вот вы смотрите фильм по тв, вдруг бац фильм прерывается, начинается реклама, потом она заканчивается и фильм продолжается именно с того места, где он прервался. Теперь представьте, что фильмом и рекламой должен управлять микроконтроллер. Известен размер фильма, но ни длительность рекламы, ни время её появления не известны...как быть? Тут на помощь может придти прерывание..А вообще, всю тему надо смещать в начинающие.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это вроде параллельности выполнения задач: то что в прерываниях - более приоритетное, нежели в основном цикле. В основном цикле пусть себе лопатит, а, например, пришел байт по уару, в прерывании его считали с уарта и записали в буфер, и дальше поехали. Вот, типа того :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

:a14: Ребят,спасибо огромное,что простыми словами и быстро разъяснили. :a14:

Буду понимать далее.

А тема,действительно,должна повисеть в этой рубрике.

Если можно,выложите примеры с-кодов с функциями обработки прерываний.

:smile3046:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если можно,выложите примеры с-кодов с функциями обработки прерываний.

:smile3046:

Каких прерываний?

Обычно даже в простенькой системе есть "системное" прерывание - от таймера, который тикает постоянно, прерывая основной цикл.

У меня оно выглядит так:

 

#pragma vector = TIMER0_COMP_vect
__interrupt void TC0_int_handler ( void )
{ ON_LED;
  BackgroundService();
  __enable_interrupt(); 
  InternalAdcService();
  MotorsService();
  FanControlService();
  OFF_LED;
}

 

В нем даже вложенные прерывания разрешаются. И такие бывают :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день. Дабы не плодить новых тем, спрошу здесь... Я как и автора занялся изучением 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 дня мучаюсь с этим АЦП=/

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если можно,выложите примеры с-кодов с функциями обработки прерываний.

 

Ниже пример программы, показывающий как во время выполнения программы (мигание 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.
  }
}

Изменено пользователем mandrew

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот,нашёл толковый сайт,где автор описывает работу с прерываниями,таймерами/счётчиками.

Довольно толково и для чайников,на мой взгляд,весьма полезно:

http://www.pcports.ru/articles/avr2.php

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Работа с таймерами/счётчиками в AVR очень хорошо описана в этом AN:

AVR130.pdf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...