.include "m8def.inc"	; ATMega8
; частота 8 МГц

.def adr_recive		= R4	; адрес для следующего принятого байта
.def adr_transmit	= R5	; адрес для следующего переданного байта
.def count_recive	= R6	; счетчик принятых байт
.def count_transmit	= R7	; счетчик переданных байт
.def save_SREG		= R15	; для сохранения регистра статуса
.def count_int_T2	= R18	; счетчик прерываний таймера2, значение 5 == 10 мс
.def count_01sec	= R19	; счетчик по 10 мс
.def number_par		= R20	; номер индицируемого параметра

.equ d18b20			= 0		; пин термометра
.equ pin_d18b20		= pinC
.equ ddr_d18b20		= ddrC

.equ buffer_USART	= 0xC0	; буфер приемопередатчика

.cseg
.org 0
rjmp nachalo_code

.org OC2addr			; адрес прерывания timer2, Timer on Compare Match (CTC) mode
rjmp timer2				; прерывание таймера2

.org URXCaddr			; адрес прерывания USART, Rx Complete
rjmp USART_Rx_Complete	; прием готов
nop
rjmp USART_Tx_Complete	; передача готова

nachalo_code:
ldi R26,  low(RAMEND)
out SPL, R26 
ldi R26, high(RAMEND)
out SPH, R26

ldi R26, buffer_USART	; подготовить регистры для приемника USART
mov adr_recive, R26
clr count_recive

;--- Порт C ---
; Порт C0 - 1-wire

;--- Порт D ---
; Порт D0 - приемник USART
; Порт D1 - передатчик USART

;--- установка портов ---
ldi R26, 0b00000000
out ddrC, R26
ldi R26, 0b11111110		; без подтяжки на PC0
out portC, R26
ldi R26, 0b00000000
out ddrD, R26
ldi R26, 0b11111111
out portD, R26

;--- запустим конвертацию температуры, чтобы при входе в полный цикл (через 1 секунду) у нас уже был результат измерения температуры ---
rcall initialization
ldi R28, 0xCC			; пропуск ROM
rcall one_byte_write
ldi R28, 0x44			; конвертировать температуру
rcall one_byte_write

;------ Таймер2 ------
ldi R26, 249			; 250 для 2 мс (8 * 250 = 2000 мкс = 2 мс)
out OCR2, R26 			; сохранить в регистре сравнения
ldi R26, 0b00001100		; таймер2, режим Compare Match, предделитель 64 == пуск таймера2
out TCCR2, R26

ldi R26, (1<<OCIE2)
out TIMSK, R26

;--- USART - универсальный приемопередатчик ---
ldi R26, 0b00100010		; RXC, TXC, регистр данных пустой, 3 бита - разные ошибки, двойная скорость, режим не используем
out UCSRA, R26
ldi R26, 0b11011000		; разрешить прерывание на RXC флаг, разрешить прерывание на TXC флаг, запретить прерывание на пустой регистр данных, 
						; разрешить прием, разрешить передачу, 8 бит (байт) данных, 2 бита для 9-битных данных - не используем
out UCSRB, R26
ldi R26, 0b10000110		; доступ к записи UCSRC, асинхронный режим, 2 бита - проверка четности запрещена, 1 стоп-бит, 2 бита - 8 бит (байт) данных, режим не используем
out UCSRC, R26
ldi R26, 103			; 103 - скорость 9600 бод при частоте генератора 8 МГц и при двойной скорости
out UBRRL, R26
ldi R26, 0				; доступ к UBRRH и старшие биты скрости равны нулю
out UBRRH, R26

;---------------
sei 					; разрешить все прерывания

;--- основной цикл программы ---
wait_timer2:
cpi count_int_T2, 5
brlo wait_timer2
clr count_int_T2
inc count_01sec

;--- сюда заходим каждые 10 мс ---

interface:
;--- структура принятой телеграммы ---
; 1 - код команды
; 2 - номер параметра
; 3 - младший байт записываемого значения параметра
; 4 - старший байт записываемого значения параметра

;--- обработка принятой телеграммы ---
mov R26, count_recive
cpi R26, 4				; проверим, пришли ли все байты
brsh tel
rjmp end_interface

tel:
ldi YL, adress_spiska	; Y - адрес списка параметров
clr YH
ldi ZL, buffer_USART	; Z - адрес буфера приемопередатчика
ld R26, Z
cpi R26, 'a'			; all - передать все параметры
breq yes_all
rjmp not_all

yes_all:				; all - передать все параметры
/*
чтение параметров по Y и передача в buffer_USART по Z
*/
ldi R26, 29				; загрузить в count_transmit число передаваемых байтов, кроме первого байта
mov count_transmit, R26
rjmp end_receive

not_all:
cpi R26, 'p'			; p - пуск/стоп
brne not_pusk_stop
rcall pusk_stop
rjmp end_receive1

not_pusk_stop:
cpi R26, 'c'			; c - сброс секундомера
brne not_sbros_sekund
rcall sbros_sekund
rjmp end_receive1

