Прерывания avr: AVR. Учебный Курс. Программирование на Си. Часть 3

Содержание

AVR Studio: как написать обработчик прерывания | avr

Микроконтроллеры без использования прерываний практически ничего не стоят. Прерывание (interrupt) получило свое название из того факта, что при срабатывании прерывания по какому-нибудь событию нормальное выполнение программы прерывается, и выполняется особый код — код обработчика прерывания (interrupt handler). Прерывания можно рассматривать просто как подпрограммы, которые приостанавливают нормальный процесс выполнения программы до тех пор, пока код подпрограммы обработчика прерывания не будет завершен. После того, как обработчик прерывания завершит свою работу, ядро микроконтроллера вернется к исполнению основной программы точно в той точке, где она была прервана прерыванием. События прерывания обычно происходят от каких-то внешних асинхронных воздействий на микроконтроллер — например, переключение логического уровня на внешнем выводе порта, либо переполнение регистра таймера, что означает истечение заданного интервала времени, и т. д.

Почему же прерывания так важны? Например, мы могли бы обойтись без прерываний, в бесконечном цикле опрашивая возникновение интересующих нас событий. Такое функционирование программы называется опросом (polling). Но опрос имеет много недостатков и неудобств — к примеру, программа будет тратить на циклы ресурс ядра, который мог быть потрачен на выполнение других действий. Это одна из причин, почему у микроконтроллера есть много источников прерывания, которые могут использоваться при необходимости. Вместо проверки событий на возникновение микроконтроллер имеет возможность прервать нормальный поток программы при возникновении события и переключиться на действия обработчика события прерывания (ISR, interrupt service routine), затем вернуться обратно и продолжить выполнение основной программы.

[Векторы прерывания]

Векторами прерывания называют адреса перехода на обработчик прерывания. Список таких адресов называется таблицей векторов прерываний, и он находится в памяти программ по заранее известному адресу. У микроконтроллеров AVR таблица векторов прерываний находится в самом начале памяти программ FLASH по адресу 0. Содержимое таблицы векторов прерываний определяет программист, когда ему нужно реализовать обработку прерываний.

Каждый вектор прерывания AVR занимает в памяти 2 байта (1 слово кода инструкций AVR), и представляет из себя команду rjmp относительный_адрес. Вот так, например, выглядит на языке ассемблера полностью заполненная таблица прерываний микроконтроллера ATmega16:

$000 rjmp RESET               ;сброс (начало программы)
$001 rjmp INT0_vect           ;внешнее прерывание 0
$002 rjmp INT1_vect           ;внешнее прерывание 1
$003 rjmp TIMER2_COMP_vect    ;прерывание совпадения сравнения таймера 2
$004 rjmp TIMER2_OVF_vect     ;прерывание переполнения таймера 2
$005 rjmp TIMER1_CAPT_vect    ;прерывание события захвата таймера 1
$006 rjmp TIMER1_COMPA_vect   ;прерывание совпадения сравнения A таймера 1
$007 rjmp TIMER1_COMPB_vect   ;прерывание совпадения сравнения B таймера 1
$008 rjmp TIMER1_OVF_vect     ;прерывание переполнения таймера 1
$009 rjmp TIMER0_OVF_vect     ;прерывание переполнения таймера 0
$00A rjmp SPI_STC_vect        ;прерывание завершения передачи SPI
$00B rjmp USART_RXC_vect      ;прерывание завершения приема байта UART
$00C rjmp USART_UDRE_vect     ;прерывание опустошения регистра передачи UART
$00D rjmp USART_TXC_vect      ;прерывание завершения передачи байта UART
$00E rjmp ADC_vect            ;прерывание завершения преобразования АЦП
$00F rjmp EE_RDY_vect         ;прерывание готовности EEPROM
$010 rjmp ANA_COMP_vect       ;прерывание изменения сигнала на выходе компаратора
$011 rjmp TWI_vect            ;прерывание двухпроводного интерфейса TWI (I2C)
$012 rjmp INT2_vect           ;внешнее прерывание 2
$013 rjmp TIMER0_COMP_vect    ;прерывание совпадения сравнения таймера 0
$014 rjmp SPM_RDY_vect        ;прерывание готовности к записи памяти программ

Такая полностью заполненная векторами таблица никогда не применяется. На практике обычно используется только 1..4 прерывания, в этом случае не используемые адреса векторов могут остаться не инициализированными. Обратите внимание, что в левом столбце метками обозначены шестнадцатеричные адреса инструкций, соответствующие байтовые адреса будут в 2 раза больше (потому что инструкция rjmp занимает 2 байта).

В этой статье на примере обработчика прерывания таймера 1 для ATmega16 рассказывается, как организовать обработчик прерывания в проекте GCC. Показаны два варианта реализации — на языке C и ассемблера. В примерах алгоритм работы таймера отличается, но это не важно для рассмотрения методов организации обработчика прерывания.

[Обработчик прерывания на C]

Это самый простой вариант. В данном примере используется следующий алгоритм — основная программа настраивает таймер 1 и запускает обработчик прерывания. Этот обработчик срабатывает раз в секунду и заботится о себе сам, подстраивая величину счетчика TCNT1 (чтобы прерывания происходили точно раз в секунду). Обработчик раз в секунду также декрементирует счетчик времени timer, который устанавливается и отслеживается в основной программе. Прерывание таймера разрешено постоянно (разрешается при старте программы). Таким образом, основная программа может получить любую задержку времени в интервале от 1 до 255 секунд.

Процесс по шагам:

1. Настраиваем таймер и разрешаем прерывание для него. Этот код должен вызываться однократно, при старте программы. Для этого можно написать отдельную процедуру, например:

#include <avr/io.h>
..
 void SetupTIMER1 (void){
    //На частоте тактов 16 МГц прерывание переполнения T/C1
    // произойдет через (счет до 65535):
    // 1 << CS10 4096 mkS (нет прескалера Fclk)
    // 1 << CS11 32.768 mS (Fclk/8)
    // (1 << CS11)|(1 << CS10) 262.144 mS (Fclk/64)
    // 1 << CS12 1048.576 mS (Fclk/256)
    TCCR1B = (1 << CS12);
    TCNT1 = 65536-62439;        //коррекция счетчика, чтобы время было ровно 1 секунда
    /* Разрешение прерывания overflow таймера 1. */
    TIMSK = (1 << TOIE1);}

2. В любом из модулей проекта (можно в общем, где функция main, а можно в отдельном, например timer.c) пишем код обработчика прерывания таймера. Вот пример такого кода:

#include <avr/interrupt.h>#include <avr/io.h>
..
 u8 timer;
 
ISR (TIMER1_OVF_vect){
    //теперь прерывание будет происходить через 62439 тиков
    // таймера 1, что на частоте 16 МГц составит 1 сек.
    TCNT1 = 65536-62439;
    //Далее идет код, который будет работать каждую секунду.
    //Желательно, чтобы этот код был короче.
    if (timer)
        timer--;}

3. В нужном месте разрешаем прерывания программы. Это делается также однократно, после того как сделаны все приготовления:

    sei();

[Обработчик прерывания на ASM]

Этот вариант не многим сложнее, просто организован по-другому. Я его сделал на основе отдельного файла, который содержит только код на языке ассемблера. Алгоритм тут тоже другой — обработчик прерывания срабатывает раз в секунду и сам себя запрещает. Основная программа отслеживает это событие и меняет секундные счетчики (выполняет все действия, которые нужно выполнять раз в секунду), и нова разрешает прерывание. Такой алгоритм позволяет ускорить обработку прерывания, что может быть критично для некоторых задач (например, только так можно организовать точный отсчет времени при использовании библиотеки V-USB). Процесс по шагам:

1. Настраиваем таймер. Это может делать код на C. Все точно так же, как и с обработчиком прерывания на C (см. шаг 1).

2. Готовим файл с нашим кодом обработчика на языке ассемблера. Вот пример кода:

#include <avr/io.h>
    .text
    .global TIMER1_OVF_vect
TIMER1_OVF_vect:
    push    R24
    ldi     R24, 0
    out     _SFR_IO_ADDR(TIMSK), R24
    pop     R24
    reti

Этот код будет работать очень быстро, поскольку короткий. Он почти ничего не делает, только запрещает прерывание от таймера 1 (в регистре TIMSK сбрасываются все флаги, в том числе и нужный нам флаг TOIE1). Запускать прерывание будет основная программа, как только обнаружит, что прерывание запрещено (путем анализа состояния флага TOIE1).

3. В нужном месте разрешаем прерывания программы. Это делается также однократно, после того как сделаны все приготовления:

    sei();

4. В основной программе, в главном цикле main, должен максимально часто вызываться следующий код:

..void main (void){
    ..
    while (1)
    {
        ..
        if (0==(TIMSK & (1 << TOIE1)))
        {
            TCNT1 = ONE_SECOND;
            TIMSK = (1 << TOIE1);
            //далее действия, которые будут происходить 
            // раз в секунду
            ..
        }
        ..
    }}

[Общие замечания]

Можно заметить, что в обоих примерах использовалась именованная константа TIMER1_OVF_vect, которая задает адрес вектора прерывания таймера 1. Имена констант можно узнать во включаемом файле процессора. Для ATmega16, например, это будет файл c:\WinAVR-20080610\avr\include\avr\iom16.h. Чтобы имена стали доступны, не нужно добавлять именно этот файл в проект директивой #include, достаточно добавить #include <avr/io.h> и задать макроопределение, задающее тип процессора (например, MCU = atmega16. Это можно сделать либо в Makefile, либо в свойствах проекта).

При использовании одновременно нескольких прерываний в AVR важно помнить, что прерывания имеют фиксированный, ненастраиваемый приоритет. Чем меньше адрес вектора прерывания, тем приоритет у прерывания выше. Этот приоритет срабатывает, если при выходе из прерывания имеется несколько необработанных флагов прерывания. Прерывание с более высоким приоритетом НЕ может временно приостановить уже работающий обработчик прерывания с меньшим приоритетом, чтобы немедленно выполнить свой код. Работает система примерно так:

