.include "2313def.inc"
.cseg
.org 0
rjmp RESET
; ЗМІННІ.
; Змінні часу.
.def timem = r11 ; Час (в хв).
.def times = r12 ; Час (в с).
.def timems = r13 ; Час (в мс).
; Змінні стану.
.def runed = r14 ; Чи запущений таймер.
.def paused = r15 ; Чи знаходиться таймер в режимі паузи.
; Загальні змінні (що не ввійшли до попередніх блоків.
.def proc = r16 ; Змінна для різних маніпуляцій.
.def over = r17 ; Похибка часу.
; КОНСТАНТИ.
; Кнопки.
.equ play = PD2 ; Кнопка "Старт".
.equ pause = PD3 ; Кнопка "Пауза".
.equ stop = PD4 ; Кнопка "Стоп"
.equ refresh = PD5 ; Кнопка "Перезапустити".
; Лінії передачі даних через COM-порт.
.equ TxD = PD1
; Прийом/передача слів.
.equ t9b = (1<<TXEN) + (1<<CHR9) ; Передача 9-бітних слів.
; Передача даних.
.equ FMB = $aa ; First message byte. ; Перший байт повідомлення.
RESET:
ldi proc,15
out WDTCR,proc ; Ініціалізація сторожового таймера:
; при відсутності команди скиду (wdr)
; через 2 с відбудеться перехід на
; переривання RESET.
wdr ; Скид сторожового таймера.
clr proc ; Очистка proc (proc = 0).
out DDRD,proc ; Лінії порта D - входи.
ser proc ; Встановлення в proc значення 0FF.
out PORTD,proc ; На всіх лініях порта D
; встановлення ВИСОКИХ рівнів.
out PIND,proc ; Операція для AVR Studio, щоб
; встановити на контактах порта
; D ВИСОКІ рівні; інакше
; відлагоджувач буде сприймати
; стан ліній порта D як одночасне
; натискання всіх чотирьох кнопок:
; "Старт", "Пауза", "Стоп" і
; "Перезапустити".
; Ініціалізація стека.
ldi proc,low(RAMEND)
out SPL,proc
main:
sbis PIND,play ; Пропуск наступної команди, якщо
; на лінії play (PD2) ВИСОКИЙ рівень.
rcall PlayTimer ; Виклик підпрограми PlayTimer.
sbis PIND,pause ; Пропуск наступної команди, якщо
; на лінії play (PD3) ВИСОКИЙ рівень.
rcall PauseTimer ; Виклик підпрограми PauseTimer.
sbis PIND,stop ; Пропуск наступної команди, якщо
; на лінії play (PD4) ВИСОКИЙ рівень.
rcall StopTimer ; Виклик підпрограми StopTimer.
sbis PIND,refresh ; Пропуск наступної команди, якщо
; на лінії play (PD5) ВИСОКИЙ рівень.
rcall ResetTimer ; Виклик підпрограми RestartTimer.
rcall IncTimer ; Нарощуємо значення таймера (звісно,
; якщо можна).
rjmp main ; Повернення в початок main'а.
; Підпрограма запуска таймера.
; ============================
PlayTimer:
ldi runed,1 ; Запис 1 у змінну стану запуску, що
; означає, що таймер запущено.
cpi paused,1 ; Перевірка, чи активовано режим паузи:
brne playTEnd ; якщо ні, то вихід з підпрограми;
ldi paused,0 ; інакше - деактивація режиму паузи.
playTEnd: ret ; Кінець підпрограми PlayTimer.
; Підпрограма обробки запиту на паузу.
; ====================================
PauseTimer:
cpi runed,1 ; Перевірка, чи запущено таймер;
brne pauseTEnd ; якщо ні, то вихід з підпрограми.
cpi paused,0 ; Стан запуску порівнюється з нулем:
breq notPaused ; якщо регістр дорівнює 0, то значить
; таймер не призупинено, отже, необхідно
; активувати паузу (перехід до мітки
; notPaused);
; інакше: вихід з режиму паузи:
ldi paused,0 ; встановлення значення змінної в 0
rjmp pauseTEnd ; і вихід з підпрограми.
notPaused: ldi paused,1 ; Запис в змінну паузи 1.
pauseTEnd: ret ; Кінець підпрограми PauseTimer.
; Підпрограма зупинки таймера.
; ============================
StopTimer:
ldi runed,0 ; У змінну стану запуску записується 0,
; що означає, що таймер зупинено.
ldi paused,0 ; Пауза теж прибирається.
ret ; Кінець підпрограми StopTimer.
; Підпрограма обнуління таймера.
; ==============================
ResetTimer:
; Обнуління таймера.
ldi timems,0
ldi times,0
ldi timem,0
ret ; Кінець підпрограми RestartTimer.
; Підпрограма нарощення часу.
; ===========================
IncTimer:
cpi runed,0 ; Перевірка, чи запущений таймер:
breq incTEnd ; якщо так, то - вихід з підпрограми.
cpi paused,0 ; Перевірка, чи не знаходиться таймер
; в режимі паузи:
breq incTEnd ; якщо так, то - вихід з підпрограми.
rcall SendTime ; Відсилання часу.
rcall Wait1ms ; Затримка в 1 мс.
inc timems ; Збільшення кількості мілісекунд.
; Досягнення секунди.
cpi timems,100 ; Перевірка, чи не досягнуто позначки
; нової секунди;
brlo incTEnd ; якщо ні, то - вихід з підпрограми;
inc times ; збільшення кількості секунд;
ldi timems,0 ; обнуління лічильника мілісекунд.
; Досягнення хвилини.
cpi times,60 ; Перевірка, чи не досягнуто позначки
; нової хвилини:
brlo incTEnd ; якщо ні, то - вихід з підпрограми;
inc timem ; збільшення кількості хвилин;
ldi times,0 ; обнуління лічильника секунд.
adiw over,8 ; Урахування похибки.
; Досягнення години.
cpi timem,60 ; Перевірка, чи не досягнуто позначки
; нової години:
brlo incTEnd ; якщо ні, то - вихід з підпрограми;
ldi timem,0 ; інакше - обнуління лічильника хвилин.
incTEnd: ret ; Кінець підпрограми IncTimer.
; Підпрограма затримки на 1 мс.
; =============================
Wait1ms:
wdr ; Скид сторожового таймера.
; Затримку в 1 мс.
ldi YL,low(13333)
ldi YH,high(13333)
waitCycle: sbiw YL,1 ; Від пари YH:YL віднімається 1.
brne waitCycle ; Якщо результат виконання останньої
; команди не рівне 0, то продовжити
; цикл.
ret ; Кінець підпрограми Wait.
; Підпрограма відсилання часу.
; ============================
SendTime:
ret ; Кінець підпрограми SendTime.