not_sbros_sekund:
cpi R26, 'w'			; w - записать параметр
brne not_write
ldd R26, Z + 1			; прочитаем номер параметра
mov number_par, R26
lsl R26
add YL, R26				; получим в регистровой паре Y адрес параметра
ldd R26, Z + 2
st Y+, R26
mov R10, R26
ldd R26, Z + 3
st Y+, R26
mov R11, R26
mov R26, number_par
lsl R26
rcall ogranichenie
rcall save_param
rjmp end_receive1

not_write:
; анализ и выполнение других команд по интерфейсу

end_receive1:
ldi R26, 3				; загрузить в count_transmit число передаваемых байтов, кроме первого байта
mov count_transmit, R26

end_receive:
clr count_recive		; подготовить регистры для приемника и передатчика
ldi R26, buffer_USART
mov adr_recive, R26		; передать адрес в adr_recive, куда записывать первый принятый байт
inc R26
mov adr_transmit, R26	; передать адрес в adr_transmit, откуда брать следующий (второй) байт

; ответная передача
lds R26, buffer_USART
out UDR, R26			; передать первый байт

end_interface:

test_1s:
cpi count_01sec, 100	; проверим 1 секунду
breq yes_1sec			; перейти на обработку полного цикла
rjmp wait_timer2

yes_1sec:
;--- полный цикл, 1 раз в секунду ---

clr count_01sec			; чистим счетчик 0,01 сек.

;--- чтение и вывод температуры ---
rcall initialization
ldi R28, 0xCC			; пропуск ROM
rcall one_byte_write
ldi R28, 0xBE			; чтение памяти
rcall one_byte_write

;--- прием данных датчика, первые два байта содержат данные о температуре ---
rcall one_byte_read
mov R10, R28			; младший байт
rcall one_byte_read
mov R11, R28			; старший байт

;--- запуск замера температуры ---
rcall initialization
ldi R28, 0xCC			; пропуск ROM
rcall one_byte_write
ldi R28, 0x44			; конвертировать температуру
rcall one_byte_write

/*
обработка результата по температуре и вывод температуры на дисплей
*/

end_cycle_1s:
rjmp wait_timer2

;----- далее только подпрограммы -----

;--- Timer2 ---
timer2:					; срабатывает по сравнению
in save_SREG, SREG

inc count_int_T2

out SREG, save_SREG
reti

;--- прием готов ---
USART_Rx_Complete:
in save_SREG, SREG
push R26				; сохраним регистры, которые использует прерывание
push ZL

in R26, UDR
mov ZL, adr_recive
st Z+, R26
mov adr_recive, ZL
inc count_recive

pop ZL
pop R26
out SREG, save_SREG
reti

;--- передача готова ---
USART_Tx_Complete:
in save_SREG, SREG
push R26				; сохраним регистры, которые использует прерывание
push ZL

mov R26, count_transmit
cpi R26, 0
breq end_transmit
mov ZL, adr_transmit
ld R26, Z+
out UDR, R26
mov adr_transmit, ZL
dec count_transmit

end_transmit:
pop ZL
pop R26
out SREG, save_SREG
reti

;--- инициализация 1-wire ---
initialization:
sbi ddr_d18b20, d18b20	; выход, импульс 0
rcall delay480us
cbi ddr_d18b20, d18b20	; вход
rcall delay480us
ret

;--- чтение одного байта из 18В20, результат приема в R28 ---
one_byte_read:
ldi R27, 8				; принять 8 бит
bit_read:
cli
sbi ddr_d18b20, d18b20	; выход
ldi R26, 3
rcall delay_short
cbi ddr_d18b20, d18b20	; вход, итого длительность нуля 2.25 мкс
ldi R26, 28
rcall delay_short
clc						; сбросить флаг переноса
sbic pin_d18b20, d18b20	; итого до проверки пина 14 мкс
sec						; установить флаг переноса
sei
ror R28					; сдвиг вправо с переносом
ldi R26, 119
rcall delay_short		; тайм-слот 60.5 us
dec R27
brne bit_read
ret

;--- запись одного байта в 18В20, передаваемый байт в R28 ---
one_byte_write:
ldi R27, 8				; передать 8 бит
bit_write:
cli
sbi ddr_d18b20, d18b20	; выход, импульс 0
lsr R28					; сдвиг вправо
brcc bit_0				; перейти, если флаг переноса очищен, запись нуля
cbi ddr_d18b20, d18b20	; вход, запись единицы
sei
bit_0:
ldi R26, 154
rcall delay_short		; тайм-слот 60.125/60.375 us
cbi ddr_d18b20, d18b20	; вход, тайм-слот окончен
sei
dec R27
brne bit_write
ret

;--- задержки ---
delay480us:
ldi R26,  low(960)
ldi R27, high(960)

delay:					; 3 цикла на rcall
subi R26, 1				; длина задержки = (4*R27:R26+7) / 8 (в микросекундах)
sbc R27, R31
brcc delay
ret

delay_short:			; 3 цикла на rcall, итого (3*R26+6) / 8 (в микросекундах)
dec R26					; длина задержки 3*R26+3
brne delay_short
ret
