;-- http://radiohlam.ru - собери сам, помоги собрать другу
;-- внутренний RC-генератор 8 МГц, - установлены фьюзы: SPIEN, SUT0 и CKSEL0 (они равны нулю, в понипрог напротив них стоят галочки)
.device ATtiny45
.include "tn45def.inc"
.list
;-- определяем свои переменные
.def   w=r16		; это будет наш аккумулятор
.def   Flags=r17    ; регистр пустой - алгоритм не запущен, установлен 0-й бит - запущен алгоритм AN1990, установлен 1-й бит - запущен алгоритм DS2502
.def   Counter=r18	; счётчик  срабатываний таймера

.def   C_2502=r19	; хранилище значения счётчика для задержки 500 мкс
.def   T_2502=r20	; хранилище значения таймера для задержки 500 мкс
.def   C_1990=r21	; хранилище значения счётчика для задержки 104 мс
.def   T_1990=r22	; хранилище значения таймера для задержки 104 мс

;--------------------------
.equ   CtrlOut=0	; PB0 - выход на управление транзисторами
.equ   InCode1=3	; PB3 - вход, кодирующий номер алгоритма
.equ   InCode2=4	; PB4 - вход, кодирующий номер алгоритма
.equ   InStart=2	; PB2 - вход, запускающий алгоритм управления

;-- Используемые регистры
; SPL - указатель вершины стека
; ACSR - управление компаратором
; DDRB - направление работы ног
; PORTB - выходы порта
; GIMSK - общее разрешение прерываний от ног
; PCMSK - выбор от каких ног разрешить прерывание
; TCCR0B - управление таймером
; TIMSK0 - прерывания от таймера
; TCNT0 - значение таймера
; OCR0A - значение модуля сравнения
; TIFR0 - флаги прерываний от таймера
;-- начало программного кода
      .cseg
      .org 0
      rjmp Init				; переход на начало программы
;-- вектора прерываний
      reti					; INT0
      rjmp PinChange		; Pin Change INT0
	  reti					; Timer1_COMPA
	  reti                  ; Timer1_OVF
      rjmp TimerOverflow	; Timer0 overflow
      reti					; EEPROM ready
      reti					; comparator
	  reti					; ADC complete
	  reti					; Timer1 compare match B
      reti					; timer0 compare match A
      reti					; timer0 compare match B
      reti					; watchdog
      reti					; USI start
      reti					; USI overflow
;-- начало программы
Init: ldi w,low(RAMEND)			; устанавливаем указатель вершины
      ldi Flags,high(RAMEND)	;
      out SPL,w					; стека на старший байт RAM
      out SPH,Flags

      sbi ACSR,7				; выключаем компаратор
	  clr w
	  out DDRB,w				; сначала все ноги на вход
	  out PORTB,w				; во все защёлки - нули (внешняя подтяжка)
	  clr Flags					; очищаем регистр флагов
;-- включить прерывания от ноги InStart
      ldi w,1<<InStart			; выбираем ногу, к которой подключен запускающий вход
      out PCMSK,w
      ldi w,1<<PCIE				; разрешаем прерывание PinChange
	  out GIMSK,w
;-- настраиваем таймер (сколько отводится на изменение сигнала на входе)
      clr w
      out TCCR0A,w		; выходы OCR0A, OCR0B отключены, Normal Mode
      ldi w, 1<<TOIE0	; прерывание по переполнению
	  out TIMSK,w
;-- загружаем значения задержек из EEPROM
//EEPROM_read:
//	  sbic EECR,EEPE
//	  rjmp EEPROM_read	; убеждаемся, что EEPE сброшен (и ждём его сброса)
//	  clr  w			; пишем в w адрес чтения
//	  out EEARL,w
//	  sbi EECR,EERE		; запускаем чтение установкой бита EERE
//	  in  C_2502,EEDR	; сохраняем прочитанный байт
//	  inc w
//	  out EEARL,w
//	  sbi EECR,EERE		; запускаем чтение установкой бита EERE
//	  in  T_2502,EEDR	; сохраняем прочитанный байт
//	  inc w
//	  out EEARL,w
//	  sbi EECR,EERE		; запускаем чтение установкой бита EERE
//	  in  C_1990,EEDR	; сохраняем прочитанный байт
//	  inc w
//	  out EEARL,w
//	  sbi EECR,EERE		; запускаем чтение установкой бита EERE
//	  in  T_1990,EEDR	; сохраняем прочитанный байт

	  ldi C_2502,0xFF
	  ldi T_2502,0xED
	  ldi C_1990,0xE7
	  ldi T_1990,0x64
