Структура ассемблерной программы
Программа, написанная на ассемблере, должна иметь определенную структуру. Предлагается следующий шаблон (для ATmega8535) ;**************************************************** ; название программы, ; краткое описание, необходимые пояснения ;**************************************************** ; *********** подключаемые дополнительные файлы .include "m8535def.inc"; файл описания ATmega8535 .include «имя_файла1.расширение»; включение дополнительных .include «имя_файла2.расширение»; файлов ;****** глобальные константы equ имя1 = хххх; equ имя2 = nnnn ;****** глобальные регистровые переменные def имя1 = регистр def имя2 = регистр ;******* сегмент данных .dseg .org ххх; адрес первого зарезервированного байта label1:.BYTE 1; резервировать 1 байт под переменную label1 label2:.BYTE m; резервировать m байт под переменную label2 .****** сегмент ЕЕPROM (ЭСППЗУ) .eseg .org ххх; адрес первого зарезервированного байта .db выражение1,выражение2,..;записать список байтов в EEPROM .dw выражение1,выражение2,...;записать список слов в EEPROM ;****** сегмент кодов .cseg .org $000; адрес начала программы в программной памяти .****** вектора прерываний (если они используются) rjmp reset; прерывание по сбросу .org $001 rjmp INT0; обработчик внешнего прерывания 0 .org $002 rjmp INT1; обработчик внешнего прерывания 1 .org adrINTx; адрес следующего обработчика прерываний rjmp INTx; обработчик прерывания х ......; далее по порядку располагать обработчики остальных ; прерываний
;******* начало основной программы main: <команда> хххх ......... ;******* подпрограммы ;******** подпрограмма 1 subr1: <команда> хххх ......... ret ;******* подпрограмма 2 subr2: <команда> хххх ......... ret
;******* программы обработчиков прерываний INT0: <команда> хххх ......... reti INT1: <команда> хххх ......... reti INTx: <команда> хххх
......... reti ; конец программы никак не обозначается.
В комплексе предусмотрена работа с однофайловыми программами для учебных целей, поэтому подключение внешних файлов, кроме.include "m8535def.inc", смысл имеет только для внешних сред программирования типа AVRStudio. При использовании подпрограмм нужно обязательно определять стек. Для этого в начале основной программы нужно занести значения адреса вершины стека в регистры SPH и SPL. Примеры программ Ниже приводятся 3 программы для решения одной и той же простейшей задачи, демонстрирующие использование директив ассемблера. Рис. 8. Алгоритм программы № 1 Задача следующая: вычесть из числа 5 число 3. Если включен тумблер на входе РА2, то на индикацию выдать результат вычитания. Если тумблер отключен – на индикацию вывести цифру ноль. При работе с портами ввода/вывода следует учитывать, что направление передачи данных через отдельные выводы задается с помощью регистров DDR (DDRA, DDRB, DDRC, DDRD). Если вывод порта сконфигурирован как выход, то его переключение производится через регистр PORT (PORTA, PORTB, PORTC, PORTD), если вывод сконфигурирован как вход, то его опрос следует производить через регистр входных данных PIN (PINA, PINB, PINC, PIND). Алгоритм программы (рис. 8) соответствует программе № 1, использующей директиву equ ассемблера.
;Программа №1.Использование директивы equ .include "m8535def.inc";включить файл-описание ATmega8535 .dseg;сегмент данных .equ cod0=$64;присвоение имен ячейкам ОЗУ .equ cod1=$65 .equ cod2=$66 .equ cod3=$67 .equ cod4=$68 .equ cod5=$69 .equ cod6=$6a .equ cod7=$6b .equ cod8=$6c .equ cod9=$6d
.cseg;сегмент кодов .org 0;адрес начала программной памяти rjmp reset;вектор сброса .org $30;начало программы reset: ldi r16,$00;определение стека с вершиной по адресу $00ff out sph,r16 ldi r16,$ff out spl,r16 ldi zl,$64;задание адреса начала зарезервированных ячеек ldi zh,$00
ldi r16,$ff;настроить порт С на выход out ddrc,r16 ldi r16,00;настроить порт А на вход out ddra,r16 ldi r16,$ff;настроить порт В на выход
out ddrb,r16 ldi r16,$f0;настроить порт D: биты 0…3 на вход, out ddrd,r16;остальные на выход sbi portd,7;выдать 1 на разряд 7 порта D
ldi r17,$3f;задание семисегментных кодов sts cod0,r17 ldi r17,$06 sts cod1,r17 ldi r17,$5b sts cod2,r17 ldi r17,$4f sts cod3,r17 ldi r17,$66 sts cod4,r17 ldi r17,$6d sts cod5,r17 ldi r17,$7d sts cod6,r17 ldi r17,$07 sts cod7,r17 ldi r17,$7f sts cod8,r17 ldi r17,$6f sts cod9,r17
ldi r17,5;задание уменьшаемого ldi r18,3;задание вычитаемого
m1: sbis pina,2;если включен тумблер, то пропустить rjmp m2;следующую команду mov r20,r17;в r20 поместить уменьшаемое sub r20,r18;вычесть вычитаемое rjmp vv m2: ldi r20,0
vv: push zl;сохранить zl в стеке add zl,r20;сложить zl с результатом ld r0,z;семисегментный код результата переслать в r0 pop zl;извлечь z1 из стека out portc,r0;выдать результат на индикацию rjmp m1
Программа № 2 отличается от программы № 1 резервированием по одному байту оперативной памяти под семисегментные коды цифр от 0 до 9.
;Программа №2. Использование оперативной памяти под переменные .include "m8535def.inc";подключение описания ATmega8535 .dseg;сегмент данных .org $64;адрес первого зарезервированного байта cod0:.byte 1;резервирование по одному байту cod1:.byte 1;под переменные cod2:.byte 1 cod3:.byte 1 cod4:.byte 1 cod5:.byte 1 cod6:.byte 1 cod7:.byte 1 cod8:.byte 1 cod9:.byte 1
.cseg;сегмент кодов .org $0;адрес начала программной памяти rjmp reset;вектор сброса reset: ldi r16,$00;определение стека с вершиной по адресу $00ff out sph,r16 ldi r16,$ff out spl,r16 ldi zl,$64;задание адреса начала зарезервированных ячеек ldi zh,$00
ldi r16,$ff;настроить порт С на выход out ddrc,r16 ldi r16,00;настроить порт А на вход out ddra,r16 ldi r16,$ff;настроить порт В на выход out ddrb,r16 ldi r16,$f0;настроить порт D: биты 0…3 на вход, out ddrd,r16;остальные на выход sbi portd,7;выдать 1 на разряд 7 порта D
ldi r17,$3f;задание семисегментных кодов sts cod0,r17 ldi r17,$06 sts codl,r17 ldi r17,$5b sts cod2,rl7 ldi r07,$4f sts cod3,rl7 ldi r17,$66 sts cod4,rl7 ldi r17,S6d sts cod5,r17 ldi r17,$7d sts cod6,r17 ldi r17,$07 sts cod7,r17 ldi r17,$7f sts cod8,r17 ldi rl7,$6f sts cod9,r17
ldi r17,5;задание уменьшаемого ldi r18,3;задание вычитаемого
m1: sbis pina,2;если включен тумблер, то пропустить rjmp m2;следующую команду mov r20,r17;в г20 поместить уменьшаемое sub r20,r18;вычесть вычитаемое rjmp vv m2: ldi r20,0
vv: push zl;сохранить zl в стеке add z1,r20;сложить zl с результатом ld r0,z;семисегментный код результата переслать в г0 pop z1;извлечь zl из стека out portc,r0;выдать результат на индикацию
rjmp m1
Программа № 3 самая короткая. Она использует директиву.dw для определения слов в программной памяти. В программе используется команда LPM ассемблера. По этой команде загружается байт, адресуемый регистром Z в регистр R0. Команда обеспечивает доступ к любому байту памяти программы, организованной как 16-битное слово. Младший бит регистра Z определяет, осуществляется ли доступ к младшему байту слова (0) или к старшему (1).
;Программа №3. Использование директивы.dw .include "m8535def.inc";подключение описания ATmega8535 .cseg .org 0 rjmp reset .dw $063f,$4f5b,$6d66,$077d,$617f,$7c77,$5e39,$7179 ;семисегментные коды цифр от 0 до F reset: ldi r16,$00;определение стека с вершиной по адресу $00ff out sph,r16 ldi r16,$ff out spl,r16
ldi rl6,$ff;настроить порт С на выход out ddrc,r16 ldi r16,00;настроить порт А на вход out ddra,r16 ldi r16,$ff;настроить порт В на выход out ddrb,r16 ldi r16,$f0;настроить порт D: биты 0...3 на вход, out ddrd,r16;остальные на выход sbi portd,7;выдать 1 на разряд 7 порта D
ldi zl,02;установить адрес семисегментного кода нуля ldi zh,00;в регистр Z ldi r17,5;задание уменьшаемого ldi r18,3;задание вычитаемого
m1: sbis pina,2;если включен тумблер, то пропустить rjmp m2;следующую команду mov r20,r17;в r20 поместить уменьшаемое sub r20,r18;вычесть вычитаемое rjmp vv m2: ldi r20,0;присвоить результату значение 0
vv: push z1;сохранить z1 в стеке add z1,r20;сложить z1 с результатом lpm;загрузить байт, адресуемый регистром Z, в регистр 0 pop z1;извлечь z1 из стека out portc,r0;выдать результат на индикацию rjmp m1
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|