Последовательный асинхронный (синхронный) интерфейс JTAG SPI Интерфейс JTAG Интерфейс SPI Программный счётчик (PC) Схема программирования УАПП (УСАПП) Энергонезависимая пямять данных (EEPROM) Память программ (FLASH) Оперативная память данных (SRAM) Указатель стека (SP) Схема прерываний Регистры общего назначения Регистр команд Дешифратор команд Регистры ввода-вывода АЛУ Управление выполнением команд Процессорное ядро (CPU) Регистр состояния (SREG) 8 Внутренняя шина данных АЦП Аналоговый компаратор Порты ввода-вывода Таймеры-счётчики, сторожевой таймер Аналоговые входы Аналоговые входы Цифровые входы-выходы Входы-выходы Рис. 2. Архитектура микроконтроллеров семейства AVR 15 0 7 0 7 0 R0 ($0000) $0000 Регистры общего назначения Память программ Внутренняя оперативная память данных (32 x 8) $0060 [конф. А] $0100) [конф. В] RAMEND RAMEND+1 R31 ($001F) FLASHEND 7 0 7 $00 Регистры ввода-вывода Энергонезависимая память данных 0 $00 ($0020) Внешняя оперативная память данных (64 x 8 – конф. А; $3F ($005F) 124 x 8 – конф. В) [конф. А] $5F $9F ($00FF) [конф. В] XRAMEND Единое адресное пространство Рис. 3. Программная модель AVR-микроконтроллеров R0 R1 R26 R27 R28 R29 R30 R31 XL XH YL YH ZL ZH X Y Z Рис. 4. Регистры общего назначения Рис. 5. Последовательность разработки ПО для микроконтроллеров Строка программы должна быть не длиннее 120 символов и может иметь одну из четырёх форм: [метка:] .директива [параметры] [;Комментарий] [метка:] команда [операнды] [;Комментарий] [;Комментарий] [Пустая строка] Входным для транслятора является файл <имя_файла>.asm с текстом программы на языке ассемблера. Транслятор создаёт четыре новых файла: файл листинга (<имя_файла>.lst), объектный файл (<имя_файла>.obj), файл-прошивку памяти программ (<имя_файла>.hex) файл-прошивку энергонезависимой памяти данных (<имя_файла>.eep). 000000 e012 LDI R17, 2 ; загрузка числа 2 в регистр R17 000001 e025 LDI R18, 5 ; загрузка числа 5 в регистр R18 000002 e133 LDI R19, 19 ; загрузка числа 13 в регистр R19 000003 9f12 MUL R17, R18 ; умножение R17 на R18, результат в R1:R0 000004 0f12 ADD R17, R18 ; сложение R17 и R18, результат в R17 000005 1b31 SUB R19, R17 ; вычитание R17 из R19, результат в R19 000006 cfff met: RJMP met ; бесконечный цикл (для отладки) Рис. 6. Пример листинга трансляции Примеры использования прямой регистровой адресации РОН: ; прямая регистровая адресация одного РОН CLR R1 ; очистка всех разрядов регистра R1 ; прямая регистровая адресация двух РОН ADD R11, R12 ; сложение содержимого регистров R11 и R12 Пример использования непосредственной адресации ОЗУ: ; непосредственная адресация .dseg ; сегмент данных (оперативная память данных) .org $0065 ; по адресу $0065 cnt1: .byte 1 ; резервирование 1 байта для cnt1 .cseg ;... LDS ; программный сегмент (память программ) R10, cnt1 ; загрузка cnt1 в R10 косвенная адресация оперативной памяти данных ; косвенная адресация .dseg ; сегмент данных (оперативная память данных) cnt1: .byte 1 ; резервирование 1 байта для cnt1 .cseg ; программный сегмент (память программ) ;... LDI R30, low(cnt1) ; загрузка в R30 младшего байта адреса cnt1 LDI R31, high(cnt1) ; загрузка в R31 старшего байта адреса cnt1 LD R1, Z ; загрузка cnt1 в R1, т. е. R1 <- (R31:R30) косвенная адресация оперативной памяти данных со смещением ; косвенная адресация со смещением .dseg ; сегмент данных (оперативная память данных) arr: .byte 5 ; резервирование 5 байт для массива arr .cseg ; программный сегмент (память программ) LDI R30, low(arr) ; загрузка в R30 младшего байта адреса arr LDI R31, high(arr) ; загрузка в R31 старшего байта адреса arr ;... LDD R10, Z + 0 ; загрузка первого элемента массива arr в R10 LDD R11, Z + 1 ; загрузка второго элемента массива arr в R11 косвенная адресация оперативной памяти данных с предекрементом ; косвенная адресация с предекрементом LD R10, -Z ; Z <- Z – 1, R10 <- (Z) косвенная адресации оперативной памяти данных с предекрементом ; косвенная адресация с предекрементом LD R10, -Z ; Z <- Z – 1, R10 <- (Z) Пример использования адресации константы в памяти программ: LDI R31, high(var<<1) ; старший байт регистра Z LDI R30, low(var<<1) ; младший байт регистра Z LPM R16, Z ; загрузка числа $50 в R16 ;... .org $0025 ; по адресу $0025 var: .db $50, 137 ; константы $50 и 137 адресации константы в памяти программ с постинкрементом LDI R31, high(var<<1) ; старший байт регистра Z LDI R30, low(var<<1) ; младший байт регистра Z LPM R16, Z+ ; загрузка числа $50 в R16, инкремент Z LPM R17, Z ; загрузка числа 137 в R17 ;... var: .db $50, 137 ; константы $50 и 137 ОРГАНИЗАЦИЯ ПОДПРОГРАММ ; ... array: .byte 5 ; 5 байт для массива array ; ... LDI R16, 5 ; предел повторений цикла LDI R17, 100 ; число, заносимое в массив array LDI R18, 1 LDI R30, low(array) ; младший байт адреса массива array LDI R31, high(array) ; старший байт адреса массива array loop: ; тело цикла ST Z, R17 ; занесение числа 100 в массив array ADD R30, R18 ; адрес следующего байта массива array SUB R16, R18 ; счётчик числа проходов, шаг равен -1 BRNEloop ; повторить, если счётчик не равен нулю ; ... Рис. 22. Фрагмент программы циклической обработки массива Исходное состояние После записи числа С . .. . .. *** Addr .. . .. . После чтения . .. *** Addr–1 С Addr SP SP Исходное состояние . .. *** Addr–1 С Addr SP .. . а) .. . б) Рис. 23. Операции записи в стек (а) и чтения из стека (б): *** – очередная свободная ячейка стека; Addr – адрес *** Addr SP Основная программа . . . Загрузка в стек адреса возврата; загрузка в программный счётчик стартового адреса подпрограммы Вызов п/п SUBR Следующая команда . . . Извлечение из стека адреса возврата; загрузка адреса возврата в программный счётчик Подпрограмма SUBR: ... . . . Возврат Рис. 24. Механизм вызова подпрограммы и возврата в вызывающую программу Организация стека во внутренней оперативной памяти LDI R16, low(RAMEND) ; младшая часть адреса RAMEND OUT SPL, R16 ; инициализация SPL LDI R16, high(RAMEND) ; старшая часть адреса RAMEND OUT SPH, R16 ; инициализация SPH Примеры использования команд вызова подпрограмм: RCALL subr1 ; относительный вызов подпрограммы subr1 ; косвенный вызов подпрограммы subr2 LDI R30, low(subr2) LDI R31, high(subr2) ICALL ; команда icall не имеет операндов .nolist .include "m8535def.inc" .list RJMP ; отключить генерацию листинга ; подключить inc-файл ; включить генерацию листинга RESET ; переход к основной программе PODPR: ; подпрограмма PODPR ; ... RET ; возврат в основную программу RESET: ; основная программа LDI OUT LDI OUT ; ... RCALL ; ... R16, low(RAMEND) SPL, R16 R16, high(RAMEND) SPH, R16 PODPR ; инициализация SPL ; инициализация SPH ; вызов подпрограммы PODPR Рис. 25. Пример программы с использованием подпрограммы Если в основной программе перед вызовом подпрограммы занести в стек значение некоторого параметра: LDI PUSH R16, $33 ; R16 <- $33 R16 ; сохранение содержимого регистра R16 в стеке то в подпрограмме можно получить к нему доступ: IN R30, SPL ; младший байт указателя стека IN R31, SPH ; старший байт указателя стека LDD R20, Z+3 ; загрузка числа $33 из стека в регистр R20 ; область векторов прерываний .org $0000 RJMP RESET ; переход к основной программе .org INT0addr RJMP EXT_INT0 ; внешнее прерывание INT0 .org OVF0addr RJMP TMR0_INT ; прерывание по таймеру Т/С0 ; подпрограмма обработки внешнего прерывания INT0 EXT_INT0: ; ... RETI ; возврат ; подпрограмма обработки прерывания по таймеру T/C0 TMR0_INT: ; ... RETI ; возврат RESET: ; инициализация стека ; ... ; основная программа ; инициализация внешнего прерывания INT0 LDI R16, (1<<ISC01)|(1<<ISC00) OUT MCUCR, R16 ; по положительному фронту LDI R16, (1<<INTF1)|(1<<INTF0) OUT GIFR, R16 ; очистка флагов внешних прерываний LDI R16, 1<<INT0 OUT GICR, R16 ; разрешение внешнего прерывания INT0 ; инициализация прерывания по таймеру T/C0 LDI R16, 1<<CS00 OUT TCCR0, R16 ; деления частоты нет LDI R16, 1<<TOIE0 OUT TIMSK, R16 ; разрешение прерывания по таймеру Т/С0 SEI ; общее разрешение прерываний forever: NOP ; пустая команда (no operation) RJMP forever ; бесконечный цикл ; ... Рис. 26. Пример программы с использованием прерываний