;-- разрешить прерывания
      sei
;-- начало работы
Work: rjmp Work

;----------------------------------------------------------------------
;----------------------------------------------------------------------
;--- Interrupts ---
PinChange:
;-- проверяем, можно ли запускать алгоритм
	  clr w
	  cpse Flags,w		; если регистр Flags сброшен - можно запускать алгоритм (пропускаем следующую команду)
	  reti
;-- проверяем состояние входа PB2 (InStart), если он ноль - запускаем алгоритм
	  sbic	PINB,InStart
	  reti
;-- проверяем состояния входов InCode1, InCode2 и настраиваем таймер в зависимости от их состояния
	  in w, PINB		; читаем состояние ног порта
	  andi w,0b00011000	; оставляем только PB3, PB4
;-- PB3=0, PB4=1 - для DS2502 (нужен импульс 480-5000 мкс)
;-- PB3=1, PB4=1 - для AN1990 (нужен импульс >100 мс)
	  cpi w,0b00011000	; PB3=1, PB4=1
	  breq AN1990_Init
	  cpi w,0b00010000	; PB3=0, PB4=1
	  breq DS2502_Init
	  reti
AN1990_Init:
      out TCNT0,T_1990				; записываем начальное значение таймера
	  mov Counter,C_1990 			; и начальное значение счетчика
	  sbr Flags,1					; ставим признак, что запущен алгоритм для AN1990 (0-й бит=1)
	  rjmp TimerStart
DS2502_Init:
      out TCNT0,T_2502				; записываем начальное значение таймера
	  mov Counter,C_2502		 	; начальное значение счетчика
	  sbr Flags,2					; ставим признак, что запущен алгоритм для DS2502 (1-й бит=1)
TimerStart:
;-- переключаем PB0 на выход (в защёлке у нас ноль)
	  sbi DDRB, CtrlOut
;-- включаем таймер
      ldi w,0b00000100	; включить таймер, Normal Mode, /256
      out TCCR0B,w
	  reti                  ; выходим

;--- если сработал таймер - увеличиваем счётчик, устанавливаем начальное значение таймера
TimerOverflow:
	  inc Counter
      breq StopAlg
	  sbrc Flags,0
	  rjmp AN1990_Work
	  sbrc Flags,1
	  rjmp DS2502_Work
StopAlg:
	  clr Flags;		; сбрасываем флаги
	  out TCCR0B,Flags	; останавливаем таймер
	  ;-- переключаем PB0 на вход (в защёлке у нас ноль)
	  cbi DDRB, CtrlOut				; переключаем на вход (в защёлке остаётся ноль)
	  reti
AN1990_work:
      out TCNT0,T_1990				; записываем начальное значение таймера
	  reti
DS2502_Work:
      out TCNT0,T_2502				; записываем начальное значение таймера
	  reti

;--------- EPROM ----------
.eseg
.db 0xFF	; CounterDS2502 - количество срабатываний таймера до выключения алгоритма = 256-255=1 (выключится при первом же переполнении, результат 608 мкс)
.db 0xED	; TimerDS2502 - начальное значение таймера = 256-237 = 19 (переполнения происходят 1 раз в 608 мкс)
.db 0xE7	; CounterAN1990 - количество срабатываний таймера до выключения алгоритма = 256-231=25 (выключится при 25-м переполнении, результат 125 мс)
.db 0x64	; TimerAN1990 - начальное значение таймера = 256-100 = 156 (переполнения происходят 1 раз в 4992 мкс)
