Четверг, 25.04.2024, 06:34
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Меню сайта
Реклама Google
Форма входа
Категории раздела
Это нужно знать! [17]
Изучаем AVR [30]
Программаторы [12]
Необходимое ПО [8]
Готовые устройства [73]
Справочная [38]
Инструмент [0]
Технология [8]
Литература [0]
Arduino скетчи [18]
Поиск
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Микроконтроллеры - это просто!
Главная » Статьи » Изучаем AVR

Обработка прерываний
AVR по умолчанию ожидает, что сразу после первой команды с адресом $0000 идет таблица т. н. векторов прерываний. Вектор — это просто отсылка по нужному адресу с помощью команды rjmp. Вообще-то вектор по нулевому адресу, на который программа переходит по сбросу (вектор сброса или вектор начальной загрузки), тоже считается прерыванием, хотя оно занимает особое место.

Адрес обозначается меткой, может располагаться в любом месте программы и содержит начало процедуры обработки прерывания. Первый вектор располагается по адресу $0001 (а для МК с памятью более 8 К — по адресу $0002, потому что по адресу $0001 находится вторая половина более длинной команды jmp), причем напомним, что для памяти программ адрес этот означает номер двухбайтового слова в памяти, а не отдельного байта. На самом деле по умолчанию нам вообще не нужно думать про абсолютные адреса и их нумерацию — первая команда программы (rjmp reset) автоматически расположится по нулевому адресу, вторая — по адресу $0001 и т. д. Найдя какую- нибудь команду перехода по метке, компилятор автоматически подставит абсолютные адреса. Нужно только быть внимательным при выборе модели: если вы подставите для МК ATmega8 в таблицу прерываний jmp вместо rjmp (а для ATmega16 и старше наоборот), то сброс у вас пройдет нормально, а вот все остальные прерывания выполняться не будут — скорее всего, программа просто "повиснет".

Порядок следования векторов и их число в таблице жестко заданы в соответствии с типом МК. Потому самое первое, что вы должны сделать, приступая к программированию, — открыть руководство по применению выбранного типа контроллеров и скопировать оттуда эту таблицу. Можно прямо через буфер обмена из PDF-описания (если вам позволят это сделать — в последних версиях описаний копирование текста через буфер обычно запрещено, что не делает чести менеджменту Atmel, но всегда можно вывернуться с помощью программ, удаляющих ограничения PDF, таких как Foxit Reader или платный Advanced PDF Password Recovery). Так меньше вероятность что-то пропустить, только придется потом удалить указанные там абсолютные адреса, стоящие в начале каждой строки. Начало программы для МК ATmega8.

Листинг
;=========прерывания================
гjmp RESET ; Reset Handler
rjmp EXT_INT0 ; IRQ0 Handler
rjmp EXT_INT1 ; IRQ1 Handler
rjmp TIM2_COMP ; Timer2 Compare Handler
rjmp TIM2_OVF ; Timer2 Overflow Handler
rjmp TIM1_CAPT ; Timer1 Capture Handler
rjmp TIM1_COMPA ; Timer1 CompareA Handler
rjmp TIM1_COMPB ; Timer1 CompareB Handler
rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
rjmp SPI_STC ; SPI Transfer Complete Handler
rjmp USART_RXC ; USART RX Complete Handler
rjmp USART_UDRE ; UDR Empty Handler
rjmp USART_TXC ; USART TX Complete Handler
rjmp ADC ; ADC Conversion Complete Handler
rjmp EE_RDY ; EEPROM Ready Handler
rjmp ANA_COMP ; Analog Comparator Handler
rjmp TWSI ; Two-wire Serial Interface Handler
rjmp SPM_RDY ; Store Program Memory Ready Handler
;==================================

