Вернемся к форме записи команды. 12 бит адреса могут представлять 4096 различных адресов. Так как единицей объема памяти программ служит слово из двух байтов (а не отдельный байт), как раз из-за того, что любая команда занимает не менее чем два байта, то общий объем адресуемой таким образом памяти и составит 8 кбайт. А вот если памяти больше, то приходится использовать команду jmp (абсолютный безусловный переход). Она состоит из четырех байт, в которых адрес займет 22 бита, и потому с ее помощью можно адресовать до 4 М (8 Мбайт) памяти. Мы условимся, что старшие модели семейства Mega применять не будем, и потому ограничимся командой rjmp.
Подведем некоторый итог: мы уже узнали многое о структуре типовой программы для AVR. Она должна начинаться с безусловного перехода на метку RESET, а само начало этой программы будет располагаться сразу после этой метки где-то в другом месте программы. А почему так странно? Нельзя ли начать прямо сразу с нулевого адреса, строка за строкой, зачем нужны какие-то переходы? Можно, отвечают нам авторы описаний AVR. Простейшая программа может начинаться с нулевого адреса без переходов, но только в одном случае: если мы обязываемся отказаться от прерываний. А без них контроллер теряет 90 % своей функциональности. Конечно, можно придумать пример программы, которая бы делала что-нибудь полезное, но при этом работала совсем без прерываний. Но на практике без прерываний обходятся только тогда, когда штатных прерываний хватает (например, для отслеживания состояния большого количества кнопок), или когда без них программа получается компактнее (такие случаи мы еще встретим).
Обработка прерываний
AVR по умолчанию ожидает, что сразу после первой команды с адресом $0000 идет таблица т. н. векторов прерываний . Вектор — это просто отсылка по нужному адресу с помощью команды rjmp. Адрес обозначается меткой, может располагаться в любом месте программы, и содержит начало процедуры обработки прерывания. Первый вектор располагается по адресу $0001 (а для МК с памятью более 8 К — по адресу $0002, потому что по адресу $0001 находится вторая половина более длинной команды jmp), причем адрес этот означает номер двухбайтного слова в памяти, а не отдельного байта (оно в два раза меньше количества байт). Попутно заметим, адреса в SRAM (ОЗУ) именно байтовые, а не пословные (см. далее). На самом деле в режиме по умолчанию нам вообще не нужно думать про абсолютные адреса и их нумерацию: первая команда программы ( rjmp RESET), которая еще называется вектором сброса (или вектором начальной загрузки ), автоматически расположится по нулевому адресу, вторая — по адресу $0001 и т. д. Найдя какую-нибудь команду перехода по метке, компилятор автоматически подставит абсолютные адреса.
Порядок векторов и их количество в таблице жестко задано в соответствии с типом МК. Потому самое первое, что вы должны сделать, приступая к программированию, — открыть руководство по применению выбранного типа контроллеров и скопировать оттуда эту таблицу. Можно попытаться сделать это прямо через буфер обмена из PDF-описания или преобразовав его в другой формат, так меньше вероятность что-то пропустить, только придется потом удалить указанные там абсолютные адреса, стоящие в начале каждой строки. Вот как будет выглядеть заготовка начала программы для МК ATmega8 (листинг 13.1).
Листинг 13.1.
;=======прерывания=======
rjmp 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 ;Timer 1 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
;========================
Обратите внимание, что в ассемблерной программе каждый оператор занимает отдельную строку (в большинстве языков высокого уровня операторы можно записывать в одной строке, например, разделяя их знаками препинания; здесь это не допускается). Символы пробелов и табуляции могут встречаться в произвольном количестве, и они полностью игнорируются, за исключением двух случаев: нельзя разбивать идентификатор на части и, наоборот, нельзя соединять разные идентификаторы между собой; хотя бы один пробел, знак табуляции (или знак препинания, если это предусмотрено форматом команды) между наименованиями инструкций, переменных, регистров и т. п. должен быть.
Читать дальше
Конец ознакомительного отрывка
Купить книгу