При освоении языка программирования, Ассемблер, в описании инструментов этого языка, упоминается такой  элемент, как —  Макрос. Зачем он нужен и какая от него польза? Чтобы реально это понять, вероятно, лучше это показать на конкретном примере, конкретной программы.

Мне, для выполнения замысла моей программы необходимо было сформировать три разных интервала времени,  вызывая эти подпрограммы периодически в разных местах программы, и для создания разных временных интервалов в них, приходилось, использовать разные константы, но при этом пользоваться тремя подпрограммами одного и того же похожего вида.

В регистровую пару, загружалось число (константа) и производилось вычитание единицы из этого числа до тех пор, пока результат не сравняется с нолём. Вычитание разных констант, при определённой тактовой частоте микроконтроллера предполагало формирование разных интервалов времени.

Для моей программы  таймера надо было сформировать  интервалы времени при тактовой частоте внутреннего RC-генератора  128кГц/8, которую я выбрал для своего проекта реализованного на микроконтроллере AVR ATtiny13.
Интервалы длительностью:
1,125 с. получались при константе = 4500
0,2 с. при константе = 800
15 с. При константе = 60000
Это имело такой вид: три похожих куска, три подпрограммы для формирования разных временных интервалов, но имеющая одно выражение, все они похожи между собой, вот пример:
{codecitation class=»brush: vb; gutter: true;» width=»700px» }
;*************************************************************************************** 
Подпрограммы формирования интервалов времени
;***************************************************************************************
;———————— 1.125 s ——————————-
Delay _1:                       ; T off   «Led»  = 1,125 s. время когда светодиод погашен
ldi    XL,Low (4500)      ; загружаем константу в нижний регистр регистровой пары Х
ldi    XH,high (4500) )   ; загружаем константу в верхний регистр регистровой пары Х
del:   
sbiw  XL,1                   ; вычитаем 1 из двухбайтного слова загруженного в регистровую пару Х
brne  del                     ; если результат не равен нолю,снова переходим к метке ( del)
ret                              ; выход из этой подпрограммы
;——————————— 0.2s  ——————————
Delay_2:                              ; ON  «Led» =0,2 s.  -формирование времени, когда светодиод горит.
ldi   XL,Low (800) 
ldi   XH,high (800)
mm:  
sbiw  XL,1
brne  mm
ret
;————————————— T = 15 Sek.  ——————————————
Delay_15:                              ; формирование отрезка времени длительностью 15сек.
ldi   XL,Low (60000)  
ldi   XH,high (60000)
del_: 
sbiw  XL,1
brne  del_
ret
;**************************************************************************
{/codecitation}
Отличие этих подпрограмм — только константы подставлены разные, почему б не объединить это в одно выражение? И вот тут нам поможет облегчить эту задачу макрос.
Кусок кода объединить в одно выражение, где можно будет подставлять только разные константы, надо присвоить этим величинам, разным константам, разные символические  имена, чтобы их понимал макрос. 
Для этого я добавил новые записи в раздел присвоения имён переменных и констант, где для удобства при отладке, я смогу изменять их, если что, в одном только месте программы, которые будут подставляться соответствующими  присвоению, именами, например:
{codecitation class=»brush: vb; gutter: true;» width=»700px» }
;=============================================================
.equ PAUSE         =60000    ;константе (15 c.) присвоили имя – « PAUSE »
.equ LED_ON     =800    ;константе (0,2c) присвоили  имя « LED_ON  »
.equ LED_OFF     =4500 ;константе (1,125c.) присвоили  имя – «LED_ OFF »
.def counter        =r18  ;Регистру повторения количества раз *delay*  имя — « counter »
;=============================================================
{/codecitation}
Для того, чтобы все три подпрограммы объединить в одно выражение, надо создать макрос. Дадим ему символическое имя —  «delay » (задержка). Так же улучшаем характеристики прежней подпрограммы для формирования больших временных интервалов, мы добавляем ещё коэффициент умножения (на сколько надо умножить полученный временной интервал с занесённой константой времени, чтобы получить ещё большие отрезки времени. Этот коэффициент — число на которое надо умножить временной интервал, полученный нами, с использованием соответствующей константы. Эта величина должна быть в пределах от 1 до 255  (255 -максимальное однобайтное число)
И вот что у меня получилось:
{codecitation class=»brush: vb; gutter: true;» width=»700px» }
;=============================================================
; macros  delay
;=============================================================
.macro    delay       ;  присваиваем имя макросу —     « delay »
Ldi  counter,@1    ; здесь @1- это коэффициент повторения макроса K раз(1-255)
K:     
ldi   XL,Low (@0)      ;Загрузить младший байт константы времени
ldi   XH,high(@0)     ;Загрузить старший байт константы времени
delay_:
sbiw  XL,1; вычитаем единицу из двухбайтного слова загруженного в регистровую пару Х
brne  delay_
dec    counter
brne    K
.endm                 ; конец макроса
;=============================================================
{/codecitation}
Важный момент! Макрос надо располагать в самом начале программы.
Компилятор ассемблера проходя с начала до конца, читая нашу программу, усваивает условия оговоренные макросом в начале, точно так же, как и присвоение имён переменных и констант и остальные моменты, которые оговариваются в начале. Если мы расположим кусок подпрограммы макроса в конце программы, то он работать не будет и будет воспринят ассемблером, как ошибка.

Вместо трёх получилось одно универсальное выражение. Сравните визуально, сколько сократилось строк в тексте программы.
Теперь, если я захочу сформировать временной интервал, то вызываю этот макрос и выглядит эта запись так:

{codecitation class=»brush: vb; gutter: true;» width=»700px» }
;———————————————————————————————————
delay  PAUSE, 3
;———————————————————————————————————
{/codecitation}
Где delay — это имя макроса, PAUSE — это имя присвоенное нами константе (15 c.). В макросе таких величин-констант может быть записано в строке через запятую до 10-ти возможных (всё зависит от того, какой макрос мы придумаем).
В нашем примере я использовал две такие величины @0 и @1, и в данной записи это имя (PAUSE) в своём положении занимает 0-й разряд. В макросе соответствует обозначению с нулевым номером — @0 и поэтому стоит первым по списку в очереди, 3 — это второе число внесённое в макрос и соответствующее обозначению в нём — @1, которое пишется в строке через запятую после написания первого символического имени соответствующего — @0. 3 — Это коэффициент умножения, выбранный нами, на который надо умножить временной интервал = 15 с. с использованием константы, с присвоенным именем — PAUSE, чтобы получить интервал времени = 45 сек.

В результате мы получаем интервал времени равный 45с  (15с. х 3).

Пример использования макроса в проекте «Выключатель освещения в подъезде на микроконтроллере AVR«. В продолжении, пример обоих программ, модель в Proteus для наглядности работы таймера, можно сравнить, посмотреть, проанализировать просматривая содержимое регистров нашей программы.

Владимир Науменко, г. Калининград
 
Просмотров всего: 2 288, сегодня: 1

Напишите комментарий