.Include "tn2313def.inc"

.def Num1Out=r0 ;Первый разряд индикатора
.def Num2Out=r1 ;Второй разряд индикатора
.def Key=r2 ;Номер нажатой кнопки
.def Tmp1=r16 ;Для временного хранения значений
.def Tmp2=r17 ;Для временного хранения значений
.def Tmp3=r18 ;Для временного хранения значений
.def Value=r19 ;Текущее значение температуры (или задания, в режиме настройки)

.dseg
KeyRepet: .byte 1 ;Защита от повторного нажатия
KeyRetesting: .byte 1 ;Автоповтор нажатой кнопки
EnterSetup: .byte 1 ;Индикатор режима установки нового значения
Hysteresis: .byte 1	;Значение гистерезиса
SC: .byte 10 ;Коды 7-сегментного индикатора
JobTemp: .byte 1 ;Температура стабилизации
OldJobTemp: .byte 1	;В режиме настройки сюда копируется старое задание, чтоб его можно было сравнить с новым
HeatingCoolingLed: .byte 1 ;Индикатор включения отключения

.cseg
.org 0

... ;Тут векторы прерываний
reti

;################################
Reset: ;Начальная инициализация #
;################################
   ldi Tmp1, low(RAMEND) ;Устанавливаем указатель стека
   out spl, Tmp1
  
   ...

   Настройка портов
   
   ...
    
   ldi Tmp1, 0 ;Адрес на чтение EEPROM
   Out EEAR, Tmp1 ;Устанавливаем в 0
   sbi EECR, EERE ;Просим прочитать
   In Tmp1, EEDR ;Копируем прочитаное во временный регистр
   sts JobTemp, Tmp1 ;Сохраняем прочитаное в ОЗУ

   dec Tmp1
   sts Hysteresis, Tmp1 ;Вычисляем гистерезис
   
   ldi Tmp1, 0b00000101
   out TCCR1B, Tmp1 ;Пределитель таймера 1024

   ldi Tmp1, 0xCC
   out OCR1AH, Tmp1	;Загружаем старший байт компаратора
   out OCR1AL, Tmp1	;Загружаем младший байт компаратора

   ldi Tmp1, 0
   sts KeyRetesting, Tmp1 ;Очищаем флаги и счетчики
   sts EnterSetup, Tmp1 ;Очищаем флаг режима установки
   sts KeyRepet, Tmp1 ;Очищаем флаг повтора
   ldi Value, 88 ;Загружаем в регистр хранения температуры начальное число

   ldi Tmp1, 0b10000100
   sts SC+0, Tmp1 ;Сохраняем 7-сегментный 0 код в ОЗУ
   ...
   ldi Tmp1, 0b10010000
   sts SC+9, Tmp1 ;Сохраняем 7-сегментный 9 код в ОЗУ
   
   SEI
   
;#####################
Main: ;Основной цикл #
;#####################
   lds Tmp1, EnterSetup
   SBRC Tmp1, 0 ;Если установлен флаг настройки, пропускаем опрос датчика
  rjmp SkipInquireDS

  rcall DS1820 ;Считываем текущую температуру
  rcall TemperatureCheck ;Проверяем на достижения порогов срабатывания

SkipInquireDS:
  rcall Decode ;Преобразуем число(температуру) в 7-сегментный код
  rcall BigDelay ;Ждем некоторое время
  rcall OutValue ;Выводим индикацию
  rjmp KeyState	;Опрашиваем кнопочки		  
rjmp main

;#############################
OutValue: ;Выводим результат #
;#############################

Вывод Num1Out и Num2Out на индикатор

ret ;Возвращаемся в основной цикл

;#################################################
TemperatureCheck: ;Проверка на достижения порога #
;#################################################
   lds Tmp1, JobTemp ;Загружаем в переменную верхний температурный порог
   CP Value, Tmp1 ;Сравниваем с текущим значением температуры
   BRSH	SwitchOffHeating ;Если порог достигнут, вызываем функцию отключения нагревателя

   lds Tmp1, Hysteresis	;Загружаем в переменную гистерезис
   CP Value, Tmp1 ;Сравниваем с текущим значением температуры
   BRLO	SwitchOnHeating	;Если порог достигнут, вызываем функцию включения нагревателя
ret ;Возвращаемся в основной цикл

;########################################
SwitchOnHeating: ;Включение нагревателя # 
;########################################
   SBI PortB, 4
   ldi Tmp1, 0b10000000
   sts HeatingCoolingLed, Tmp1 
ret ;Возвращаемся в основной цикл

;##########################################
SwitchOffHeating: ;Отключение нагревателя #
;##########################################
   CBI PortB, 4
   ldi Tmp1, 0
   sts HeatingCoolingLed, Tmp1
ret ;Возвращаемся в основной цикл

;######################################
KeyState: ;Проверяем состояние кнопок #
;######################################
   In Key, PinD ;Считываем состояние порта

   SBRS Key, 0 ;Если кнопка нажата, вызываем процедуру проверки
  rjmp KeyCheck

   SBRS Key, 1 ;Если кнопка нажата, вызываем процедуру проверки
  rjmp KeyCheck

   ldi Tmp1, 0
   sts KeyRepet, Tmp1 ;Если ничего не нажато, сбрасываем флаг повтора
   sts KeyRetesting, Tmp1 ;Обнуляем счетчик автоповтора

KeyStateExit:
rjmp Main

;#######################################################
KeyAutoRepetition: ;Функция автоповтора нажатой кнопки #
;#######################################################
   lds Tmp2, KeyRetesting
   inc Tmp2
   sts KeyRetesting, Tmp2 
   CPI Tmp2, 13	;Если в течении 13 циклов опроса кнопка была нажата, сбрасываем флаг повтора
   BRSH ResetKeyRepet
