Вроде как попробовал и остался доволен. Но(1)...
Ясно, что таймеры ни кто не отменял и конкретные реализации протоколов можно успешно реализовать только на них. Но (2)...
...(2) Иногда все танцы (таймеры) расписаны и жаль делить под разные задачи и это не главные причины. Бывает нужно обеспечить именно простой работы МК для наружной периферии, при этом не соблюдая особой точности, типа ожидания поворота шестерни или обеспечение продолжительности мигания СДИ или пищалки. Да и просто удобно было бы скомандовать "DELAY 250" или "DELAY 1800".
...(1) Реализация Макросом таила подводные грабли: сумасшедший отжор программной памяти. Т.е. чем чаще использовал вызов макроса, тем толще оказывалась прошивка. После причёсывания проблемы, размер распухшей прошивки с 27К, уменьшился до 11К! И это ассемблер! Я и так где надо использовал PUSHF + POPF и даром это не проходило. Спасает от глюков, но платить приходится опять же программной памятью.
Для себя решил минимизировать поглощение программной памяти и пожертвовал 4-е верхних регистра навсегда. Но, если надо, то вставить в макроопределение PUSH + POP, ни кто не запрещает.
Переменные:
Спойлер
; Объявления переменных для функций Delay.def Delay1=r19 ; переменная функции Delay 1
.def Delay2=r20 ; переменная функции Delay 2
.def Delay3=r21 ; переменная функции Delay 3
.def Delay4=r22 ; переменная функции Delay 4
Макрос:
Спойлер
.macro DELAY_MS ; Вызов: "DELAY_MS 10"ldi Delay3, LOW(@0)
ldi Delay4, HIGH(@0)
rcall DELAY_M_S
.endm
; или для освобождения регистров, ценой программной памяти:
.macro DELAY_MS ; Вызов: "DELAY_MS 10"
PUSH Delay4
PUSH Delay3
PUSH Delay2
PUSH Delay1
ldi Delay3, LOW(@0)
ldi Delay4, HIGH(@0)
rcall DELAY_M_S
POP Delay1
POP Delay2
POP Delay3
POP Delay4
.endm
Функция:
Спойлер
; Задержка в циклах; Delay1 – параметр в диапазоне 4-255 (количество циклов)
DELAY_CL:
_delay_cl:
subi Delay1, 4
cpi Delay1, 4
brsh _delay_cl
cpi Delay1, 1
breq end_cl_1
cpi Delay1, 0
breq end_cl
cpi Delay1, 2
breq end_cl
rjmp end_cl
end_cl_1:
NOP
NOP
NOP
end_cl:
ret
; Задержка в циклах
; Delay1+Delay2 – параметр в диапазоне 15-65535 (количество циклов)
DELAY_C: ; добиться =1мСек, принимается аргумент XTAL/1000
cpi Delay1, 10
brsh fault
rjmp init_Delay2
fault: ; Delay1>=10
ldi Delay1, LOW(LOW(XTAL/1000))
rcall DELAY_CL ; LOW(@0-7)
; коррекция в тактах -28 для 4000 тактов 4МГц(нужно подумать...)
; коррекция в тактах +19 для 16000 тактов 16МГц
ldi Delay1,19
rcall DELAY_CL
init_Delay2: ; Delay1<10
cpi Delay2, 0
breq end_c
new_cycle:
subi Delay2, 1
ldi Delay1,239
rcall DELAY_CL
cpi Delay2, 0
brne new_cycle
NOP
end_c:
ret
; Задержка в милисекундах. Вызов: "DELAY_MS 2567" – параметр в диапазоне 1 – 65535 (количество миллисекунд)
; XTAL – Частота в Герцах
DELAY_M_S:
cpi Delay3, 0
breq re_init
_cicl_msl:
ldi Delay1, LOW(XTAL/1000)
ldi Delay2, HIGH(XTAL/1000)
rcall DELAY_C
subi Delay3, 1
cpi Delay3, 0
breq re_init
rjmp _cicl_msl
re_init:
cpi Delay4, 0
breq _end_c
subi Delay4, 1
ldi Delay3, 255
ldi Delay1, LOW((XTAL/1000)-255*5)
ldi Delay2, HIGH((XTAL/1000)-255*5)
rcall DELAY_C
rjmp _cicl_msl
_end_c:
ret
З.Ы. Пишу здесь, т.к. Хабр не позволяет после регистрации отвечать в старых темах.
З.З.Ы. И это естественно не мой код, только адаптация. И, если кому не сложно, то отполируйте его до приличия. У меня просто не хватает времени и думаю, что сам кому-то его сэкономлю, как и программную память.