— когда общие прерывания разрешены (установлен бит I в регистре SREG, этот бит называют

Global Interrupt Enable), то может быть вызвано любое разрешенное прерывание с любым приоритетом. Бит Global Interrupt Enable может быть принудительно сброшен или установлен командами CLI или SEI соответственно.
— для того, чтобы прерывание могло сработать и вызвать свой обработчик, кроме установки бита Global Interrupt Enable необходимо также установить бит разрешения соответствующего прерывания. Для таймеров-счетчиков это биты регистра TIMSK, для интерфейса SPI — бит SPIE в регистре SPCR, и т. д.
— когда срабатывает любое прерывание, то сразу очищается флаг I (Global Interrupt Enable), и автоматически запрещаются все прерывания, пока не произойдет выход из обработчика прерывания. Если во время работы обработчика прерывания возникали условия, при которых должны были сработать другие прерывания, то эти другие прерывания не вызываются, а просто запоминаются соответствующие им флаги (прерывания «откладываются» на будущее). При выходе из обработчика прерывания запомненные флаги прерывания запустят нужный обработчик прерывания в соответствии с назначенным ему приоритетом (если на данный момент имеется несколько отложенных прерываний).
— разработчик может в обработчике прерывания вызвать команду SEI (которая установит флаг Global Interrupt Enable), тем самым разрешив выполнение других прерываний во время работы этого обработчика прерывания. Тогда, если произойдет новое другое прерывание до завершения текущего обработчика (в котором уже была вызвана команда SEI), текущий обработчик прерывания будет приостановлен, адрес возврата в него будет сохранен в стеке и будет вызвано новое прерывание. Таким способом можно обеспечить некое подобие соблюдения приоритета — в низкоприоритетных обработчиках прерывания должна первой стоять команда SEI, а в высокоприоритетных обработчиках команда SEI должна отсутствовать, что обеспечит выполнение этого обработчика полностью.

Отсутствие возможности четко настроить приоритет — довольно серьезный недостаток платформы AVR.

[Ссылки]

1. Как комбинировать программу на Си (C) с кодом ассемблера (ASM).

Прерывания микроконтроллеров семейства AVR | AVR Lab устройства на микроконтроллерах AVR

Меня самого мучал вопрос что ж это такое, искал информацию, но из-за того, что в русскоязычном интернете нету ни одного толкового сайта наполненного информацией, структурированного и ухоженного, кроме конечно easyelectronics.ru пришлось потратить довольно много времени на освоение данного вопроса.

Еще одна сложность изучения прерываний в том, что наилучший показатель по освоению материала достигается примерами рабочего кода программы. Такие хоть и есть, НО!!! Из-за того, что многие в основном ленивые проггеры начинают работу с компилятором CV-AVR, в котором хоть и есть предварительный редактор кода с помощью которого перед написанием программы можно предварительно сконфигурировать те же таймеры, модули USART, TWI, но все же крайне не удобный интерфейс, с моей точки зрения и вообще CV-AVR мне крайне не симпатичен. Другое дело AVR Studio в связке с WinAVR 🙂
Так очень распространены примеры программ на ассемблере, у него куча преимуществ но один значительный недостаток, при изучении с нуля необходимо присутствие специалиста. Так же в интернете есть еще куча различных вариантов для написания управляющей программы микроконтроллера такие как: Basic, Flow Code и тд. тп. Но как-то так сложилось, как в своё время с операционной системой Windows, она не самая лучшая но никому нет до этого дела. Кстати о Windows советую посмотреть фильм «Пираты силиконовой долины».

И так, прерывание — это событие, после которого выполняется подпрограмма (обработчик прерываний).
Пример:
Основная программа — бегущий огонек из 8-ми светодиодов, выполняется при включении питания микроконтроллера.
К микроконтроллеру подключена кнопка к ножке int0 (смотри datasheet на конкретный микроконтроллер).
При нажатии на кнопку программа бегущего огонька останавливается и восемь светодиодов начинают мигать — это и есть программа обработки прерывания. Светодиоды мигают столько, сколько задано в подпрограмме, после окончания выполнения подпрограммы обработки прерывания микроконтроллер возвращается к выполнению основной программы — бегущего огонька, при том с места, на котором он ранее остановился.

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

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

  1. SIGNAL (SIG_INTERRUPT1)//программа-обработчик прерываний

  2. {

  3. ...

  4. }

  5.  

  6. int main (void)//основная программа

  7. {

  8. sei(); //Разрешаем глобально прерывания

  9. ...

  10. }

Так же предусмотрен вариант, когда необходимо на время запретить выполнение прерываний, для это используют следующую запись в языке C:

  1. {

  2. cli(); //запрещаем выполнение прерываний

  3. ...

  4. }

Вызвать прерывание можно несколькими способами, верней даже это не способы а причины появления прерывания. В datasheet имеется таблица прерывания микроконтроллера, и в ней можно посмотреть все источники этих самых прерываний.
Таблица прерываний микроконтроллера ATtiny2313:

Номер вектора Адрес подпрограммы Источник прерывания Описание прерывания
1 0x0000 RESET Внешний сброс, сброс при включении питания, сброс по срабатыванию охранного таймера
2 0x0001 INT0 Внешний запрос на прерывание по входу INT0
3 0x0002 INT1 Внешний запрос на прерывание по входу INT1
4 0x0003 TIMER1 САРТ Прерывание по захвату таймера/счетчика 1
5 0x0004 TIMER1 COMPA Прерывание по совпадению таймера/счетчика 1. Канал А
6 0x0005 T1MER1 OVF Прерывание по переполнению таймера/счетчика 1
7 0x0006 TIMER0 OVF Прерывание по переполнению таймера/счетчика 0
8 0x0007 USART0, RX USART0, прием завершен
9 0x0008 USART0, UDRE USART0 буфер данных пуст
10 0x0009 USART0, TX USART0, передача завершена
11 0x000A ANALOG COMP Прерывание от аналогового компаратора
12 0x000B PCINT Прерывание по изменению на любом из выводов
13 0x000C TIMER1 COMPB Прерывание по совпадению таймера/счетчика 1. Канал В
14 0x000D TIMER0 COMPA Прерывание по совпадению таймера/счетчика 0. Канал В
15 0x000E TIMER0 COMPB Прерывание по совпадению таймера/счетчика 0. Канал А
16 0x000F USI START Прерывание по USI. Готовность к старту
17 0x0010 USI OVERFLOW Прерывание по USI, Переполнение
18 0x0011 ЕЕ READY Готовность EEPROM
19 0x0012 WDT OVERFLOW Переполнение охранного таймера

Пример синтаксиса объявления подпрограммы-обработчика прерываний:
Обработка прерываний INT1

  1. SIGNAL (SIG_INTERRUPT1)

  2. {

  3. ...

  4. }

Обработка прерываний по переполнению таймера 0

  1. ISR (TIMER0_OVF_vect)

  2. {

  3. ...

  4. }

Обработка прерывания по приходу байта на модуль USART

  1. ISR(USART_RXC_vect)

  2. {

  3. ...

  4. }

  1. SIGNAL (SIG_OVERFLOW0)

  2. {

  3. ...

  4. }

Синтаксис для компилятора WinAVR в CV-AVR немножко по другому будет выглядеть, обратите внимание.

Прерывания очень полезны если программа довольно большая и имеет разветвленную структуру, прерывания могут облегчить её написание уменьшить размер.

Прерывания имеют свой приоритет, так если например в программе используется несколько прерываний и так получилось что в один и тот же момент времени случаются два прерывания, то в первую очередь будет выполнено прерывание с приоритетом выше. Приоритет прерываний указан в таблице прерываний, чем меньше адрес подпрограммы прерывания, тем выше приоритет.
Наглядный пример работы с прерываниями int0 и int1 с исходным кодом и комментариями.

interrupt — Обрабатывать прерывания с одинаковым приоритетом

Если у меня есть набор периферийных устройств в микроконтроллере AVR с равным приоритетом, использует ли микроконтроллер циклический перебор в качестве подходящего арбитражного механизма для прерывания подсистемы?

Или как можно управлять прерываниями с тем же приоритетом, что и в одно и то же время?

1

Dinithi 28 Июл 2019 в 11:31

Это зависит.

Например, «классические» микроконтроллеры AVR имеют простой одноуровневый контроллер прерываний. Это означает, что, когда прерывание запущено, флаг прерывания в SREG сбрасывается, таким образом блокируя любое другое прерывание от запуска. Инструкция IRET снова включает этот флаг, и после выполнения одной инструкции из основного кода следующее прерывание готово к выполнению.

Когда несколько запросов на прерывание подаются одновременно, то выбирается только один с самым низким адресом вектора прерывания.

Например, обратитесь к ATMega328P таблице (раздел 6.7 Сброс и обработка прерываний , стр. 15):

Чем ниже адрес, тем выше уровень приоритета.

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

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

Например, в ATmega3208 (см. таблица данных, раздел 12. Контроллер прерываний процессора ):

Все векторы прерываний, кроме NMI, по умолчанию назначаются уровню приоритета 0 (нормальный). Пользователь может переопределить это, назначив один из этих векторов в качестве вектора с высоким приоритетом. Устройство будет иметь много векторов с нормальным приоритетом, и некоторые из них могут быть ожидающими одновременно. Доступны две разные схемы планирования, позволяющие выбрать, какие из ожидающих прерываний с обычным приоритетом следует обслуживать первыми: статический и циклический

Итак, ответ : внимательно прочитайте таблицу данных той части, с которой вы работаете.

0

AterLux 31 Июл 2019 в 11:36

Раздел 9 таблицы ATmega328PB озаглавлен «Ядро процессора AVR» и гласит:

Все прерывания имеют отдельный вектор прерывания в таблице векторов прерываний. Прерывания имеют приоритет в соответствии с их положением вектора прерывания. Чем ниже адрес вектора прерывания, тем выше приоритет.

0

David Grayson 29 Июл 2019 в 18:37

Лекция №9″Спящие» режимы центрального процессора — Лекции — Микропроцессорная техника


Лекции — Микропроцессорная техника
скачать (4640.4 kb.)

Доступные файлы (14):


содержание

Лекция_09_Режимы энергосбережения.doc

Лекция №9

«Спящие» режимы центрального процессора

