Написание программы
Текст программы можно набирать в любом текстовом редакторе, такие как встроенный редактор 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
return false">ссылка скрыта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