Но постойте: мы что, обязаны использовать все прерывания? Конечно, нет. Для неиспользуемых прерываний в контроллерах с памятью программ менее 16 кбайт команду rjmp [метка] следует заменить на reti — выход из прерывания ("return interrupt"). На самом деле можно было бы указать и команду nop — пустую операцию. Мы будем ставить именно reti, т. к. тогда нам неважно — если прерывание случайно инициализировано, оно все равно не будет выполняться, а писать и отлаживать программы так удобнее. Я в своих программах просто дополняю стандартные строки командой reti и точкой с запятой, чтобы закомментировать команду rjmp.

Листинг

.include "m8def.inc"
. . . . . . . . . . .
.def temp = r16 ;рабочая переменная
rjmp RESET ; Reset Handler 
reti ;rjmp EXT_INT0 ;IRQ0 Handler 
reti ;rjmp EXT_INTl ;IRQ1 Handler
. . . . . . . . . . .

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

Листинг 
rjmp RESET ;Reset Handler 
rjmp EXT_INT0 ;IRQ0 Handler
. . . . . . . . . . .
EXT_INT0: ;процедура обработки прерывания INT0 
. . . . . . . . . . .

reti ;окончание процедуры обработки прерывания INT0
Есть и более короткий способ оформления таблицы векторов прерываний (он особенно актуален для старших Mega, где число прерываний может достигать нескольких десятков, а из-за четырехбайтового формата команды jmp заменить ее на reti просто так не получается). Способ основан на использовании директивы org, которая устанавливает абсолютный адрес в памяти программ. В inc-файлах есть специальные определения констант для адресов прерываний, например (из файла 8515def.inc):

.equ INT0addr=$001; External Interrupt0 Vector Address
. . . . . . . . . . .
.equ URXCaddr=$009; UART Receive Complete Interrupt Vector Address
.equ UDREaddr=$00a; UART Data Register Empty Interrupt Vector Address
.equ UTXCaddr=$00b; UART Transmit Complete Interrupt Vector Address
. . . . . . . . . . .

Тогда, если вам, к примеру, никакие иные прерывания не требуются, кроме прерываний URXC и UDRE для UART.

Листинг 
;Установка векторов прерываний 
.org 0 ;начало программы после сброса
rjmp RESET
.org UDREaddr ;адрес прерывания UDRE 
rjmp TransUART
.org URXCaddr ;адрес прерывания URXC 
rjmp ReceiveUART
.org $0D ;только для 8515 Classic
. . . . . . . . . . .
[программа]
. . . . . . . . . . .

Здесь TransUART и ReceiveUART — процедуры, которые выполняются при возникновении соответствующих прерываний. Обратите внимание на то, что при смене модели здесь не требуется что-либо исправлять (при условии, конечно, что новая модель будет поддерживать такие же прерывания), за исключением строки .org $0D. В модели 8515 всего 12 прерываний + сброс, а объем памяти 8 кбайт, поэтому таблица прерываний занимает 13 двухбайтовых ячеек, и программа может начинаться с ячейки номер $0D. В других моделях это обязательно будет другое число, т. к. количество прерываний отличается, причем для моделей с объемом памяти программ меньше или равной 8 кбайт к адресу последнего прерывания нужно добавить единицу, а в моделях с объемом памяти более 8 кбайт — двойку.

Если вы боитесь ошибиться, то более-менее универсальный метод заключается в том, чтобы пренебречь потерями пространства памяти и всегда начинать программу с адреса, заведомо большего следующего за вектором последнего прерывания, например, так: .org $40. В данном случае мы потеряем первые 64 ячейки памяти минус занятые под реально действующие векторы. Обратите внимание, что в старших моделях Mega таблица прерываний может занимать и больше места, чем 64 ячейки (так, в ATmega128 программа может начинаться лишь с ячейки $46), но для них, за небольшим исключением, и названия прерываний будут иными, так что все равно программу придется править (или использовать условную компиляцию).
Категория: Изучаем AVR | Добавил: Alex (05.01.2014)
Просмотров: 2190 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Copyright MyCorp © 2024