Микроконтроллеры нередко применяются в приборах с питанием от аккуму­ляторов и батарей. В таких случаях особенно важно, чтобы потребление тока мик­роконтроллером было как можно меньшим. Микроконтроллеры семейства АVR изготовлены по технологии КМОП, и потому для их работы необходим ток не­большой силы. Благодаря выбору более низкого уровня питающего напряжения, потребление тока снижается еще больше. Если и этого недостаточно, то можно выбрать настолько низкую тактовую частоту, насколько позволяет прикладная за­дача, поскольку из-за токов перезарядки паразитных емкостей ток потребления КМОП-схем почти пропорционален тактовой частоте. В дополнение к перечисленным мерам, центральный процессор микроконтроллеров семейства АVR можно перевести в режим пониженного энергопотребления или «спящий режим» (Sleep Mode). В таком режиме потребление тока резко снижается.

В табл. 9.1 показано типичное потребление тока центральным процессором модели А T90S1200 для различных режимов работы при температуре окружающей среды 250С, отключенном аналоговом компараторе и заблокированном сторожевом таймере.

Таблица 9.1. Типичное потребление тока Icc центральным процессором модели АT90S 1200 для различных режимов работы


Vcc

Ф

Icc/

Активный


Icc/

Ждущий


Icc/

Пониженное потребление


5 В

12МГц

9 мА

2,4 мА

0,75 мкА

5 В

2МГц

4 мА

1 мА

0,75 мкА

3,3 В

6МГц

2,5 мА

0,7 мА

0,1 мкА

3,3 В

2МГц

1,8 мА

0,4 мА

0,1 мкА

Для перевода микроконтроллера семейства АVR в один из режимов понижен­ного потребления энергии необходимо разряд SE (Sleep EnabIe) регистра управле­ния MCUCR установить в лог. 1, а затем выполнить команду sleep. Благодаря связи команды sleep с разрядом SE, центральный процессор не может быть не­преднамеренно переведен в режим пониженного энергопотребления.

Когда во время режима пониженного энергопотребления происходит преры­вание, центральный процессор выходит из «спящего» режима, выполняет подпро­грамму обработки прерывания и продолжает выполнение программы с команды, следующей после команды sleep. Если во время режима пониженного энергопо­требления поступает сигнал сброса, то центральный процессор выходит из «спя­щего» режима и продолжает выполнение программы с команды, расположенной по адресу $000 области команд.

Содержимое рабочих регистров и регистров ввода/вывода в течение режима пониженного энергопотребления остается неизменным. В том случае, если режим пониженного энергопотребления должен быть отключен в результате прерывания по уровню сигнала, низкий уровень должен сохраняться дольше, чем 16 мс, кото­рые необходимы для перехода осциллятора в рабочий режим. В противном слу­чае, соответствующий флаг прерываний снова должен быть сброшен прежде, чем центральный процессор возобновит работу.

