Текст программы можно набирать в любом текстовом редакторе, такие как встроенный редактор Norton Commander, FAR, а также Microsoft Word, WordPad и других. Также можно использовать специально предназначенные для этого программы Wavrasm, AVR Studio
Для создания программы не обязательно использовать ассемблер, программное обеспечение AVR поддерживает также и язык C или С++. Но в лабораторном комплексе этот вариант не рассматривается.
Программа, написанная на ассемблере, должна иметь определенную структуру.
Предлагается следующий шаблон (для AT90S8535)
;*******************************************
; название программы,
; краткое описание, необходимые пояснения
:*******************************************
;******подключаемые дополнительные файлы
.include “8535def.inc”; файл описания AT90S8535
.include «имя_файла1.расширение»; включение дополнительных
.include «имя_файла2.расширение»; файлов
;****** глобальные константы
.equ имя1 = xxxx;
.equ имя2 = nnnn
;****** глобальные регистровые переменные
.def имя1= регистр
.def имя2= регистр
;******* сегмент данных
.dseg
.org xxxx; адрес первого зарезервированного байта
label1:.BYTE 1; резервировать 1 байт под переменную label1
label2:.BYTE m; резервировать m байт под переменную label2
;****** сегмент EEPROM (ЭСППЗУ)
.eseg
.org xxxx; адрес первого зарезервированного байта
.db выражение1,выражение2,…; записать список байтов в EEPROM.
.dw выражение1,выражение2,…; записать список слов в EEPROM.
;****** сегмент кодов
.cseg
.org $0000; адрес начала программы в программной памяти
;****** вектора прерываний (если они используются)
rjmp reset;прерывание по сбросу
.org $0002
rjmp INT0;обработчик прерывания IRQ0
.org $0004
rjmp INT1;обработчик прерывания IRQ1
.org adrINTx;адрес следующего обработчика прерываний
rjmp INTx;обработчик прерывания x
…….;далее по порядку располагать обработчики остальных;прерываний
;******* начало основной программы
main: <команда> xxxx
… …
;******* подпрограммы
;******* подпрограмма 1
subr1: <команда> xxxx
…… ………. ……
ret
;******* подпрограмма 2
subr2: <команда> xxxx
…… ………. ……
ret
…………….
;******* программы обработчиков прерываний
INT0: <команда> xxxx
…… ………. ……
reti
INT1: <команда> xxxx
…… ………. ……
reti
INTx: <команда> xxxx
…… ………. ……
reti
………………………
; конец программы никак не обозначается.
Ниже приводятся 3 программы решения одной и той же простейшей программы, демонстрирующие использование директив ассемблера.
Как уже указывалось, программа простейшая: вычесть из числа 5 число 3. Если включен тумблер SA1 (рис. 1.2), то на индикацию выдать результат вычитания. Если тумблер SA1отключен – на индикацию вывести цифру ноль.
Десятичное число | Код |
3f | |
5b | |
4f | |
6d | |
7d | |
7f | |
6f |
Рис. 1.5 Алгоритм программы №1
Алгоритм программы (рис. 1.5) соответствует программе №1, использующей директиву equ ассемблера.
Программа №2 отличается от программы №1 резервированием по одному байту оперативной памяти под семисегментные коды цифр от 0 до 9.
Программа №3 самая короткая. Она использует директиву.dw для определения слов в программной памяти. В программе используется команда LPM ассемблера. По этой команде загружается байт, адресуемый регистром Z в регистр R0. Команда обеспечивает доступ к любому байту памяти программы, организованной как 16 битное слово. Младший бит регистра Z определяет, осуществляется ли доступ к младшему байту слова (0) или к старшему (1).
;Программа №1.Использование директивы equ
.include "8535def.inc";включить файл – описание для AT90S8535
.dseg;сегмент данных
.equ cod0=$64;присвоение имен ячейкам SRAM
.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,$c;настроить порт В: биты 2 и 3 на выход, остальные на вход
out ddrb,r16
ldi r16,$f0;настроить порт D: биты 0...4 на вход, остальные на выход
out ddrd,r16
sbi portB,3;выдать 1 на разряд 3 порта В
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,4;если включен тумблер SA1,то пропустить
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;семисегментный код результата переслать в r20
pop zl;извлечь zl из стека
out portc,r0;выдать результат на индикацию
rjmp m1
;Программа №2. Использование оперативной памяти под переменные
.include "8535def.inc";подключение файла описания AT90S8535
.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,$c;настроить порт В: биты 2 и 3 на выход, остальные на вход
out ddrb,r16
ldi r16,$f0;настроить порт D: биты 0...4 на вход, остальные на выход
out ddrd,r16
sbi portb,3;выдать 1 на разряд 3 порта В
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,4;если включен тумблер SA1,то пропустить
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;семисегментный код результата переслать в r20
pop zl;извлечь zl из стека
out portc,r0;выдать результат на индикацию
rjmp m1
;Программа №3. Использование директивы.dw
.include "8535def.inc";подключение файла описания AT90S8535
.cseg
.org 0
rjmp reset
.dw $063f,$4f5b,$6d66,$077d,$6f7f,$7c77,$5e39,$7179;семисегментные коды
reset:
ldi r16,$00;определение стека с вершиной по адресу $00ff
out sph,r16
ldi r16,$ff
out spl,r16
ldi r16,$ff
out ddrc,r16;настроить порт С на выход
ldi r16,00
out ddra,r16;настроить порт А на вход
ldi r16,$c
out ddrb,r16;настроить порт В: биты 2 и 3 на выход, остальные на вход
ldi r16,$f0
out ddrd,r16;настроить порт D: биты 0...4 на вход, остальные на выход
sbi portb,3;выдать 1 на разряд 3 порта В
ldi zl,02;установить адрес семисегментного кода нуля в регистр Z
ldi zh,00
ldi r17,5;задание уменьшаемого
ldi r18,3;задание вычитаемого
m1: sbis pina,4;если включен SA1, то пропустить следующую команду
rjmp m2
mov r20,r17;в r20 поместить уменьшаемое
sub r20,r18;вычесть вычитаемое
rjmp vv
m2:
ldi r20,0;присвоить результату значение нуль
vv: push zl;сохранить zl в стеке
add zl,r20; сложить zl с результатом
lpm;загружаем бит, адресуемый регистром Z, в регистр R0
pop zl;извлечь zl из стека
out portc,r0;выдать результат на индикацию
rjmp m1