ret

ResetKeyRepet:
   ldi Tmp2, 0
   sts KeyRepet, Tmp2 ;Сбрасываем флаг повтора
ret

;#######################################################
KeyCheck: ;Проверка на повтор и вход в режим установки #
;#######################################################
   rcall KeyAutoRepetition

   lds Tmp1, KeyRepet 
   CPI Tmp1, 1
   BREQ KeyStateExit ;Если флаг повтора установлен, ничего не делаем
   
   ldi Tmp1, 1
   sts KeyRepet, Tmp1 ;Устанавливаем флаг повтора

   lds Tmp1, EnterSetup
   CPI Tmp1, 0 ;Если режим установки не включен
   BREQ SetupActivity ;Быстренько его включаем
   
   ldi Tmp1, 0
   out TCNT1H, Tmp1 ;Обнуляем старший байт счетчика
   out TCNT1L, Tmp1 ;Обнуляем младший байт счетчика

   SBRC Key, 0
  rjmp KeyUp

   SBRC Key, 1
  rjmp KeyDown
rjmp Main

;###########################
KeyUp: ;Увеличить значение #
;###########################
   lds Tmp1, JobTemp
   inc Tmp1
   sts JobTemp, Tmp1
   mov Value, Tmp1
rjmp Main 

;#############################
KeyDown: ;Уменьшить значение #
;#############################
   lds Tmp1, JobTemp
   dec Tmp1
   sts JobTemp, Tmp1
   mov Value, Tmp1
rjmp Main

;###########################################
SetupActivity: ;Установить режим настройки #
;###########################################
   ldi Tmp1, 0
   out TCNT1H, Tmp1 ;Обнуляем старший байт счетчика
   out TCNT1L, Tmp1 ;Обнуляем младший байт счетчика

   sts HalfDeg, Tmp1 ;Очищаем флаг половины градуса, чтоб не мешал индицировать режим установки
   
   ldi Tmp1, 1
   sts EnterSetup, Tmp1	;Устанавливаем флаг режима установки
   
   lds Value, JobTemp
   sts OldJobTemp, Value 

   ldi Tmp1, 0b01000000
   out TIMSK, Tmp1 ;Разрешаем прерывание компаратора таймера 1
rjmp Main

;############################################
TIM1_COMPA: ;Прерывание таймера компаратора #
;############################################
   push Tmp1
   In Tmp1, SREG
   push	Tmp1
   push Tmp2
   push Tmp3

   ldi Tmp1, 0
   out TIMSK, Tmp1
   sts EnterSetup, Tmp1
   sts BlinkDelay, Tmp1

   lds Tmp1, OldJobTemp	;Загружаем в переменную значение старого задания
   lds Tmp2, JobTemp ;Загружаем в переменную значение нового задания
   CP Tmp1, Tmp2 ;Сравниваем, если не равны, значит задание поменялось 
   BRNE	SaveNewThreshold ;Переходим на процедуру сохранения нового задания
   
   ldi Tmp1, 0b10100010	;Загружаем в переменную 7-сегментный код буквы 'Н'
   mov Num1Out, Tmp1 ;Копируем код в регистр для вывода на индикатор
   ldi Tmp1, 0b11000101	;Загружаем в переменную 7-сегментный код буквы 'С'
   mov Num2Out, Tmp1 ;Копируем код в регистр для вывода на индикатор
   rcall OutValue ;Выводим на индикатор 'НС' (Не Сохранено)

ExitInterrupt:
   pop Tmp3
   pop Tmp2
   pop Tmp1
   out SREG, Tmp1
   pop Tmp1
reti

SaveNewThreshold: ;Процедура сохранения нового задания
   ldi Tmp1, 0 ;Загружаем в переменную адрес ячейки EEPROM для сохранения
   lds Tmp2, JobTemp ;Загружаем в переменную данные для сохранения в EEPROM
   sts OldJobTemp, Tmp2	;
   Out EEAR, Tmp1 ;Выводим в регистр адрес ячейки для сохранения
   Out EEDR, Tmp2 ;Выводим в регистр данные для сохранения
   sbi EECR, EEMWE ;Разрешение записи
   sbi EECR, EEWE ;Строб на запись
   dec Tmp2	;Вычисляем гистирезис
   sts Hysteresis, Tmp2	;Сохраняем вычисленный гистерезис

   ldi Tmp1, 0b10010010 ;Загружаем в переменную 7-сегментный код буквы 'У'
   mov Num1Out, Tmp1 ;Копируем код в регистр для вывода на индикатор
   ldi Tmp1, 0b11000101	;Загружаем в переменную 7-сегментный код буквы 'С'
   mov Num2Out, Tmp1 ;Копируем код в регистр для вывода на индикатор
   rcall OutValue ;Выводим на индикатор 'УС' (Успешно Сохранено)
   rcall BigDelay ;Небольшая пауза, чтоб надпись успели прочитать :)
rjmp ExitInterrupt

;#################################################
Decode: ;Преобразования числа в 7-сегментный код #
;#################################################

Число из регистра Value, преобразуется в код для 7-сегментного идикатора
Значения сохраняются в Num1Out, Num2Out

ret ;Вернуться в основной цикл

;#######################
DS1820:	;Опрос датчика #
;#######################
Считывается значение температуры и сохраняется в Value
ret ;Вернуться в основной цикл

;#########################
BigDelay: ;Большая пауза #
;#########################

1/4 секунды

ret ;Вернуться в основной цикл