Для микроконтроллеров семейства АVR может быть выбран один из двух «спящих» режимов:


  • в ждущем режиме (Idle Mode) работа центрального процессора приоста­навливается, но таймер/счетчик, сторожевой таймер, система прерываний и тактирования остаются активными. Благодаря этому, центральный процессор может быть возвращен в обычный режим работы с помощью стороже­вого таймера, таймера/счетчика или внешнего прерывания. Если нет необ­ходимости в том, чтобы выход из ждущего режима осуществлялся с помо­щью аналогового компаратора, то компаратор отключается посредством установки в лог. 1 разряда АСО регистра ACSR. Это еще более снижает потребление тока в ждущем режиме, как это показано в табл. 9.2.

  • В режиме пониженного энергопотребления (Power Down Mode) систем­ный осциллятор (а значит и весь микроконтроллер) находится в отключен­ном состоянии.

    Icc / Ждущий

    Ф

    Аналоговый компаратор

    Аналоговый компаратор

    включен

    отключен

    58

    12 МГц

    9мА

    2,9мА

    2,4мА

    58

    2МГц

    4мА

    1,5 мА

    1 мА

    3,38

    6МГц

    2,5 мА

    0,9 мА

    0,7 мА

    3,3 8

    2МГц

    1,8 мА

    0,5 мА

    0,4мА

    В табл. 9.3 показано потребление тока центральным процессором модели А T90S 1200 в режиме пониженного энергопотребления при активном и от­ключенном сторожевом таймере.

    Таблица 9.3. Типичное потребление тока lee центральным процессором модели AT90S1200 в режиме пониженного энергопотребления при активном и отключенном сторожевом таймере


    Vcc

    Icc / Пониженное потребление

    Icc / Пониженное потребление

    Сторожевой таймер включен

    Сторожевой таймер отключен

    58

    80 мкА

    0,75 мкА

    3,38

    18мкА

    0,1 мкА

    Выбор одного из «спящих» режимов осуществляется с помощью разряда SM регистра MCUCR. Если разряд SM установлен в лог. 1, то микроконтроллер пере­водится в режим пониженного энергопотребления последующей командой sleep, если же разряд SM сброшен в лог.

    Режимы энергосбережения нужны для того, чтобы экономить питание. Применять их следует при питании от автономного ис­точника — как правило, любой МК большую часть времени простаивает в ожидании событий. Например, процедура динамической индикации, повторяющаяся с частотой сотни герц, сама по себе выполняется всего за несколько десятков микросекунд, т. е. занимает сотые доли общего време­ни работы МК и даже меньше. Если считать, что в активном режиме МК по­требляет порядка 10-15 мА, то ввод его в режим энергосбережения в паузах между событиями позволяет снизить суммарное потребление до -100 мкА и повысить временной ресурс работы схемы в сотни раз.

    Но правильно организовать работу МК в режиме энергосбережения не так-то просто. Следует учитывать внешние соединения — один забытый в «нулевом состоянии» выход с подсоединенным подтягивающим резистором способен испортить всю картину. Переключение всех выводов на вход также может не дать нужного эффекта, если часть из них «висит в воздухе» — наводки будут переключать входную логику (если она не отключена) и тем самым повышать потребление. Отключение логики происходит автоматически при вводе в ре­жим энергосбережения, но не для всех контактов — остаются включенными, например, выводы внешних прерываний, если они разрешены в программе, а также некоторые другие, если они используются в режиме альтернативных функций. Следует также не забывать выключать аналоговый компаратор, ко­торый включен по умолчанию.

    Не имеет большого смысла заниматься энергосбережением, если у вас в схе­ме имеются другие элементы с большим потреблением, которые невозможно отключить. Большинство стан­дартных устройств, ориентированных на подключение к МК (EEPROM, часы, tlasll-карты, современные преобразователи уровня RS-232), автоматически (или по команде извне) устанавливаются в режим пониженного энергопо­требления, когда находятся в ожидании команд. Но могут быть и компонен­ты, для отключения которых приходится изобретать специальные способы.

    Нужно учитывать и нюансы внутренней работы МК. Скажем, когда вы посы­лаете байт через UART, то собственно передача после окончания операции записи в регистр данных начнет выполняться аппаратно, и может длиться порядка миллисекунды, в то время как GPU уже формально свободен для других операций.

    В различных моделях МК АVR имеется от 2-3 (семейства Classic и Tiny) до 5-6 (старшие Mega) режимов энергосбережения.

    Два базовых режима общие для всех моделей: Idle mode и Power Down mode. Отметим, что к режимам энергосбережения также относят стоящий несколько особняком специальный режим АDС Noise Reduction, который имеет иное назначение, и мы его рас­смотрим далее. При практическом использовании режимов энергосбере­жения следует учесть, что их нельзя вызывать из процедуры прерывания — только из основной программы.

    В МК АVR имеются следующие разновидности режимов энергосбережения.

    В Idle mode (режиме ожидания) останавливается GPU (а также устройство управления выборкой команд из памяти). Все периферийные устройства ­таймеры, АЦП, порты — продолжают функционировать. Поэтому значи­тельной экономии не получается: потребление снижается лишь на 30-50%. Очевидно, что режим Idle mode имеет смысл использовать тогда, когда общее по­требление устройства лимитируется именно МК, который при этом обяза­тельно должен находиться в состоянии постоянной готовности.

    Само по себе программирование режима энергосбережения — без учета всех отмеченных нюансов — очень простое.

    Некоторую сложность здесь пред­ставляет только выбор режима из-за того, что в разных моделях МК АVR управляющие биты SMx (в младших Tiny и в семействе Classic всего один та­кой бит SM, выбирающий между двумя режимами Idle и Power Down, в ос­тальных их больше) «разбросаны» по разным регистрам, и приходится смот­реть в описание, чтобы не ошибиться. В большинстве младших моделей Mega, а также в Tiny и Classic, эти биты находятся в регистре MCUCR – в том же, который отвечает и за внешние прерывания. Но вот, например в АTmega8515 (в отличие от сделанного на его же основе А Tmega8535, где также один ре­гистр MCUCR), три бита SM0..2 разбросаны по трем регистрам MSUCR, MCUCSR и IEMCUCR. Есть и другие варианты: в АTmega16 все эти биты также в одном ре­гистре MCUCR, но бит SM2 почему-то поменялся местами с битом разрешения slеер -режима SE.

    По умолчанию все биты установки ^ , сколько их есть (три SM0. . Он определяется установкой бита SM1 (либо SM, если бит уста­новки единственный) в единичное состояние. Удобен режим Standby (в тех МК, где он доступен), когда тактовый генератор продолжает работать, и по­тому для выхода из состояния «сна» требуется гораздо меньше времени ­всего шесть машинных циклов, в то время как выход из режима Power Down по времени аналогичен запуску МК после сброса.


    Скачать файл (4640.4 kb.)


    Программа обработки прерываний AVR не выполняется так быстро, как ожидалось (накладные расходы на инструкции?)

    Существует много регистров PUSH’а и POP’ов, которые собираются в стек до того, как ваш фактический ISR запускается, что превышает 5 упомянутых вами тактовых циклов. Посмотрите на разборку сгенерированного кода.

    В зависимости от того, какую цепочку инструментов вы используете, выгрузка сборки с перечислением нас производится разными способами. Я работаю в командной строке Linux, и это команда, которую я использую (для ввода требуется файл .elf):

    avr-objdump -C -d $(src).elf

    Взгляните на фрагмент кода, который я недавно использовал для ATtiny. Вот как выглядит C-код:

    ISR( INT0_vect ) {
            uint8_t myTIFR  = TIFR;
            uint8_t myTCNT1 = TCNT1;

    И это сгенерированный код сборки для него:

    00000056 <INT0_vect>:
      56:   1f 92           push    r1
      58:   0f 92           push    r0
      5a:   0f b6           in      r0, SREG        ; 0x3f
      5c:   0f 92           push    r0
      5e:   11 24           eor     r1, r1
      60:   2f 93           push    r18
      62:   3f 93           push    r19
      64:   4f 93           push    r20
      66:   8f 93           push    r24
      68:   9f 93           push    r25
      6a:   af 93           push    r26
      6c:   bf 93           push    r27
      6e:   48 b7           in      r20, TIFR       ; uint8_t myTIFR  = TIFR;
      70:   2f b5           in      r18, TCNT1      ; uint8_t myTCNT1 = TCNT1;

    Честно говоря, моя подпрограмма C использует еще пару переменных, которые вызывают все эти push-сообщения и pop-ы, но вы поняли идею.

    Загрузка 32-битной переменной выглядит следующим образом:

      ec:   80 91 78 00     lds     r24, 0x0078
      f0:   90 91 79 00     lds     r25, 0x0079
      f4:   a0 91 7a 00     lds     r26, 0x007A
      f8:   b0 91 7b 00     lds     r27, 0x007B

    Увеличение 32-битной переменной на 1 выглядит следующим образом:

      5e:   11 24           eor     r1, r1
      d6:   01 96           adiw    r24, 0x01       ; 1
      d8:   a1 1d           adc     r26, r1
      da:   b1 1d           adc     r27, r1

    Хранение 32-битной переменной выглядит следующим образом:

      dc:   80 93 78 00     sts     0x0078, r24
      e0:   90 93 79 00     sts     0x0079, r25
      e4:   a0 93 7a 00     sts     0x007A, r26
      e8:   b0 93 7b 00     sts     0x007B, r27

    Затем, конечно, вы должны вытолкнуть старые значения после выхода из ISR:

     126:   bf 91           pop     r27
     128:   af 91           pop     r26
     12a:   9f 91           pop     r25
     12c:   8f 91           pop     r24
     12e:   4f 91           pop     r20
     130:   3f 91           pop     r19
     132:   2f 91           pop     r18
     134:   0f 90           pop     r0
     136:   0f be           out     SREG, r0        ; 0x3f
     138:   0f 90           pop     r0
     13a:   1f 90           pop     r1
     13c:   18 95           reti

    Согласно сводке инструкций в техническом описании, большинство инструкций являются одноразовыми, а PUSH и POP — двухцикловыми. Вы поняли, откуда берется задержка?

    12. Микроконтроллеры avr. Подсистема прерываний.

    Обработка внешних прерываний

    В качестве входов внешних прерываний используются входы портов с альтернативной функцией. Это входы PD2, PD3 для прерываний INT0, INT1 и вход PE0 для прерывания INT2 в микроконтроллере ATmega8515. Запросы внешних прерываний INT0, INT1 могут быть представлены низким уровнем сигнала прерывания (L), переходом от высокого уровня сигнала к низкому (HL — по отрицательному фронту), переходом от низкого уровня сигнала к высокому (LH — по положительному фронту), запрос INT2 только переходами (LH) и (HL). В зависимости от типа запроса в регистре управления микроконтроллера MCUCR необходимо установить биты ISCx0 и ISCx1 согласно табл. для каждого из прерываний INTx (x=0,1) и определить бит ICS2 в регистре EMCUCR для прерывания INT2. При ICS2=0 прерывание осуществляется по положительному фронту, при ICS2=1 – по отрицательному фронту.

    Таблица выбора типа запроса

    IXCx1

    ISCx0

    Тип запроса

    0

    0

    L

    0

    1

    1

    0

    HL

    1

    1

    LH

    Подготовить программу переключения светодиодов с использованием внешнего прерывания от кнопки STOP. Согласно поставленным требованиям в блок инициализации микроконтроллера внесем ряд изменений:

    — добавляем вектор прерываний;

    — указатель стека устанавливаем на последнюю ячейку ОЗУ;

    — разрешаем внешнее прерывание INT0 (по сигналу «0» на линии 2 порта PD) и прерывания вообще.

    Так как внешнее прерывание INT0 представлено сигналом на входе порта PD2, в качестве кнопки STOP используем кнопку SW2 и программируем PD2 на ввод. Пример программы 2 приведен ниже. Задержка представлена подпрограммой DELAY. Программа работает аналогично программе 1, но нажатие кнопки STOP вызывает прерывание.

    Система прерываний – комплекс программных и аппаратных средств, команд и программ обслуживания прерываний.

    Прерывание прекращает нормальный ход программы для выполнения приоритетной задачи, определяемой внутренним или внешним событием МП.

    Функции СП:

    1) Идентификация запроса прерывания.

    2) Сохранение состояния прерванной программы

    3) Обслуживание прерывания.

    4) Восстановление состояния прерванной программы.

    По типу событий, вызвавших прерывание:

    1) От внешних устройств (УВВ).

    2) Запросы от устройств времени (таймеров).

    3) Запросы каналов последовательного ВВ.

    По способу представления запроса:

    1) Статического типа – запрос сохраняет свое значение на все время обслуживания, поэтому после обслуживания необходимо сбросить прерывание.

    2) Динамического типа – запрос остается активным в течении некоторого времени. Он должен быть зафиксирован до тех пор, пока не будет принят на обслуживание.

    Время реакции лежит в пределах самой длинной команды. На это время необходимо сохранять запрос.

    Применение прерываний при программировании на AVR

    Для того чтобы сделать все то же самое, но «по-настоящему», придется вос­пользоваться таймером, а значит — прерываниями. А значит — текст про­граммы придется оформить несколько по-иному. Если помните, я говорил, что при возникновении прерывания процессор обращается по некоторому фиксированному адресу. Для каждой модели МК количество и типы преры­ваний различаются, поэтому эти адреса фиксированы для каждой модели процессора.

    Это первые адреса памяти программ, начиная с адреса 0:0 и дальше, столько адресов, сколько имеется прерываний. В МК ATtiny2313 имеется 19 преры­ваний (в его классическом аналоге было всего 11), соответственно, они зани­мают первые 19 адресов памяти программ. Напомним, что так как коды ко­манд двухбайтовые, то память программ организована по 16-битовым словам, поэтому адреса в памяти программ означают адреса слов, а байтовый адрес будет в два раза больше (то есть не О, 1, 2,…, а О, 2, 4,…). Это вас ни в коей мере не должно волновать, потому что абсолютные адреса вам отсчиты­вать не придется: достаточно правильно оформить первые 19 строк кода, по­сле секции всех определений. Поэтому использующая прерывания программа для ATtiny2313 всегда должна начинаться с последовательности команд, представляющих векторы прерываний, по следующему образцу: .include «tn2313def.inc» < секция определений>

    rjmp RESET ; Reset Handler rjmp EXT__INTO ; External InterruptO Handler rjmp EXT__INT1 ; External Interruptl Handler rjmp TIM1_CAPT ; Timer 1 Capture Handler rjmp TIM1_C0MPA ; Timer 1 CompareA Handler rjmp TIM1_0VF ; Timer 1 Overflow Handler rjmp TIM0_OVF ; Timer 0 Overflow Handler rjmp USARTO_RXC ; USARTO RX Complete Handler rjmp USARTO__DRE / USARTO,UDR Empty Handler rjmp USARTO_TXC ; USARTO TX Canplete Handler rjmp ANA_COMP ; Analog Comparator Handler rjmp PCINT ; Pin Change Interrupt rjmp TIMER1_C0MPB ; Timer 1 Compare В Handler

    rjmp TIMER0_COMPA ; Timer О Compare A Handler

    rjmp TIMER0_COMPB ; Timer 0 Compare В Handler

    rjmp USI_START ; USI Start Handler

    rjmp USI_OVERFLOW ; USI Overflow Handler

    rjmp EE_READY ; EEPROM Ready Handler

    rjmp WDT__OVERFLOW ; Watchdog Overflow Handler

    Подробности

    Если сравнить таблицы прерываний «классического» AT90S2313 и ATtiny2313, то окажется, что первые 11 векторов у них полностью совпадают. Отсутствую­щие в «классическом» аналоге остальные 8 векторов можно просто проигно­рировать: если соответствующие прерывания не задействованы, то к ним ни­когда не произойдет обращения. По этой причине программы, написанные для AT90S2313, полностью совместимы с ATtiny2313 (не требуется даже заменять файл определений констант 2313def.inc). Мало того, если программа написана для ATtiny2313, но используются только функции «классического» аналога, то имеет место и обратная совместимость: просто первые после таблицы преры­ваний восемь ячеек памяти профзмм будут заняты пустыми командами, к ко­торым обращения не будет происходить. В дальнейшем мы будем без поясне­ний говорить о том, что приведенные программы годятся для обеих версий этого МК.

    Здесь rjmp— знакомая нам команда безусловного перехода, а reset, EXTiNTO и т. п. — метки в тексте программы, откуда начинается текст про­цедуры (подпрограммы) обработки прерывания. Метки могут быть обозна­чены и по-иному, тут полный произвол. Сам переход осуществляется автома­тически, если в процессе выполнения программы возникнут условия для возникновения соответствующего прерывания, для чего и его отдельно, и прерывания вообще надо еще разрешить. Все прерывания и особенности их вызова мы рассматривать, конечно, не будем, а некоторые их них разберем далее на практике.

    Сначала заметим, что подобным образом должна выглядеть программа, если вы используете все 19 прерываний, чего на самом деле, конечно, не бывает. Но каждой записи rjmp <метка> должно соответствовать наличие метки да­лее в тексте, иначе ассемблер укажет на ошибку (посылать по неизвестному адресу нехорошо!). Поэтому если некоторые прерывания не используются, то, вообще говоря, можно вместо безусловных переходов наставить в соот­ветствующих строках команд пор (по operation — ее код равен просто нулям во всех разрядах), но на практике вместо них чаще ставят команду reti, ко­торая означает возврат из процедуры прерывания к выполнению основной программы, если вдруг оно возникнет.

    Заметки на полях

    На самом деле в общем случае не имеет значения, какую именно команду в этих строках ставить — выполняться они никогда не будут, если соответст­вующие прерывания не активированы, нам только нужно занять память, что­бы команда rjmp используемого нами прерывания оказалась по нужному адресу: например, можно поставить команду rjmp $0000. что МК начинает выполнение программы с нулевого адреса. Программа из предыдущего раздела с него прямо начиналась (то есть при включении питания сразу выполнялся первый оператор, потом второй и т. д.), но если задействованы прерывания, мы не можем так поступить. По­этому в самом первой строке программы обязательно должен стоять указа­тель на процедуру, которая осуществляется в самом начале работы, и обычно так и называется — reset. Эта процедура должна начинаться со следующих обязательных строк:

    reset: ;Старт главной программы

    Idi rl6,low(ramend) /только для 2313 out spl,rl6 /установка указателя стека

    <начальные установки и разрешение необходимых прерываний>

    sei /общее разрешение прерываний

    Если указатель стека не установить, то прерывания не заработают. Установка указателя стека для ряда моделей Tiny (в которых отсутствует SRAM) не требуется, а вот для других, в том числе и всех Mega, где количество SRAM превышает 256 байт, эта загрузка будет протекать иначе, так как константа RAMEND там размером больше байта:

    RESET: ;для моделей с SRAM более 256 байт

    ldi temp,low(RAMEND) ;загрузка указателя стека out SPL, temp

    ldi temp,high(RAMEND) ;загрузка указателя стека out SPH, temp

    Подробности

    Как мы уже отмечали в главе 18, стек — область памяти, куда будут записы­ваться адреса точек возврата при вызове подпрограмм по команде rcaii или перехода к обработчикам прерываний. По окончании процедуры обработки прерывания (по команде reti) или обычной подпрограммы (по команде ret) этот адрес считывается в программный счетчик и выполнение основной про­граммы продолжается. Если во время выполнения обработчика данного пре­рывания происходит другое прерывание с большим приоритетом (это нужно специально разрешать, по умолчанию в AVR любое прерывание будет ожи­дать окончания обработки предыдущего), то в стек записывается также и этот текущий адрес команды, таким образом ошибиться при последовательном возврате невозможно. Стек устроен по принципу «последним вошел — первым вышел», то есть извлекается всегда последнее записанное туда значение. Программист может использовать стек и для своих целей (командами push и pop — например, для сохранения текущего значения рабочих регистров), но неопытным программистам лучше активно этим способом не пользоваться: вероятность допустить трудно обнаруживаемую ошибку значительно возрас­тает. Тем более что в AVR и без того достаточно РОН (в отличие, например, от х51, где без стека обойтись практически невозможно), а при необходимости можно еще и хранить текущие значения в SRAM.

    AVR® Interrupts — Справка разработчика

    AVR ® Устройства предоставляют несколько различных источников прерываний, включая внутренние и внешние прерывания. Прерывания могут остановить выполнение основной программы для выполнения отдельной процедуры обслуживания прерывания (ISR). Когда ISR завершается, управление программой возвращается к основной программе по инструкции, которая была прервана.

    Каждое из этих прерываний имеет отдельный программный вектор в области памяти программ.Всем прерываниям назначаются отдельные биты разрешения, которые должны быть записаны в одной логике вместе с битом разрешения глобального прерывания в регистре состояния, чтобы разрешить прерывание. Самые низкие адреса в области памяти программ по умолчанию определены как векторы сброса и прерывания. Они определили уровни приоритета; чем ниже адрес, тем выше уровень приоритета. СБРОС имеет наивысший приоритет, затем следует запрос внешнего прерывания 0 (INT0).

    Таблица векторов прерываний для ATmega324PB:

    Векторы прерывания могут быть перемещены в начало секции загрузочной флэш-памяти путем установки бита IVSEL в регистре управления MCU MCUCR.Вектор сброса также можно переместить в начало секции загрузочной флэш-памяти, запрограммировав предохранитель BOOTRST.

    Как это работает

    При возникновении прерывания I-бит разрешения глобального прерывания сбрасывается, и все прерывания блокируются. Вектор прерывания направляет управление программой на правильный ISR или выполнение. Этот ISR может записывать логическую единицу в I-бит, чтобы разрешить вложенные прерывания. Все разрешенные прерывания могут затем прервать текущую программу обработки прерываний.Когда ISR завершается и из ISR выполняется команда возврата (RETI), глобальный I-бит автоматически устанавливается в «ON», и выполнение программы возвращается к основной программе по инструкции, которая была прервана.

    Время реакции на прерывание

    Ответ выполнения прерывания для всех разрешенных прерываний AVR составляет минимум четыре тактовых цикла. После четырех тактов выполняется адрес программного вектора для действительной процедуры обработки прерывания. В течение этого периода четырех тактов счетчик программ помещается в стек.Вектор обычно представляет собой переход к программе обработки прерывания, и этот переход занимает три тактовых цикла. Если прерывание происходит во время выполнения многоцикловой инструкции, эта инструкция завершается до того, как прерывание будет обработано.

    Если прерывание происходит, когда MCU находится в спящем режиме, время реакции на выполнение прерывания увеличивается на четыре тактовых цикла. Это увеличение происходит в дополнение ко времени запуска из выбранного спящего режима. Возврат из подпрограммы обработки прерывания занимает четыре тактовых цикла.В течение этих четырех циклов тактовой частоты программный счетчик (два байта) извлекается из стека, указатель стека увеличивается на два и устанавливается бит I в SREG.

    Векторы прерывания AVR

    Ниже приведены таблицы прерываний, доступных на микроконтроллерах AVR, используемых в классе. Имя вектора — это идентификатор, который следует использовать в начале процедура обслуживания прерывания (ISR). Например, ISR для вывода ATmega328P Запрос на изменение прерывания 0 будет выглядеть так.

    ISR (PCINT0_vect)
    {
    // код ISR
    
    }
     

    Примечание: имена векторов не всегда одинаковы для одного и того же прерывания. в разных процессорах. Перед написание ISR.

    ATmega328P
    900 7 12 USART_UDRE_vect Tx Complete
    Номер вектора Определение прерывания Имя вектора
    2 Запрос внешнего прерывания 0 INT0_vect
    3 Запрос внешнего прерывания 1 INT1_vect
    4 Запрос прерывания смены контакта 0 PCINT0_vect
    5 Запрос прерывания смены контакта 1 PCINT1_vect
    6 Запрос прерывания смены контакта 2 PCINT2_vect
    Прерывание тайм-аута сторожевого таймера WDT_vect
    8 Таймер / счетчик2 Сравнить соответствие A TIMER2_COMPA_vect
    9 Таймер / счетчик2 Сравнить соответствие B TI MER2_COMPB_vect
    10 Переполнение таймера / счетчика2 TIMER2_OVF_vect
    11 Timer / Counter1 Capture Event 1 TIMER1_CAPT_vect
    A Match TIMER1_COMPA_vect
    13 Таймер / счетчик1 Сравнить соответствие B TIMER1_COMPB_vect
    14 Таймер / счетчик1 Переполнение TIMER1_OVF_vect Сравнить время TIMER1_OVF_vect TIMER0_COMPA_vect
    16 Таймер / счетчик0 Сравнить соответствие B TIMER0_COMPB_vect
    17 Таймер / счетчик0 18 Переполнение TIMER0_OVF_vect TIMER0_OVF_ve Последовательная передача SPI завершена SPI_STC_vect
    19 USART Rx Complete USART_RX_vect
    20 Регистр данных USART пуст USART_UDRE_vect43 USART_TX_vect
    22 Преобразование АЦП завершено ADC_vect
    23 EEPROM Ready EE_READY_vect
    ANNAL
    Compara
    25 Двухпроводной последовательный интерфейс TWI_vect
    26 Сохранение памяти программ для чтения SPM_READY_vect
    ATtiny4313
    _COMPA_vect _COMPA_vect TIMER 7
    Номер вектора Определение прерывания Имя вектора
    2 Запрос внешнего прерывания 0 INT0_vect
    3 Запрос внешнего прерывания 1 INT1_vect
    4 Timer / Counter1 Capture Event TIMER1_CAPT_vect
    5 Timer / Counter1 Compare Match A TIMER1_COMPA_vect
    6
    6 Таймер / счетчик0 Переполнение TIMER0_OVF_vect
    8 USART Rx Complete USART0_RX_vect
    9 Регистр данных USART пуст USART0_UDRE_ve ct
    10 USART Tx Complete USART0_TX_vect
    11 Аналоговый компаратор ANA_COMP_vect
    12 900_43 PCMP_vect Запрос прерывания изменения контакта
    13 Таймер / Счетчик1 Сравнить Соответствие B TIMER1_COMPB_vect
    14 Таймер / Счетчик0 Сравнить Соответствие A TIMER0_COMPA_vect
    Сравнение
    15 Таймер B / Счетчик0 900 TIMER0_COMPB_vect
    16 Состояние запуска USI USI_START_vect
    17 Переполнение USI USI_OVERFLOW_vect
    18 EEP42 EEP42 M_READY_vect
    19 Переполнение сторожевого таймера WDT_OVERFLOW_vect
    20 Запрос прерывания по смене пина 1 PCINT_A_vect
    PCINT_A_vect PCINT_A_vect Прерывание Запрос на изменение пина
    ATtiny85
    _OVF_vect 41 _vect
    Номер вектора Определение прерывания Имя вектора
    1 Внешний запрос прерывания 0 INT0_vect
    2 Запрос прерывания смены контакта 0 PCINT0_vect
    3 Таймер / Счетчик1 Сравнить Соответствие A TIMER1_COMPA_vect
    4 Таймер / Счетчик1 Переполнение TIMER1_OVF_vect
    5
    5 Таймер / Счетчик0 Переполнение 6 EEPROM Ready EE_RDY_vect
    7 Аналоговый компаратор ANA_COMP_vect
    8 Преобразование ADC завершено ADC_vect
    9 Таймер / Счетчик1 Сравнить Соответствие B TIMER1_COMPB_vect
    10 Таймер / Счетчик0 Сравнить Соответствие A TIMER0_COMPA_vect
    11 Согласование Таймер / Счетчик0 Сравнить TIMER0_COMPB_vect
    12 Тайм-аут сторожевого таймера WDT_vect
    13 Начальное условие USI USI_START_vect
    USI_START_vect
    USI_START_vect USI USI USI

    Стек AVR

    Прерывания, как следует из названия, прерывают нормальный ход выполнения программы.Когда происходит прерывание, ALU вызывает соответствующий вектор прерывания и выполняет код по этому адресу. Поскольку каждый вектор прерывания имеет длину всего одно слово (классический AVR, два слова для некоторых мегабайт), вы обычно помещаете туда инструкцию перехода, которая переходит в процедуру обслуживания прерывания.

    Векторы прерывания начинаются с адреса 0x0000. Самый первый (по адресу 0x0000) — это вектор сброса. Когда происходит сброс (внутренний или внешний), здесь устанавливается счетчик программы.Поэтому почти все программы начинаются с

    .
    .org 0x0000
    rjmp reset

    ; (может быть, что-то
    ; между ними …)

    reset:

    ; сообщить ассемблеру, что следующее должно начинаться с адреса
    ; 0x0000. По адресу 0x0000 перейдите к «сбросу»
    ;
    ; сюда можно поставить другие векторы прерывания, а также любой другой код
    ;
    ;
    ; сделать это после сброса
    ;

    Другие векторы прерывания будут следовать за вектором прерывания сброса.Первые — это линии внешних прерываний (INT0, INT1 и так далее), затем есть таймеры, UART и другие периферийные устройства. В каждом техническом описании AVR есть где-то раздел «Прерывания», который будет включать список доступных прерываний и их векторные адреса. Если таблица заполнена не полностью, вы можете использовать отдельные операторы .org, чтобы установить программный счетчик ассемблера на правильный адрес вектора прерывания вместо заполнения таблицы другим бесполезным кодом. Вот два примера того же действия 8515:

    .org 0x0000
    rjmp reset
    rjmp Ext_Int0
    rjmp Ext_Int1
    reti
    reti
    reti
    reti
    reti
    reti
    rjmp UART_RxC
    ; сбросить адрес вектора (0x0000)
    ; после сброса перейти к «сбросу»
    ; адрес вектора внешнего прерывания 0 (0x0001)
    ; адрес вектора внешнего прерывания 1 (0x0002)
    ; (событие захвата таймера 1)
    ; (таймер 1 сравнивает совпадение A)
    ; (таймер 1 сравнивает совпадение B)
    ; (переполнение таймера 1)
    ; (таймер 0 переполнение)
    ; Перенос SPI завершен
    ; Прием UART Полный адрес вектора (0x0009)
    .org 0x0000
    сброс rjmp
    rjmp Ext_Int0
    rjmp Ext_Int1
    .org 0x0009
    rjmp UART_RxC
    ; сбросить адрес вектора (0x0000)
    ; после сброса перейти к «сбросу»
    ;
    ;
    ;
    ;

    Так почему же некоторые люди используют первую версию? Второй короче и, если доступно много источников прерываний (взгляните на mega128!), Лучше посмотреть, если используются только несколько.

    Первый безопаснее. Если происходит прерывание (по ошибке), для которого нет инструкции по адресу вектора сброса, будет вызвана следующая действительная команда.Поэтому, если во второй таблице по неизвестной причине происходит прерывание завершения передачи SPI, вызывается UART_RxC ISR. Фигово.

    Прерывания могут возникать в любое время (если не сброшен бит разрешения прерывания в SREG). Следовательно, они также могут возникать, если код просто выполняет некоторые вычисления. Эти вычисления изменяют флаги в регистре состояния и используются для следующего шага вычисления или некоторого перехода. Если ISR также меняет флаги в SREG (например, проверяя регистр на ноль), это может испортить вычисления, выполняемые в обычном приложении.Вот почему ISR должны предпринять некоторые меры предосторожности:

    — Сохранить регистр состояния (флаги вычислений могут быть повреждены в ISR)

    — Сохранять все используемые регистры (если они также используются в основном коде)

    Конечно, вы также можете пропустить все это, учитывая, что обеспечивается следующее:

    — ISR не меняет никаких статусных флагов

    — ISR получают специальные рабочие регистры, которые не используются в основном коде.

    ISR будет вызываться, только если установлен соответствующий бит разрешения прерывания И если установлен глобальный бит разрешения прерывания. Это дает вам возможность выбрать разрешенные прерывания. Следующая блок-схема может немного прояснить ситуацию:

    Если прерывания не нужны во время определенного сегмента кода (при выполнении критических по времени вещей или вычислений), просто отключите Бит разрешения глобального прерывания (бит GIE) в SREG.

    Когда вызывается ISR, бит GIE сбрасывается, так что никакой int не может прервать ISR.ISR должны возвращаться с reti вместо ret, поскольку reti автоматически включает бит GIE.

    Atmel AVR для начинающих 2

    Atmel AVR для начинающих 2 — Прерывания и двоичный счетчик

    В предыдущей статье про Atmel AVR мы моргали только светодиодами, без влияние событий вне микропроцессора. Все порты работали только как выходы, входа не было. Сейчас мы покажем как подключить кнопки управления к микроконтроллеру и как использовать выводы INTO и INT1 в качестве входов.Чтобы продемонстрировать это, я выбрал Atmega8 (вы можете также используйте более новый Atmega8A). Кнопки подключены к контактам 4 и 5, которые являются битами 3 и 4 порта D, но также имеют альтернативную функцию — INT0 и INT1. Эти альтернативные функции в наших интересах. Они являются внешними источниками прерываний. Если эти прерывания разрешены, вы можете использовать эти входы для запуска обработчика прерывания. Прерывание INT1 разрешается с помощью самого старшего бита в регистре GICR. Прерывание INT0 разрешается с помощью второго старшего бита.Разрешение обоих прерываний мы делаем, устанавливая два старших бита GICR в 1:

    LDI REG, 0b11000000
    ВЫХОДИТ GICR, REG
     

    Затем нам нужно выбрать, что будет вызывать прерывание — чувствительность прерывания. Это делается с помощью регистратора MCUCR. Чувствительность INT0 выбирается комбинацией двух битов — ISC01 и ISC00. Чувствительность INT1 выбирается битами ISC10 и ISC11. В нашем примере нам нужна чувствительность к заднему фронту, поэтому для каждой пары установлено значение 1 0.Сделать это можно так:

    LDI REG, 0b00001010
    ВЫХОД MCUCR, REG
     

    Положение битов в регистрах GICR и MCUCR показывает таблица:

    Значение пар битов ISC01 и ISC00 или ISC10 и ISC11 в реестре MCUCR, устанавливающее чувствительность входов:
    0 0 … логический 0 запускает прерывание
    0 1 … любое логическое изменение запускает прерывание
    1 0 … задний фронт запускает прерывание
    1 1 … нарастающий фронт запускает прерывание

    Теперь нажатие кнопки запускает соответствующий обработчик прерывания. В нашем примере это увеличение / уменьшение рабочего регистра. REG, а затем отправляет свое состояние на выходе, который является портом C — его первые 6 бит. Его состояние отображается 6 светодиодами. Теперь, когда вы построили двоичный счетчик, вы можете нажать одну кнопку, чтобы добавить 1, и вторую кнопку, чтобы вычесть 1. Принципиальную схему этой экспериментальной схемы вы можете увидеть ниже.Это видео внизу страницы демонстрирует эту функцию. Конечно, вы можете найти много других вещей, для которых можно использовать кнопки :). Если прерывание не выполняется, программа выполняет бесконечный цикл (в коде курса он называется SMYCKA). В цикле ничего нет, но можно что-то добавить. Программа доступна для скачивания ниже.
    Вся программа для скачивания:
    Двоичный счетчик с прерываниями — исходный код на ассемблере (ASM)
    Двоичный счетчик с прерываниями — скомпилированный HEX файл


    Схема экспериментальной схемы ATmega8.Позволяет как программировать, так и тестировать.


    Схема тестирования в макете


    Видео — демонстрация работоспособности схемы.



    Предупреждение для лам:
    Предупреждение! Неправильное подключение может повредить микропроцессор, порт LPT или весь ПК.

    Предыдущая статья про АВР
    дом

    прерываний в Atmega16-AVR %%

    Введение

    Прерывание — это еще один метод программирования микроконтроллера.В методе прерывания микроконтроллер прерывается подключенным к нему устройством. После прерывания он будет запускать фрагмент кода, написанный для определенного прерывания, который называется Interrupt Service Routine (ISR). Как только он завершит выполнение, он возобновит операцию с того места, где она была прервана.

    Типы прерываний

    Всего в Atmega16 семейства AVR имеется 21 прерывание, которые можно разделить на два основных типа — внешнее и внутреннее прерывание.Как следует из названия, внешних прерываний запускаются аппаратными средствами (внешними устройствами). В то время как внутренних прерываний, запускаются событиями, происходящими в самой программе. Прерывание от таймера, последовательные прерывания, прерывание от АЦП (аналого-цифровые преобразователи) и т. Д. Являются примерами внутренних прерываний в Atmega16.

    Внешние прерывания

    В Atmega16 есть четыре контакта, которые назначены для обработки прерываний от внешних источников.Это PIND0 (PIN16), PIND1 (PIN17), PINB2 (PIN3) и СБРОС (PIN9). Из этих прерываний вывод RESET немаскируется. Это означает, что остальные прерывания могут быть активированы или деактивированы вами ( маскируется, ), но если прерывание RESET запускается, микроконтроллер должен его выполнить. По сути, прерывание RESET сбрасывает программу, загруженную в микроконтроллер.

    Внутренние прерывания

    В Atmega16 17 внутренних прерываний.Эти прерывания поддерживают различные операции микроконтроллера, включая аналого-цифровой преобразователь (АЦП), прерывания по таймеру, последовательные прерывания и т. Д. Мы обсудим каждое прерывание в следующих статьях.

    События происходят во время прерывания

    Какие события происходят при срабатывании прерывания?

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

    Общий метод программирования с использованием прерывания

    Я хочу обсудить общие шаги по программированию с использованием метода прерывания. Это упрощает понимание процесса программирования каждого прерывания.

    • Мы собираемся найти подходящий регистр, который управляет конкретным прерыванием.
    • Затем мы устанавливаем конкретный бит регистра в высокий или низкий уровень в соответствии с необходимостью разрешить или запретить конкретное прерывание.
    • Мы также должны установить «Регистр флагов» для конкретного прерывания.
    • Напишите программу обслуживания прерывания для конкретного прерывания.

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

    Ну вот и все. Если вам понравилась эта статья, подпишитесь на нас, чтобы не пропустить обновления.Увидимся в следующий раз.

    Связанное сообщение

    Опрос против прерывания

    Связанный

    Arduino / ATmega328p — Арнаб Кумар Дас

    Примечание

    Эта статья является частью Руководства по программированию встроенного ПО на C для Arduino / ATmega328p. Попробуйте изучить домашнюю страницу курса, чтобы найти статьи на похожие темы.

    Учебное пособие по Arduino Встроенный уровень регистра C Мастер-класс Arduino

    Также посетите страницу выпуска для встроенной библиотеки аппаратной абстракции C на уровне регистров и код для AVR .

    Введение

    В этом разделе описаны особенности обработки прерываний, выполняемой в ATmega328P. Также обсуждаются векторы прерывания, доступные в микросхеме, и способы их использования.

    Что вы узнаете

    • Как Iterrupts работают в Arduino?
    • Как работают прерывания процессора микросхемы AVR ATmega328p?
    • Каковы различные источники прерываний в ATmega328p?
    • В чем разница между внутренними и внешними прерываниями в ATmega328p?
    • Как прерывания включаются или отключаются в Arduino / ATmega328p?

    Векторы прерывания ATmega328P

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

    Каждый вектор прерывания занимает два командных слова в ATmega328 / 328P. Этот список определяет уровни приоритета различных прерываний. Чем ниже адрес, тем выше уровень приоритета.Самые низкие адреса в области памяти программ по умолчанию определены как векторы сброса и прерывания.

    7 900 909 Передача USART USART
    Номер вектора Программа
    Адрес
    Источник Определение прерывания
    1 0x0000 RES, внешний вывод питания Отключение, сброс системы сторожевого таймера
    2 0x0002 INT0 Запрос внешнего прерывания 0
    3 0x0004 INT1 Запрос внешнего прерывания 1
    4 PCINT0 Запрос прерывания смены контакта 0
    5 0x0008 PCINT1 Запрос прерывания смены контакта 1
    6 0x000A PCINT2 Запрос прерывания смены контакта 2 0x000C WDT Тайм-аут сторожевого таймера Inte rrupt
    8 0x000E TIMER2 COMPA Timer / Counter2 Compare Match A
    9 0x0010 TIMER2 COMPB Таймер / Counter2 Сравнить Match B
    TIMER2 OVF Переполнение таймера / счетчика2
    11 0x0014 TIMER1 CAPT Таймер / счетчик1 захват события
    12 0x0016
    12 0x0016 TIMER1 COMPA Время
    13 0x0018 TIMER1 COMPB Таймер / Coutner1 Сравнить Соответствие B
    14 0x001A TIMER1 OVF Таймер / счетчик1 Переполнение
    0
    0 900 Таймер / счетчик 0 Сравнить совпадение A
    16 0x001E TIMER0 COMPB Таймер / счетчик0 Сравнить соответствие B
    17 0x0020 TIMER0 OVF Таймер / счетчик0 Переполнение
    18 0x0022 SPI SPI, STC
    19 0x0024 USART, RX USART Rx Complete
    20 0x0026 USART, UDRE USART, регистр данных пустой
    21 0x0028 USART, Tx Complete
    22 0x002A ADC Преобразование ADC завершено
    23 0x002C EE READY EEPROM Ready
    Аналоговый компаратор
    25 0x0030 TWI 2-проводный последовательный интерфейс
    26 0x0032 SPM READY Сохранение памяти программ готово

    При возникновении прерывания I-бит разрешения глобального прерывания сбрасывается, и все прерывания блокируются.Программное обеспечение пользователя может записать логическую единицу в I-бит, чтобы разрешить вложенные прерывания. Все разрешенные прерывания могут затем прервать текущую программу обработки прерываний. Бит I устанавливается автоматически при выполнении инструкции возврата из прерывания — RETI. Когда AVR выходит из прерывания, он всегда возвращается в основную программу и выполняет еще одну инструкцию, прежде чем будет обработано любое ожидающее прерывание.

    Ответ выполнения прерывания для всех разрешенных прерываний AVR составляет минимум четыре тактовых цикла.После четырех тактов выполняется адрес программного вектора для действительной процедуры обработки прерывания. В течение этого периода, равного четырем тактам, Программный счетчик помещается в стек. Вектор обычно представляет собой переход к программе обработки прерывания, и этот переход занимает три тактовых цикла. Если прерывание происходит во время выполнения многоцикловой инструкции, эта инструкция завершается до того, как прерывание будет обработано. Если прерывание происходит, когда MCU находится в спящем режиме, время отклика на выполнение прерывания увеличивается на четыре тактовых цикла.Это увеличение происходит в дополнение ко времени запуска из выбранного спящего режима.

    Для возврата из подпрограммы обработки прерывания требуется четыре тактовых цикла. В течение этих четырех тактов Программный счетчик (два байта) извлекается из стека, указатель стека увеличивается на два и устанавливается бит I в SREG.

    Если программа никогда не разрешает источник прерывания, векторы прерывания не используются, и в эти места можно поместить обычные программные коды. Это также имеет место, если вектор сброса находится в разделе приложения, а векторы прерывания находятся в разделе загрузки, или наоборот.

    + 0x0001222 900
    MCUCR — Регистр управления MCU

    Регистр управления MCU управляет размещением таблицы векторов прерываний.

    BOOTRST IVSEL Адрес сброса Начальный адрес векторов прерывания
    1 0 1 0 1 0 0x000 Адрес сброса загрузки + 0x0002
    0 0 Адрес сброса загрузки 0x002
    0 1 Адрес сброса загрузки Адрес сброса загрузки
    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R
    0
    R / W 0 R / W
    0
    R / W
    0
    R
    0
    R
    0
    R / W
    0
    R / W
    0
    0x35 (0x55) КОРПУС КОРПУС PUD IVSEL IVCE
    • Бит 1 — IVSEL: выбор вектора прерывания
      Когда бит IVSEL сброшен (ноль), векторы прерывания помещаются в начало флэш-памяти.Когда этот бит установлен (единица), векторы прерывания перемещаются в начало раздела загрузчика Flash.
    • Бит 0 — IVCE: разрешение изменения вектора прерывания
      Бит IVCE должен быть записан в логическую единицу, чтобы разрешить изменение бита IVSEL. IVCE очищается аппаратно через четыре цикла после записи или при записи IVSEL.

    Внешние прерывания ATmega328P

    Распиновка корпуса Atmega328p DIP Dual Inline

    Внешние прерывания запускаются выводами INT0 и INT1 или любым из выводов PCINT23… 0.Прерывания будут срабатывать, даже если выводы INT0 и INT1 или PCINT23… 0 сконфигурированы как выходы. Эта функция обеспечивает способ создания программного прерывания. Прерывание смены вывода PCI2 сработает, если переключится любой активированный вывод PCINT [23:16]. Прерывание смены вывода PCI1 сработает, если переключится любой активированный вывод PCINT [14: 8]. Прерывание смены вывода PCI0 сработает, если переключится любой активированный вывод PCINT [7: 0]. Регистры PCMSK2, PCMSK1 и PCMSK0 управляют тем, какие выводы участвуют в прерываниях смены выводов.Прерывания по смене вывода на PCINT23… 0 обнаруживаются асинхронно. Это означает, что эти прерывания могут использоваться для пробуждения части также из спящих режимов, отличных от режима ожидания.

    Прерывания INT0 и INT1 могут быть вызваны спадающим или нарастающим фронтом или низким уровнем. Это настроено, как указано в спецификации для регистра управления внешним прерыванием A — EICRA. Когда прерывания INT0 или INT1 разрешены и настроены как запускаемые по уровню, прерывания будут срабатывать до тех пор, пока на выводе будет оставаться низкий уровень.Обратите внимание, что для распознавания прерываний по падающему или нарастающему фронту на INT0 или INT1 требуется наличие тактовых импульсов ввода-вывода.

    Сроки прерывания смены вывода в AVR
    EICRA — Регистр управления внешним прерыванием A

    Регистр управления внешним прерыванием A содержит биты управления для управления распознаванием прерывания.

    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R
    0
    R
    R
    0
    R
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    0x35 (0x55) ISC11 ISC10 ISC01 ISC00
    • Бит 7: 4 — Зарезервирован
      Не используется и всегда читается как ноль
    • Бит 3, 2 — ISC11, ISC10: Управление распознаванием прерывания 1, бит 1 и бит 0
      Внешнее прерывание 1 активируется внешним вывод INT1, если установлены I-флаг SREG и соответствующая маска прерывания.Значение на выводе INT1 выбирается до обнаружения фронтов. Если выбрано прерывание по фронту или переключение, импульсы, длящиеся дольше одного тактового периода, будут генерировать прерывание. Более короткие импульсы не гарантируют создания прерывания. Если выбрано прерывание низкого уровня, низкий уровень должен удерживаться до завершения выполняемой в данный момент инструкции, чтобы сгенерировать прерывание.
    • Бит 1, 0 — ISC01, ISC00: Управление распознаванием прерывания 0 Бит 1 и бит 0
      Внешнее прерывание 0 активируется внешним выводом INT0, если установлены флаг SREG I и соответствующая маска прерывания.Значение на выводе INT0 выбирается до обнаружения фронтов. Если выбрано прерывание по фронту или переключение, импульсы, длящиеся дольше одного тактового периода, будут генерировать прерывание. Более короткие импульсы не гарантируют создания прерывания. Если выбрано прерывание низкого уровня, низкий уровень должен удерживаться до завершения выполняемой в данный момент инструкции, чтобы сгенерировать прерывание.
    ISC11 ISC10 Описание
    0 0 Низкий уровень INT1 генерирует запрос прерывания.
    0 1 Любое логическое изменение на INT1 генерирует запрос прерывания.
    1 0 Спад INT1 генерирует запрос прерывания.
    1 1 Нарастающий фронт INT1 генерирует запрос прерывания
    ISC01 ISC00 Описание
    0 0 Низкий уровень INT0 генерирует запрос прерывания.
    0 1 Любое логическое изменение на INT0 генерирует запрос прерывания.
    1 0 Спад INT0 генерирует запрос прерывания.
    1 1 Нарастающий фронт INT0 генерирует запрос прерывания
    EIMSK — регистр маски внешнего прерывания

    Регистр маски внешнего прерывания содержит разрешающие или запрещающие прерывания INT1 и INT0.

    909
    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R
    0
    R
    R
    0
    R
    0
    R
    0
    R
    0
    R / W
    0
    R / W
    0
    0x1D (0x3D) INT1 INT0
    • Бит 7: 2 — Зарезервирован
      Эти биты являются неиспользуемыми битами и всегда читаются как ноль.
    • Бит 1 — INT1: разрешение запроса 1 внешнего прерывания
      Когда бит INT1 установлен (единица), а I-бит в регистре состояния (SREG) установлен (единица), прерывание по внешнему контакту разрешено.
    • Бит 0 — INT0: Разрешение запроса внешнего прерывания 0
      Когда бит INT0 установлен (единица), а I-бит в регистре состояния (SREG) установлен (единица), прерывание по внешнему контакту разрешено.
    EIFR — Регистр флага внешнего прерывания

    Регистр флага внешнего прерывания содержит флаг INTF1 и INTF0.

    909
    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R
    0
    R
    R
    0
    R
    0
    R
    0
    R
    0
    R / W
    0
    R / W
    0
    0x1C (0x3C) INTF1 INTF0
    • Бит 7: 2 — Зарезервирован
      Эти биты являются неиспользуемыми битами и всегда читаются как ноль.
    • Бит 1 — INTF1: Флаг внешнего прерывания 1
      Когда изменение фронта или логики на выводе INT1 запускает запрос прерывания, INTF1 устанавливается (единица). Если бит I в SREG и бит INT1 в EIMSK установлены (единица), MCU перейдет к соответствующему вектору прерывания. Флаг сбрасывается при выполнении подпрограммы прерывания. Как вариант, флаг можно сбросить, записав в него логическую единицу. Этот флаг всегда сбрасывается, если INT1 настроен как прерывание по уровню.
    • Бит 0 — INTF0: Флаг внешнего прерывания 0
      Когда изменение фронта или логики на выводе INT0 запускает запрос прерывания, INTF0 устанавливается (единица).Если бит I в SREG и бит INT0 в EIMSK установлены (единица), MCU перейдет к соответствующему вектору прерывания. Флаг сбрасывается при выполнении подпрограммы прерывания. Как вариант, флаг можно сбросить, записав в него логическую единицу. Этот флаг всегда сбрасывается, если INT0 настроен как прерывание по уровню.
    PCICR — Регистр управления прерыванием смены вывода

    Регистр управления прерыванием смены контакта включает или отключает PCI1, PCI2, PCI3.

    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R
    0
    R
    R
    0
    R
    0
    R
    0
    R / W
    0
    R / W
    0
    R / W
    0
    (0x68) PCIE2 PCIE1 PCIE0
    • Бит 7: 3 — Зарезервирован
      Эти биты являются неиспользуемыми битами и всегда читаются как ноль.
    • Бит 2 — PCIE2: Разрешение прерывания при смене вывода 2
      Когда бит PCIE2 установлен (единица) и установлен бит I в регистре состояния (SREG) (единица), разрешается прерывание 2 при смене вывода. Любое изменение на любом активированном выводе PCINT [23:16] вызовет прерывание. Соответствующее прерывание запроса прерывания смены вывода выполняется из вектора прерывания PCI2. Контакты PCINT [23:16] активируются индивидуально регистром PCMSK2.
    • Бит 1 — PCIE1: Разрешение прерывания при смене вывода 1
      Когда бит PCIE0 установлен (единица) и установлен бит I в регистре состояния (SREG) (единица), разрешается прерывание 0 при смене вывода.Любое изменение на любом активированном выводе PCINT [7: 0] вызовет прерывание. Соответствующее прерывание запроса прерывания смены вывода выполняется из вектора прерывания PCI0. Контакты PCINT [7: 0] активируются индивидуально регистром PCMSK0.
    PCIFR — Регистр флага прерывания смены вывода

    Регистр флага прерывания смены вывода содержит флаги PCIF1, PCIF2, PCIF3.

    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R
    0
    R
    R
    0
    R
    0
    R
    0
    R / W
    0
    R / W
    0
    R / W
    0
    0x1B (0x3B) PCIE2 PCIE1 PCIE0
    • Бит 7: 3 — Зарезервирован
      Эти биты являются неиспользуемыми битами и всегда читаются как ноль.
    • Бит 2 — PCIF2: Флаг прерывания 2 при смене вывода
      Когда изменение логики на любом выводе PCINT [23:16] вызывает запрос прерывания, устанавливается PCIF2 (единица). Если бит I в SREG и бит PCIE2 в PCICR установлены (единица), MCU перейдет к соответствующему вектору прерывания. Флаг сбрасывается при выполнении подпрограммы прерывания. Как вариант, флаг можно сбросить, записав в него логическую единицу.
    • Бит 1 — PCIF1: Флаг прерывания при смене вывода 1
      Когда изменение логики на любом выводе PCINT [14: 8] запускает запрос прерывания, устанавливается PCIF1 (единица).Если бит I в SREG и бит PCIE1 в PCICR установлены (единица), MCU перейдет к соответствующему вектору прерывания. Флаг сбрасывается при выполнении подпрограммы прерывания. Как вариант, флаг можно сбросить, записав в него логическую единицу.
    PCMSK2 — Регистр маски изменения вывода 2
    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    ( 0x6D) PCINT23 PCINT22 PCINT21 PCINT20 PCINT19 PCINT18 PCINT17 PCINT16
    • Бит 7: 0 — PCINT [23:16]: маска разрешения смены вывода 23… 16
      Каждый бит PCINT [23:16] определяет, разрешено ли прерывание смены вывода на соответствующем выводе ввода-вывода.Если установлен PCINT [23:16] и установлен бит PCIE2 в PCICR, прерывание смены вывода разрешается на соответствующем выводе ввода / вывода. Если PCINT [23:16] сброшен, прерывание смены вывода на соответствующем выводе ввода-вывода отключено.
    PCMSK1 — Регистр маски изменения вывода 1
    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    ( 0x6C) PCINT14 PCINT13 PCINT12 PCINT11 PCINT10 PCINT9 PCINT8
    • Бит 6: 0 — PCINT [14: 8]: маска разрешения смены вывода 14… 8
      Каждый бит PCINT [14: 8] определяет, разрешено ли прерывание при смене вывода на соответствующем выводе ввода / вывода.Если установлен PCINT [14: 8] и установлен бит PCIE1 в PCICR, прерывание смены вывода разрешается на соответствующем выводе ввода / вывода. Если PCINT [14: 8] очищен, прерывание смены вывода на соответствующем выводе ввода / вывода отключено.
    PCMSK0 — Регистр маски изменения вывода 0
    Бит 7 6 5 4 3 2 1 0
    Чтение / запись
    Начальное значение
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    R / W
    0
    ( 0x6B) PCINT7 PCINT6 PCINT5 PCINT4 PCINT3 PCINT2 PCINT1 PCINT0
    • Бит 6: 0 — PCINT [7: 0]: Маска разрешения смены вывода 7… 0
      Каждый бит PCINT [7: 0] определяет, разрешено ли прерывание смены вывода на соответствующем выводе ввода / вывода.Если установлен PCINT [7: 0] и установлен бит PCIE0 в PCICR, прерывание смены вывода разрешается на соответствующем выводе ввода / вывода. Если PCINT [7: 0] очищен, прерывание смены вывода на соответствующем выводе ввода-вывода отключено.
    Микроконтроллер

    — как использовать процедуру обслуживания прерывания без файла interrupt.h в avr? Микроконтроллер

    — как использовать процедуру обслуживания прерывания без файла interrupt.h в avr? — Обмен электротехнического стека
    Сеть обмена стеков

    Сеть Stack Exchange состоит из 178 сообществ вопросов и ответов, включая Stack Overflow, крупнейшее и пользующееся наибольшим доверием онлайн-сообщество, где разработчики могут учиться, делиться своими знаниями и строить свою карьеру.

    Посетить Stack Exchange
    1. 0
    2. +0
    3. Авторизоваться Зарегистрироваться

    Electrical Engineering Stack Exchange — это сайт вопросов и ответов для профессионалов в области электроники и электротехники, студентов и энтузиастов.Регистрация займет всего минуту.

    Зарегистрируйтесь, чтобы присоединиться к этому сообществу

    Кто угодно может задать вопрос

    Кто угодно может ответить

    Лучшие ответы голосуются и поднимаются наверх

    Спросил

    Просмотрено 653 раза

    \ $ \ begingroup \ $

    Хотите улучшить этот вопрос? Добавьте подробности и проясните проблему, отредактировав этот пост.

    Закрыт 5 лет назад.

    В микроконтроллере avr, при использовании процедуры обслуживания прерывания, вы пишете функцию:

      ISR (Int_Vect) {
    
    }
      

    Чтобы использовать эту функцию, вы должны включить . Итак, теперь я не хочу использовать файл interrupt.h, потому что я пытаюсь написать свой драйвер. как использовать процедуру обслуживания прерывания без файла interrupt.h?

    Создан 06 окт.

    Ахмед ЯсенАхмед Ясен

    4722 серебряных знака88 бронзовых знаков

    \ $ \ endgroup \ $ 6 \ $ \ begingroup \ $

    ср / прерывание.h на самом деле довольно прост в том, что касается заголовков прерываний. Просматривая его, я не вижу ничего, что вам не нужно было бы хранить, чтобы прерывания работали. Постороннего пуха очень мало. Было бы полезно потратить время на то, чтобы добраться до того, где можно понять interrupt.h, прежде чем вы попытаетесь написать свою собственную замену для него. Я бы сказал, что если вы посмотрите на макросы определения, которые вам нужны (т.е. не смотрите на ISR_ALIAS , если вам не нужно использовать псевдонимы ISR). Я бы сказал, что 90-100% из тех частей, которые вы рассматриваете, необходимы для обработки прерываний.Единственное, что может быть необязательным, — это то, что вы можете избежать использования вариативных макросов и __VA_ARGS__ , если вы готовы переписывать этот код каждый раз, а не использовать макрос.

    Прерывания очень зависят от компилятора и процессора. Вы можете посмотреть в своем руководстве по процессору, чтобы точно определить, в какие части памяти записывать, чтобы разрешить прерывания, а затем вы можете заставить свой драйвер делать это. Однако вам придется использовать все флаги, которые вызывают прерывание.h добавляет ваши функции, чтобы убедиться, что они совместимы с вызовом в качестве прерывания (или напишите свой собственный обработчик прерывания в сборке).