;
; Project name: thermostat
; Description: Electronic thermostat on AVR Microcontroller
; Source code: https://github.com/sergeyyarkov/attiny2313a_thermostat
; Device: ATtiny2313A
; Device Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/doc8246.pdf
; Assembler: AVR macro assembler 2.2.7
; Clock frequency: 8 MHz External Crystal Oscillator
; Fuses: lfuse: 0xCF, hfuse: 0xDF, efuse: 0xFF, lock: 0xFF
;
; Written by Sergey Yarkov 01.07.2023
.LIST
.INCLUDE "definitions.asm"
.INCLUDE "macros.asm"
//
; **** СЕГМЕНТ ДАННЫХ ********************************************
.DSEG
.ORG SRAM_START
MCU_STATE: .BYTE 1 ; Текущее состояние МК
SRAM_TEMP_1: .BYTE 2 ; Хранения временного 16-бит числа в ячейке
DIGITS: .BYTE 4 ; Ячейки, где хранятся символы, для вывода на индикатор
CURRENT_DIGIT: .BYTE 1 ; Номер разряда индикатора, который сейчас горит
TEMP_L: .BYTE 1 ; Младший байт температуры
TEMP_H: .BYTE 1 ; Старший байт температуры
TEMP_F: .BYTE 1 ; Дробная часть
SETTING_TEMP_H: .BYTE 1 ; Уставка температуры (старший байт)
SETTING_TEMP_L: .BYTE 1 ; Уставка температуры (младший байт)
SETTING_HYST: .BYTE 1 ; Гистерезис: отклонение от уставки
SETTING_MODE: .BYTE 1 ; Режим работы: '1' - нагрев; '0' - 'охлаждение'
DEVICE_FAMILY_CODE: .BYTE 1 ; Должно быть 0x10 для DS18B20
PROGRAM_STEPS: .BYTE 1 ; Текущий "шаг" для настройки (0 - ничего; 1 - уставка T; 2 - гистерезис)
SW_DATA: .BYTE 1
;//
//
; **** СЕГМЕНТ КОДА **********************************************
.CSEG
//
.ORG 0x00
rjmp RESET_vect
.ORG 0x04
reti
.ORG 0x000B
rjmp PCINT0_vect
.ORG 0x000D
rjmp TIMER0_COMPA_vect
//
//
PCINT0_vect:
push r16
push r17
in r16, SREG
in r17, SW_PIN
; если нажаты две кнопки то входим в режим программирования
andi r17, (1<
//
; **** ДИНАМИЧЕСКАЯ ИНДИКАЦИЯ ************************************
TIMER0_COMPA_vect:
push r16
push r17
push r18
push r19
push r20
push r21
in r21, SREG
lds r20, CURRENT_DIGIT
cpi r20, 5
brge _CLR_CURRENT_DIGIT ; сброс активного разряда если >= 5
rjmp _indicate_1
_CLR_CURRENT_DIGIT: ; сброс текущего активного разряда в ноль
clr r20
sts CURRENT_DIGIT, r20
_indicate_1:
cpi r20, 0
brne _indicate_2
cbi PORTD, DIGIT_2_PIN
cbi PORTD, DIGIT_3_PIN
cbi PORTD, DIGIT_4_PIN
brts PC+2
rjmp PC+3
ldi TEMP_REG_A, 11 ; // -
rjmp PC+3
lds TEMP_REG_A, DIGITS+2
tst TEMP_REG_A
breq PC+3
sbi PORTD, DIGIT_1_PIN
rjmp PC+2
cbi PORTD, DIGIT_1_PIN
rcall DISPLAY_DECODER
rcall USI_TRANSMIT
_indicate_2:
cpi r20, 1
brne _indicate_3
cbi PORTD, DIGIT_1_PIN
cbi PORTD, DIGIT_3_PIN
cbi PORTD, DIGIT_4_PIN
lds TEMP_REG_A, DIGITS+1
lds r19, DIGITS+2
or TEMP_REG_A, r19
breq PC+3
sbi PORTD, DIGIT_2_PIN
rjmp PC+2
cbi PORTD, DIGIT_2_PIN
lds TEMP_REG_A, DIGITS+1
rcall DISPLAY_DECODER
rcall USI_TRANSMIT
_indicate_3:
cpi r20, 2
brne _indicate_4
cbi PORTD, DIGIT_1_PIN
cbi PORTD, DIGIT_2_PIN
cbi PORTD, DIGIT_4_PIN
sbi PORTD, DIGIT_3_PIN
lds TEMP_REG_A, DIGITS
rcall DISPLAY_DECODER
rcall USI_TRANSMIT
_indicate_4:
cpi r20, 3
brne _indicate_exit
cbi PORTD, DIGIT_1_PIN
cbi PORTD, DIGIT_2_PIN
cbi PORTD, DIGIT_3_PIN
sbi PORTD, DIGIT_4_PIN
lds TEMP_REG_A, DIGITS+3
rcall DISPLAY_DECODER
rcall USI_TRANSMIT
_indicate_exit:
inc r20
sts CURRENT_DIGIT, r20
out SREG, r21
pop r21
pop r20
pop r19
pop r18
pop r17
pop r16
reti
;//
; **** СТАРТ ПРОГРАММЫ *******************************************
RESET_vect:
ldi TEMP_REG_A, LOW(RAMEND)
out SPL, TEMP_REG_A
//
; **** ПРОЦЕСС ИНИЦИАЛИЗАЦИИ МК **********************************
MCU_INIT:
; **** ИНИЦИАЛИЗАЦИЯ ПИНОВ *************************************
outi r16, DDRD, (1<
//
; **** ГЛАВНЫЙ ЦИКЛ **********************************************
LOOP:
lds r16, MCU_STATE ; получаем текущее состояние МК
_STATE_DEFAULT:
cpi r16, MCU_STATE_DEFAULT
brne _STATE_PROGRAM
lds r18, TEMP_F
sts DIGITS+3, r18
rcall TEMP_UPD ; обновление данных о температуре
rcall DISPLAY_UPD_DIGITS
rcall TEMP_COMPARSION ; логика термостата
outi r17, TIMSK, (1<
; **** ПОДПРОГРАММЫ **********************************************
.INCLUDE "div16u.asm"
.INCLUDE "div8u.asm"
.INCLUDE "mpy16u.asm"
//
TEMP_SEND_UART:
push r16
push r17
; целая часть
lds r16, TEMP_L
mov r5, r16
rcall UART_WR_BYTE
; дробная часть
lds r16, TEMP_F
mov r5, r16
rcall UART_WR_BYTE
; состояние реле
in r16, PIND
andi r16, (1<
//
UART_WR_BYTE:
sbis UCSRA, UDRE
rjmp UART_WR_BYTE
out UDR, r5
ret
//
//
INIT_DEFAULT_PARAMS:
ldi r16, DEFAULT_SETTING_TEMP_H
sts SETTING_TEMP_H, r16 ; уставка HIGH
mov EEP_D_r, r16
ldi r16, EEP_SETTING_TEMP_H
mov EEP_A_r, r16
rcall EEP_WR_BYTE
ldi r16, DEFAULT_SETTING_TEMP_L
sts SETTING_TEMP_L, r16 ; уставка LOW
mov EEP_D_r, r16
ldi r16, EEP_SETTING_TEMP_L
mov EEP_A_r, r16
rcall EEP_WR_BYTE
ldi r16, DEFAULT_SETTING_HYST
sts SETTING_HYST, r16 ; гистерезис
mov EEP_D_r, r16
ldi r16, EEP_SETTING_HYST
mov EEP_A_r, r16
rcall EEP_WR_BYTE
ldi r16, DEFAULT_SETTING_MODE
sts SETTING_MODE, r16 ; режим
mov EEP_D_r, r16
ldi r16, EEP_SETTING_MODE
mov EEP_A_r, r16
rcall EEP_WR_BYTE
ldi r16, 0x10
mov EEP_D_r, r16
ldi r16, EEP_FIRST_TIME_RUN
mov EEP_A_r, r16
rcall EEP_WR_BYTE
ret
//
//
WRITE_PARAMS_TO_EEP:
push r16
lds r16, SETTING_TEMP_H ; уставка HIGH
mov EEP_D_r, r16
ldi r16, EEP_SETTING_TEMP_H
mov EEP_A_r, r16
rcall EEP_WR_BYTE
lds r16, SETTING_TEMP_L ; уставка LOW
mov EEP_D_r, r16
ldi r16, EEP_SETTING_TEMP_L
mov EEP_A_r, r16
rcall EEP_WR_BYTE
lds r16, SETTING_HYST ; гистерезис
mov EEP_D_r, r16
ldi r16, EEP_SETTING_HYST
mov EEP_A_r, r16
rcall EEP_WR_BYTE
lds r16, SETTING_MODE ; режим
mov EEP_D_r, r16
ldi r16, EEP_SETTING_MODE
mov EEP_A_r, r16
rcall EEP_WR_BYTE
pop r16
ret//
//
EEP_WR_BYTE:
cli
push r16
_EEP_WR_BYTE_LP:
; ждем завершения предыдущей записи
sbic EECR, EEPE
rjmp _EEP_WR_BYTE_LP
; режим программирования - атомарный
ldi r16, (0<
//
TEMP_COMPARSION:
push r16
push r17
push r18
push r19
push r20
push r21
push r23
.DEF temp_r_l = r16
.DEF temp_r_h = r17
.DEF min_r_trhd_l = r11
.DEF min_r_trhd_h = r10
.DEF max_r_trhd_l = r13
.DEF max_r_trhd_h = r12
; умножаем температуру на 10
lds mc16uL, TEMP_L // r16
lds mc16uH, TEMP_H // r17
ldi mp16uL, LOW(10)
ldi mp16uH, HIGH(10)
rcall mpy16u
mov temp_r_l, m16u0 ; L
mov temp_r_h, m16u1 ; H
; добавляем дробную часть
lds r18, TEMP_F
clr r19
add temp_r_l, r18
adc temp_r_h, r19
; определяем нижний и верхний пороги
lds r20, SETTING_TEMP_L
lds r21, SETTING_TEMP_H
lds r22, SETTING_HYST
push r20
push r21
clr r23
sub r20, r22
sbc r21, r23
mov min_r_trhd_l, r20
mov min_r_trhd_h, r21
pop r21
pop r20
clr r23
add r20, r22
adc r21, r23
mov max_r_trhd_l, r20
mov max_r_trhd_h, r21
; определяем знак температуры
brts _NEGATE_TEMP
rjmp _COMPARE
_NEGATE_TEMP:
com temp_r_l
com temp_r_h
subi temp_r_l, low(-1)
sbci temp_r_h, high(-1)
_COMPARE:
; проверяем нижний порог
cp min_r_trhd_l, temp_r_l
cpc min_r_trhd_h, temp_r_h
brge _MIN_THRESHOLD ; TEMP <= MIN
; проверяем верхний порог
cp temp_r_l, max_r_trhd_l
cpc temp_r_h, max_r_trhd_h
brge _MAX_THRESHOLD ; TEMP >= TOP
rjmp _COMPARSION_EXIT
_MIN_THRESHOLD:
; определяем режим работы
lds r20, SETTING_MODE
tst r20
brne PC+3
relay_off
rjmp PC+2
relay_on
rjmp _COMPARSION_EXIT
_MAX_THRESHOLD:
lds r20, SETTING_MODE
tst r20
brne PC+3
relay_on
rjmp PC+2
relay_off
_COMPARSION_EXIT:
pop r23
pop r21
pop r20
pop r19
pop r18
pop r17
pop r16
ret
//
//
TEMP_UPD:
push r17
rcall TEMP_CONV
DELAY24 751000
rcall TEMP_RD
; обновляем данные в ячейках
lds r17, TEMP_L
mov DISP_NUM_L, r17
lds r17, TEMP_H
mov DISP_NUM_H, r17
pop r17
ret
//
//
RD_F_CODE:
push r16
rcall OW_PRESENCE
ldi r16, DS18B20_CMD_READROM
mov OW_CMD_r, r16
rcall OW_SEND_BYTE
ldi XL, LOW(DEVICE_FAMILY_CODE)
ldi XH, HIGH(DEVICE_FAMILY_CODE)
rcall OW_RD_BYTE
pop r16
ret//
//
TEMP_RD:
push r16
push r17
push r18
push r19
push r20
rcall OW_PRESENCE
sbrs OWFR, OWPRF
rjmp _TEMP_RD_EXIT
ldi r16, DS18B20_CMD_SKIPROM
mov OW_CMD_r, r16
rcall OW_SEND_BYTE
ldi r16, DS18B20_CMD_RSCRATCHPAD
mov OW_CMD_r, r16
rcall OW_SEND_BYTE
ldi XL, LOW(TEMP_L)
ldi XH, HIGH(TEMP_L)
rcall OW_RD_BYTE
ldi XL, LOW(TEMP_H)
ldi XH, HIGH(TEMP_H)
rcall OW_RD_BYTE
lds r17, TEMP_L
lds r18, TEMP_H
push r18
cbr r18, (1<<0) | (1<<1) | (1<<2) ; убираем ненужные биты на время (интересуют последних битов в TEMP_H)
cpi r18, 0xf8 ; проверяется является ли число минусовой
breq _TEMP_RD_TO_UNSIGNED ; если да то конвертируем в беззнаковое число
clt
rjmp _TEMP_RD_CONTINUE ; если нет то преобразуем значение АЦП в температуру (делим на 16)
_TEMP_RD_TO_UNSIGNED:
pop r18
set
com r17
com r18
subi r17, low(-1)
sbci r18, high(-1)
; ldi r19, 1
; add r17, r19
; ldi r19, 0
; adc r18, r19
rjmp PC+2
_TEMP_RD_CONTINUE: ; Температура = Число с АЦП / 16 (сдвиг вправо 4)
pop r18
lsr r18
ror r17
lsr r18
ror r17
lsr r18
ror r17
lsr r18
ror r17
_TEMP_RD_END:
lds r19, TEMP_L
brtc PC+2
neg r19 ; переводим в беззнаковое число если минус
; далее происходит такое для получения дробной части:
; ((n<<3) + (n<<1))>>4 или (n*10)/16
mov r20, r19
andi r19, 0x0f
mov r20, r19
lsl r19
lsl r19
lsl r19
lsl r20
add r19, r20
lsr r19
lsr r19
lsr r19
lsr r19
; записываем данные
sts TEMP_L, r17
sts TEMP_H, r18
sts TEMP_F, r19
_TEMP_RD_EXIT:
pop r20
pop r19
pop r18
pop r17
pop r16
ret
;
TEMP_CONV:
push r16
rcall OW_PRESENCE
sbrs OWFR, OWPRF
rjmp _TEMP_CONV_EXIT
ldi r16, DS18B20_CMD_SKIPROM
mov OW_CMD_r, r16
rcall OW_SEND_BYTE
ldi r16, DS18B20_CMD_CONVERTTEMP
mov OW_CMD_r, r16
rcall OW_SEND_BYTE
_TEMP_CONV_EXIT:
pop r16
ret
//
//
; **** ОТПРАВКА БАЙТА В СДВИГОВЫЙ РЕГИСТР *************************
USI_TRANSMIT:
push r16
push r0
out USIDR, r0 ; Байт для отправки всегда находится в регистре r0. Помещаем данные в регистр USIDR.
; Enable USI Overflow Interrupt Flag (will be 0 if transfer is not compeleted)
ldi TEMP_REG_A, (1< USI Wire Mode
; USICS1 <--------------> USI Clock Source Select
; USICLK <--------------> USI Clock Strobe
; USITC <--------------> USI Toggle Clock (Enable clock generation)
ldi TEMP_REG_A, (1<
//
BUTTON_PROCESS:
push r16
_SW_CHECK_ON_0:
sbis SW_PIN, SW_SET_PIN
rjmp _SW_SET_0
rjmp _SW_CHECK_ON_1
_SW_SET_0:
lds r16, SW_DATA
tst r16
brne _SW_SET_FROM_0_TO_1
rjmp _SW_CHECK_ON_1
_SW_SET_FROM_0_TO_1:
clr r16
sts SW_DATA, r16
rcall DEBOUNCE_SW
inc REPROGRAM_STEP_r
mov r17, REPROGRAM_STEP_r
cpi r17, 4
brge _SAVE_SETTINGS
rcall BEEP_SHORT
rjmp _SW_CHECK_ON_1
_SAVE_SETTINGS:
outi r17, TIMSK, (0<
//
REPROGRAM_SETTINGS:
push r16
push r17
push r18
push r19
push r20
mov r16, REPROGRAM_STEP_r
tst r16
breq _INTO
rjmp _REPROGRAM_SETTINGS_LOOP
_INTO:
relay_off
sbi PORTD, LED_PGM_PIN
rcall BEEP_SHORT
inc REPROGRAM_STEP_r
_REPROGRAM_SETTINGS_LOOP:
rcall BUTTON_PROCESS
_CHECK_STEP:
cpi r16, 1
breq _STEP_1
cpi r16, 2
breq _STEP_2
cpi r16, 3
breq _S3_JMP
rjmp _REPROGRAM_SETTINGS_END
//
_STEP_1: ; установка и отображение гистерезиса
rcall DISPLAY_UPD_DIGITS
_S1_CHECK_PLUS:
sbis SW_PIN, SW_PLUS_PIN
rjmp _INCREASE_HYST
rjmp _S1_CHECK_MINUS
_S1_CHECK_MINUS:
sbis SW_PIN, SW_MINUS_PIN
rjmp _DECREASE_HYST
rjmp _SHOW_HYST
_INCREASE_HYST:
rcall DEBOUNCE_SW
lds r17, SETTING_HYST
cpi r17, MAX_HYST
breq PC+2
inc r17
sts SETTING_HYST, r17
rjmp _SHOW_HYST
_DECREASE_HYST:
rcall DEBOUNCE_SW
lds r17, SETTING_HYST
cpi r17, MIN_HYST
breq PC+2
dec r17
sts SETTING_HYST, r17
_SHOW_HYST:
clt
push dd8u
push dv8u
lds dd8u, SETTING_HYST
ldi dv8u, 10
rcall div8u
mov DISP_NUM_L, dres8u
clr DISP_NUM_H ; гистерезис 8 битный так что ноль пишем в старший байт
sts DIGITS+3, drem8u
pop dv8u
pop dd8u
rjmp _REPROGRAM_SETTINGS_END
//
_S3_JMP: ; просто прыжок на _STEP_3
rjmp _STEP_3
//
_STEP_2:
rcall DISPLAY_UPD_DIGITS
_S2_CHECK_PLUS:
sbis SW_PIN, SW_PLUS_PIN
rjmp _INCREASE_TEMP
rjmp _S2_CHECK_MINUS
_S2_CHECK_MINUS:
sbis SW_PIN, SW_MINUS_PIN
rjmp _DECREASE_TEMP
rjmp _SHOW_TEMP
_INCREASE_TEMP:
rcall DEBOUNCE_SW
lds r17, SETTING_TEMP_L
lds r18, SETTING_TEMP_H
cpi r17, MAX_TEMP_L
ldi r19, MAX_TEMP_H
cpc r18, r19
breq PC+7
ldi r19, 10
add r17, r19
clr r19
adc r18, r19
sts SETTING_TEMP_L, r17
sts SETTING_TEMP_H, r18
rjmp _SHOW_TEMP
_DECREASE_TEMP:
rcall DEBOUNCE_SW
lds r17, SETTING_TEMP_L
lds r18, SETTING_TEMP_H
cpi r17, MIN_TEMP_L
ldi r19, MIN_TEMP_H
cpc r18, r19
breq PC+3
__DECREASE:
subi r17, 10
sbci r18, 0
sts SETTING_TEMP_L, r17
sts SETTING_TEMP_H, r18
_SHOW_TEMP:
push dd16uL
push dd16uH
push dv16uL
push dv16uH
lds dd16uL, SETTING_TEMP_L
lds dd16uH, SETTING_TEMP_H
mov r18, dd16uH
andi r18, (1<<7)
brne _NEGATE_SET_TEMP
clt
rjmp _DIVIDE_SET_TEMP
_NEGATE_SET_TEMP:
set
com16 dd16uL, dd16uH
_DIVIDE_SET_TEMP:
ldi dv16uL, LOW(10)
ldi dv16uH, HIGH(10)
rcall div16u
mov DISP_NUM_L, dres16uL
mov DISP_NUM_H, dres16uH
ldi r16, 10
sts DIGITS+3, r16 ; значок градуса
pop dv16uH
pop dv16uL
pop dd16uH
pop dd16uL
rjmp _REPROGRAM_SETTINGS_END
//
//
_STEP_3:
clt
_S3_CHECK_PLUS:
sbis SW_PIN, SW_PLUS_PIN
rjmp _SET_HEAT_MODE
rjmp _S3_CHECK_MINUS
_S3_CHECK_MINUS:
sbis SW_PIN, SW_MINUS_PIN
rjmp _SET_COOLING_MODE
rjmp _SHOW_MODE
_SET_HEAT_MODE:
rcall DEBOUNCE_SW
ldi r17, HEAT_MODE
sts SETTING_MODE, r17
rjmp _SHOW_MODE
_SET_COOLING_MODE:
rcall DEBOUNCE_SW
ldi r17, COOLING_MODE
sts SETTING_MODE, r17
_SHOW_MODE:
clr r17
mov DISP_NUM_L, r17
mov DISP_NUM_H, r17
ldi r17, 14
sts DIGITS, r17
sts DIGITS+1, r17
sts DIGITS+2, r17
lds r18, SETTING_MODE
tst r18
breq _SHOW_COOLING
rjmp _SHOW_HEATING
_SHOW_COOLING:
ldi r17, 12
sts DIGITS+3, r17
rjmp _REPROGRAM_SETTINGS_END
_SHOW_HEATING:
ldi r17, 13
sts DIGITS+3, r17
//
_REPROGRAM_SETTINGS_END:
pop r20
pop r19
pop r18
pop r17
pop r16
ret
//
//
//
; **** ОПРОС ПРИСУТСТВИЯ УСТРОЙСТВА ******************************
OW_PRESENCE:
cli
ow_pull
DELAY16 480
ow_release
DELAY16 70
rcall OW_CHECK_PRESENCE
DELAY16 410
sei
ret
//
//
; **** ПРОВЕРКА НАЛИЧИЯ УСТРОЙСТВА *******************************
; Если подчиненное устройство притянет шину, то устанавливаем флаг OWPRF в единицу в регистре флагов
;
OW_CHECK_PRESENCE:
sbis OW_PIN, OW_LINE
sbr OWFR, (1<
//
OW_SEND_BYTE:
cli
push r16
push r17
mov r16, OW_CMD_r
ldi r17, 8
_OW_SEND_BYTE_LOOP:
lsr r16
brcc _OW_SEND_0
brcs _OW_SEND_1
_OW_SEND_0:
ow_pull
DELAY16 60
ow_release
DELAY16 10
rjmp _OW_SEND_BYTE_END
_OW_SEND_1:
ow_pull
DELAY16 6
ow_release
DELAY16 64
_OW_SEND_BYTE_END:
dec r17
brne _OW_SEND_BYTE_LOOP
pop r17
pop r16
sei
ret
//
//
OW_RD_BYTE:
cli
push r16
push r17
clr r16
ldi r17, 8
_OW_RD_BYTE_LP:
lsr r16
ow_pull
DELAY16 6
ow_release
DELAY16 9
sbic OW_PIN, OW_LINE
sbr r16, (1<<7)
DELAY16 55
dec r17
brne _OW_RD_BYTE_LP
st X, r16
pop r17
pop r16
sei
ret
//
//
//
; **** ПОЛУЧЕНИЕ ЦИФР ИЗ 16-ТИ БИТНОГО ЧИСЛА *********************
; Описание: Перемещает цифры числа в соответствующие ячейки памяти в SRAM
; путем деления этого числа несколько раз
DISPLAY_UPD_DIGITS:
push r16
push r21
ldi r21, 3
; инициализация указателя (за каждый проход цикла будет инкрементироваться)
ldi XL, LOW(DIGITS)
ldi XH, HIGH(DIGITS)
.equ dividend = SRAM_TEMP_1 ; число которе будем делить
.equ divisor = 10 ; на что делим
; загружаем число которое хотим поделить в адрес SRAM делимого
sts dividend, DISP_NUM_L
sts dividend+1, DISP_NUM_H
; четыре раза производим деление для получения остатков
DIV_LOOP:
; заполняем нужные регистры
lds dd16uL, dividend
lds dd16uH, dividend+1
ldi dv16uL, LOW(divisor)
ldi dv16uH, HIGH(divisor)
rcall div16u ; делим
st X+, drem16uL ; сохраняем остаток в ячейку по указателю и увеличиваем его
; обновляем делимое
sts dividend, dres16uL
sts dividend+1, dres16uH
dec r21 ; декрементируем счетчик цикла
brne DIV_LOOP ; делим еще раз если не 0
pop r21
pop r16
ret
//
//
; **** ЗАГРУЖАЕТ НУЖНЫЙ АДРЕС СИМВОЛА В R0 ***********************
DISPLAY_DECODER:
push r16
push r17
ldi ZL, LOW(2*DISPLAY_SYMBOLS)
ldi ZH, HIGH(2*DISPLAY_SYMBOLS)
clr TEMP_REG_B
add ZL, TEMP_REG_A
adc ZH, TEMP_REG_B
lpm r0, Z
lds r16, CURRENT_DIGIT
cpi r16, 2
breq _DOT_ON
rjmp _DISPLAY_DECODER_EXIT
_DOT_ON:
mov r16, r0
cbr r16, (1<<7)
mov r0, r16
mov r16, REPROGRAM_STEP_r
cpi r16, 2
brge _DOT_OFF
lds r16, MCU_STATE
cpi r16, MCU_STATE_ERROR
breq _ERR_DOT_OFF
rjmp _DISPLAY_DECODER_EXIT
_DOT_OFF:
mov r16, r0
sbr r16, (1<<7)
mov r0, r16
rjmp _DISPLAY_DECODER_EXIT
_ERR_DOT_OFF:
rjmp _DOT_OFF
_DISPLAY_DECODER_EXIT:
pop r17
pop r16
ret
//
//
BEEP_SHORT:
sbi BUZZER_PORT, BUZZER_PIN
DELAY24 150000
cbi BUZZER_PORT, BUZZER_PIN
ret
//
//
BEEP_LONG:
sbi BUZZER_PORT, BUZZER_PIN
DELAY24 500000
cbi BUZZER_PORT, BUZZER_PIN
ret
//
//
DEBOUNCE_SW:
push r16
push r17
push r18
ldi r18, 10
_loop_2:
ldi r17, 255
_loop_0:
ldi r16, 255
_dec_0:
dec r16
brne _dec_0
_loop_1:
dec r17
brne _loop_0
_loop_3:
dec r18
brne _loop_2
pop r18
pop r17
pop r16
ret//
//
DELAY_LOOP_16:
subi DELAY_8_r, 1
sbci DELAY_16_r, 0
brcc DELAY_LOOP_16
ret
//
//
DELAY_LOOP_24:
subi DELAY_8_r, 1
sbci DELAY_16_r, 0
sbci DELAY_24_r, 0
brcc DELAY_LOOP_24
ret
//
//
DISPLAY_SYMBOLS:
; HGFEDCBA HGFEDCBA
.DB 0b11000000, 0b11111001 ; 0, 1
.DB 0b10100100, 0b10110000 ; 2, 3
.DB 0b10011001, 0b10010010 ; 4, 5
.DB 0b10000010, 0b11111000 ; 6, 7
.DB 0b10000000, 0b10010000 ; 8, 9
.DB 0b10011100, 0b10111111 ; °, -
.DB 0b11000110, 0b10001001 ; C, H
//
//
//
; **** СЕГМЕНТ EEPROM ********************************************
.ESEG
.ORG 0x30
INFO: .DB "AVR Thermostat. Written by Sergey Yarkov"
;