- •I справочный материал ц
- •Подразумевается, что читатель знаком с показательной формой записи действи- етльных чисел.
- •Int a[5]; // массив a[] из 5-и элементов типа int
- •Int a1, a2, a3, a4, a5; // 5 отдельных переменных типа int
- •Void boot_program_page (uint32_t page, uint8_t *buf){
- •Int main(void){
- •Isr_noblock
- •Isr_naked
- •Isr_alias()
- •Isr_aliasof()
- •Isr_block
Врезка. Пример
использования.
#include
<avr/io.h> FUSES ={
low
= LFUSE_DEFAULT,
• high
= (FUSE_BOOTSZ0 & FUSE_EESAVE
& FUSE_SPIEN &
FUSE_JTAGEN),
extended
= EFUSE_DEFAULT, };
return
0; }
34 Т.к.
fuse-биты отличаются в
зависимости от модели микроконтроллера,
следует ознакомиться с их наименованием
по соответствующей документации к
выбранному контроллеру; в настоящей
документации они не приводятся.
Int main(void){
программе функции, названной в соответствии с определенными соглашениями, приводит к тому, что компилятор генерирует для нее нестандартный код пролога и эпилога, в частности, обязательно сохраняет SREG в начале и восстанавливает в конце, а так же использует для возврата из функции команду RETI. Кроме того, в таблице векторов прерываний для каждой определенной пользователем функции-обработчика помещается команда перехода к соответствующей функции.
Далее кратко перечислены основные характерные особенности реализации обработчиков прерываний WinAVR. Подробности следует искать в описаниях соответствующих макросов.
Детали реализации этого подхода остаются за кадром, т.к. программисту достаточно определить при помощи макроса ISR() функцию - и она будет назначена (и соответственно оформлена) обработчиком определенного прерывания.
Особенность аппаратного строения AVR заключается в том, что во время работы одного обработчика прерываний все прочие прерывания запрещены. Такая ситуация в некоторых случаях может быть нежелательной, для чего можно (естественно, осознавая последствия, к которым это может привести) разрешить прерывания принудительно внутри функции-обработчика, используя макрос sei(). Но можно поступить и проще, указав для макроса ISR() параметр ISR_NOBLOCK, что заставит компилятор поместить соответствующую инструкцию глобального разрешения прерываний сразу после пролога функции (т.е. инициализирующего участка кода).
При разработке программ не исключена ситуация, когда случайно будет сгенерировано прерывание, для которого нет назначенного обработчика (ситуация «баг программы»). По умолчанию компилятор генерирует код, который в этом случае приведет к переходу на адрес 0х0000, т.е. поведение кода равносильно сбросу микроконтроллера. Однако такое поведение можно изменить, определив особый обработчик «неверного прерывания», который автоматически назначается все «незанятым» векторам прерываний. Делается это при помощи указания для ISR() «плохого» вектора BADISR_vect. Такой обработчик будет использован для всех векторов прерываний, для которых не указаны явно их обработчики.
Так же часто может возникать ситуация, когда один и тот же обработчик должен использоваться для нескольких прерываний. Можно, конечно, определить несколько абсолютно идентичных функций, однако, можно и сэкономить память, указав для ISR() параметр ISR_ALIASOF().
Еще одной занимательной ситуацией, связанной с прерываниями, является пробуждение микроконтроллера по прерыванию из «спящего» режима. В этом случае обработчик прерывания вызывается, однако, часто в нем никаких полезных действий выполняться не должно. Для таких случаев предусмотрен макрос EMPTY_INTERRUPT(), позволяющий определить обработчик, который не делает ничего.
Наконец, во многих случаях может оказаться, что неизбежно генерируемый компилятором для обработчика прерывания код пролога и эпилога оказывается слишком велик. Было бы удобно в таком случае использовать обработчик, реализованный на ассемблере, либо попытаться обойтись средствами Си для получения более оптимального кода. Сделать это можно при помощи параметра ISR_NAKED, указываемого для ISR(). В этом случае компилятор не генерирует вообще никакого пролога и эпилога, поэтому программист сам должен обеспечить сохранение контекста программы (в частности, содержимого SREG), и, главное, использовать макрос reti() для выхода из обработчика.
Для каждого микроконтроллера определены свои константы для указания соответствующего вектора прерывания. Эти константы содержат в своем составе суффиктс _vect. Для совместимости с предыдущими версиями WinAVR сохранена и возможность определять обработчик прерывания при помощи «сигналов», т.е. констант, имеющих «префикс» SIG_ (префиксы и суффиксы соответствующих векторов определены в заголовочных файлах для каждого типа микроконтроллеров). Рекомендуется использовать «новую» форму _vect.
Макросы и определения
sei()
sei() - глобальное разрешение прерываний
cli()
cli() - глобальное запрещение прерываний
reti()
reti() - макрос принудительно помещает в код программы инструкцию RETI, обеспечивая возврат из прерывания.
ISR()
ISR(vector, attributes) - макрос для определения обработчика прерываний.
Врезка ISR_ALIAS
//
определяем обработчик внешнего запроса
прерывания №0 ISR(INT0_vect){
PORTB
= 42; }
//
назначаем этот обработчик и для запроса
№1 ISR_ALIAS(INT1_vect, INT0_vect);
Врезка
ISR_ALIASOF
//
определяем обработчик внешнего запроса
прерывания №0 и одновременно №1
ISR(INT0_vect, ISR_ALIASOF(INT1_vect)){
PORTB
= 42; }
Второй параметр attributes - необязательный, определяет опциональные варианты реализации соответствующего обработчика. Допустимо использовать несколько атрибутов из числа следующих (атрибуты разделяются запятыми):
ISR_BLOCK - атрибут по умолчанию, означает запрет прерываний, пока не отработает текущий обработчик
ISR_NOBLOCK - разрешает глобально прерывания сразу после пролога обработчика
ISR_NAKED - указывает, что вся реализация кода обработчика делается программистом (нет никакого пролога и эпилога)
ISR_ALIASOF(v) - позволяет назначить текущему обработчику несколько векторов (см. врезку для ISR_ALIASOF).
SIGNAL()
SIGNAL(vector) - макрос определения обработчика, сохраненный исключительно для совместимости со старым кодом. Не рекомендуется использование в новых разработках. В качестве параметра vector должен получать константу с префиксом SIG_ из заголовочного файла конкретного микроконтроллера (например, SIG_ADC).
EMPTY_INTERRUPT()
EMPTY_INTERRUPT(vector) - макрос определения «пустого» обработчика, т.е. состоящего только из команды RETI. В качестве параметра принимаются те же значения, что и для ISR().
