Решил я собрать термометр на tiny2313 на датчике DS1820, взял за основу статью http://radiokot.ru/circuit/digital/home/12/
Кварц мне нужен на 10МГц поэтому пришлось переделать процедуры задержки. Вывод температуры хочу произвести на лапках PortB (это пока, в планах дисплейчик приколхозить, но надо еще разобраться что и как с ним делать), т.е. двоичное число, соответствующее температуре. Короче говоря, я пытался немного переделать под нужды моего проекта, но Proteus был против...
Может быть кот ученый сможет мне подсказать...
Программа:
- .include "2313def.inc"
.include "ds1820.inc" ;команды датчика
.def rot = r17
.def Temp = r16
.def Temp1 = r18
.def Temp2 = r19
.def Temp3 = r20
.def Temp4 = r21
.dseg
buffer: .byte 9 ;9 байт буфера приема
CRC: .byte 1 ;расчитываемая контр.сумма
.cseg
.org 0
rjmp Reset ;вектора прерываний
rjmp INT_0
rjmp INT_1
rjmp Timer1_capt1
rjmp Timer1_comp1
rjmp Timer1_OVF1
rjmp Timer0_OVF0
rjmp UART_RX
rjmp UART_UDRE
rjmp UART_TX
rjmp ANA_COMP
;Reset:
INT_0:
INT_1:
Timer1_capt1:
;Timer1_comp1:
Timer1_OVF1:
Timer0_OVF0:
UART_RX:
UART_UDRE:
UART_TX:
ANA_COMP:
reti
;==========
.macro Send_1w
;отправка в линию 1-Wire
ldi Temp, @0 ;первый параметр
mov r0, Temp
rcall Send1w ; вывод
.endmacro
;==========
.macro popf ;извлечение SREG
pop Temp
out SREG, Temp
pop Temp
.endmacro
.macro pushf ;сохранение SREG
push Temp
in Temp, SREG
push Temp
.endmacro
;==========
;*********************************************************************
; задержка в X мкс
;*********************************************************************
.macro delayXmks ;присваиваем имя макросу - « delay »
ldi XL,Low (@0) ;Загрузить младший байт константы времени
ldi XH,high(@0) ;Загрузить старший байт константы времени
delay_:
ldi Temp1,4
Loop: dec Temp1 ;в сумме это 10 команд, которые будут выполняться X раз, т.е. X мкс
brne Loop
sbiw XL,1 ;вычитаем единицу из двухбайтного слова загруженного в регистровую пару Х
brne delay_
.endm ;конец макроса
;*********************************************************************
; задержка в X мс
;*********************************************************************
.macro delayXms ;присваиваем имя макросу - « delay »
ldi YL,Low (@0) ;Загрузить младший байт константы времени
ldi YH,high(@0) ;Загрузить старший байт константы времени
delay_1:
delayXmks 1000
sbiw YL,1 ;вычитаем единицу из двухбайтного слова загруженного в регистровую пару Х
brne delay_1
.endm ;конец макроса
;****************************************************
; ИНИЦИАЛИЗАЦИЯ
;****************************************************
Reset: ldi Temp,0 ;настройка портов
out DDRD,Temp
ldi Temp,0b11111111 ;настройка портов
out DDRB,Temp
ldi Temp,0b01000000 ;разрешить прерывание компаратора
out TIMSK,Temp
ldi Temp,0b00000100 ;тактовый сигнал = CK/256
out TCCR1B,Temp
ldi Temp,0x5B ;инициализация компаратора
out OCR1AH,Temp
ldi Temp,0x8E
out OCR1AL,Temp
ldi Temp,RamEnd ;установка указателя стека
out SPL,Temp
ldi Temp,0 ;обнуление таймера
out TCNT1H,Temp
out TCNT1L,Temp
ldi temp2,5 ;это регистр, благодаря которому только 5-ое прерывание компаратора работает
sei ;разрешить прерывания
;****************************************************
; ОСНОВНОЙ ЦИКЛ
;****************************************************
Inf:
;Тут у меня в планах всякие примочки
rjmp Inf
;****************************************************
; измерение температуры 1 датчика
;****************************************************
termo:
rcall reset1w ; сброс 1-Wire
breq presented ; есть датчик ?
error:
; нету датчика или сбой обмена 1-Wire
;------------------------------------
ldi temp1,0b10101010
out PortB,temp1 ;ну чтобы знать что ошибка
ret ; повторяем сначала
presented:
; есть датчик
Send_1w CMD_SKIP_ROM ; команда "пропустить адрес"
Send_1w CMD_CONVERT_T ; команда "измерить температуру"
delayXms 1000 ; ждем 1 секунду, т.к. измеряется долго
; получение результата измерения температуры
rcall reset1w ; сброс 1-Wire
Send_1w CMD_SKIP_ROM ; команда "пропустить адрес"
Send_1w CMD_R_SCRATCHPAD ; команда "считывание регистров"
rcall readbytes1w ; получаем данные
tst r0 ; r0 - результат обмена
brne error ; если ошибка - перейдем к индикации ошибки
;выводы
ret
;****************************************************
; ОБРАБОТЧИК ПРЕРЫВАНИЯ КОМПАРАТОРА
;****************************************************
Timer1_comp1:
cli
dec temp2
brne endtimer
rcall termo
;полезный код. Rot*100 - обороты в минуту
lds Temp, Buffer
out PortB,temp
ldi rot,0 ;обнуление числа оборотов
ldi Temp,0 ;обнуление таймера
out TCNT1H,Temp
out TCNT1L,Temp
ldi temp2,5
sei
reti
endtimer:
sei
reti ;выход из обработчика
;#####################################################
;#################### 1-WIRE #######################
;#####################################################
.equ wireport = DDRD;
.equ wirepin = PinD; ; порт сигнальных линий
.equ wirebit = 5 ; номер линии порта
.def wiretemp = r22 ; регистр под нужды 1-wire
.def wireres = r2 ; обязательно из числа r0...r15
.macro wire1;
cbi wireport, wirebit ; 0->DDR = Z-состояние
.endmacro;
.macro wire0;
sbi wireport, wirebit ; 1->DDR = 0 на выходе
.endmacro;
;*********************************************************************
reset1w:
; выполняет выдачу сброса в линию 1-wire и возврат состояния PRESENCE
; вход: ничего
; выход: флаг Z установлен, если был PRESENCE
; так как длительность RESET может быть любой, прерывания не запрещаются,
; если это не необходимо
wire1
sbis wirepin, wirebit ; проверим наличие 1 в линии
rjmp presence_fault ; если нет - это ошибка
wire0 ; давим линию в 0
delayXmks 480 ; 480 микросекунд задержка
wire1 ; линию в 1
delayXmks 60 ; 60 микросекунд задержка
; начинаем ждать PRESENCE
ldi wiretemp, 250 ; Тут примерно 1с должно быть
rw1_wait:
sbis wirepin, wirebit
rjmp presence_ok
delayXmks 1
dec wiretemp
brne rw1_wait
ldi wiretemp, 250
rw2_wait:
sbis wirepin, wirebit
rjmp presence_ok
delayXmks 1
dec wiretemp
brne rw2_wait
ldi wiretemp, 125;
rw3_wait:
sbis wirepin, wirebit
rjmp presence_ok
delayXmks 1
dec wiretemp
brne rw3_wait
presence_fault:
; сюда мы попадаем, если не дождались PRESENCE
clz ; сбрасываем Z-флаг
ret
presence_ok:
; PRESENCE получен
sez
delayXmks 480 ; 480 микросекунд задержка
ret ; Z-флаг и так стоит
;*********************************************************************
resive1w:
; выполняет прием байта из линии
; вход: ничего
; выход: r0 - принятый байт
;ldi wiretemp, 0xFF
ser wiretemp
mov r0, wiretemp
;*********************************************************************
send1w:
; выполняет передачу байта в линию
; вход: R0 - выводимый байт
; выход: R0 - то, что удалось ВВЕСТИ из линии
; портит: R0
; примечание: если делать ВЫВОД 0хFF, то на выходе будет ПРИНЯТЫЙ байт
ldi wiretemp, 8 ; число битов в байте
sw1_next:
pushf ; сохраним флаги, т.к. будем запрещать
cli ; запрещаем прерывания
wire0 ; давим линию в 0
delayXmks 1 ; 1 мкс задержки
ror r0 ; выталкиваем выводимый бит
brcc s0 ; если бит C = 0 - обход
wire1 ; линию в 1
s0:
push wiretemp
ldi wiretemp, 9 ; в некоторых случаях может потребоваться
; увеличить это значение, но не более 13!
sw1_wait:
delayXmks 1
dec wiretemp
brne sw1_wait
clc
sbic wirepin, wirebit
sec
ror wireres
delayXmks 90 ; 90 микросекунд - длительность тайм-слота
wire1
pop wiretemp
popf
dec wiretemp
brne sw1_next
mov r0, wireres
ret
;*********************************************************************
readbytes1w:
; считывает 9 байтов в буфер, подсчитывает CRC
; портит r0 и SREG, регистры X и Z
clr wiretemp
sts CRC, wiretemp ; обнуляем CRC
ldi XL, low(Buffer)
ldi XH, high(Buffer)
ldi wiretemp, 9
r1w_next:
push wiretemp
rcall resive1w ; считываем 1 байт
; r0=считанному байту, начинаем подсчет CRC
st X+, r0 ; сохраняем принятый байт
rcall crc8 ; считаем контрольную сумму
pop wiretemp
dec wiretemp
brne r1w_next
ret
;*********************************************************************
crc8:
push r0
ldi wiretemp, 8
mov wireres,wiretemp
r1w_loop_crc:
lds wiretemp, CRC
eor r0, wiretemp
ror r0
mov r0, wiretemp
brcc zero
ldi wiretemp, 0x18
eor r0, wiretemp
zero:
ror r0
sts CRC, r0
pop r0
; 4 следующие команды делают циклический сдвиг r0
push r0
ror r0
pop r0
ror r0
; сдвиг закончен - очень удобно, не правда ли?!
push r0
dec wireres
brne r1w_loop_crc
pop r0
lds r0, CRC
ret
