Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Датчик DS18B20
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Letis
У меня проблема следующего характера. К микроконтроллеру Mega8535 подключены 4 датчика DS18B20. Но я их не могу подключить на одну линию, так как нужно считывать адреса, а датчики розмещены в разных местах, ну в общем, этот вариант мне не подходит.
Тогда я решил разместить датчики на одном порте на на разных линиях. Но когда дело дошло дело до программирования (Code Vision), у меня ничего не получается.
Вот так я подключаю первый датчик
#asm
.equ __w1_port=0x12 ;PORTD
.equ __w1_bit=0
#endasm
Считываю те-ру и хочу сменить адрес шины:
#asm
.equ __w1_port=0x12 ;PORTD
.equ __w1_bit=1
#endasm
Но при компиляции выбивает ошибку.
Посоветуйте, что делать.

Как повесить 4 датчика DS18B20 на разные ноги контроллера ?
miksergei
Цитата(Letis @ Sep 15 2010, 00:11) *
У меня проблема следующего характера. К микроконтроллеру Mega8535 подключены 4 датчика DS18B20. Но я их не могу подключить на одну линию, так как нужно считывать адреса, а датчики розмещены в разных местах, ну в общем, этот вариант мне не подходит.
Тогда я решил разместить датчики на одном порте на на разных линиях. Но когда дело дошло дело до программирования (Code Vision), у меня ничего не получается.
Вот так я подключаю первый датчик
#asm
.equ __w1_port=0x12 ;PORTD
.equ __w1_bit=0
#endasm
Считываю те-ру и хочу сменить адрес шины:
#asm
.equ __w1_port=0x12 ;PORTD
.equ __w1_bit=1
#endasm
Но при компиляции выбивает ошибку.
Посоветуйте, что делать.

Как повесить 4 датчика DS18B20 на разные ноги контроллера ?


Так не пройдет без чтения кодов не обойтись.
Letis
А как нужно сделать ?
vovanse
AVR318: Dallas 1-Wire master on tinyAVR and megaAVR devices http://www.atmel.com/dyn/products/app_note...p?family_id=607

Там как раз написан опрос нескольких линий
Letis
Чесно говоря я ничего не понял с єтого app_note. Можно ли попроще ? Я все таки учил только немецкий язык.
wer_1
http://www.gaw.ru/html.cgi/txt/app/micros/avr/avr318.htm
на русском
Letis
м-да, сложно єто, проще поставить ключ 4066.
А может кто имеет простой пример ?
Сергей Борщ
Цитата(Letis @ Sep 15 2010, 00:11) *
Посоветуйте, что делать.
Написать свою функцию чтения. Или подобрать что-то готовое тут в ветке "исходники программ и библиотек". Там этих 1-wire штук 10, наверное, выкладывали.
Letis
Например ?
Сергей Борщ
Цитата(Letis @ Sep 15 2010, 12:42) *
Например ?
Например что? Поискать для вас ветку "исходники программ и библиотек"? Вот: http://electronix.ru/forum/index.php?showtopic=10934 Искать в ней за вас не буду.
Letis
что надежнее ключи или программный метод?
MrYuran
Цитата(Letis @ Sep 15 2010, 16:37) *
что надежнее ключи или программный метод?

Меньше компонентов - меньше связей - меньше вероятность дефектов компонентов и связей - выше надёжность.
Ставить внешний ключ вместо того, чтобы чуть поправить функцию вывода - как минимум неразумно
zalg
У меня такая проблема. Писал код "с нуля" на ассемблере, все согласно даташиту. В итоге датчик реагирует, но как то странно. При включении показывает температуру +85 С(0550h в первых двух считанных байтах, затем считывание прекращаю, подавая "ресет" ). Насколько я понял, так и должно быть, НО затем он начинает фиксировать изменения температуры относительно этого значения, как будто калибруется при подаче питания. И еще одна странность - младший бит байта 0 - всегда ноль, т.е. при нагреве (если коснуться датчика пальцами) температура начинает расти так - 0550h,0552h,0554h и т.д. Перепроверял все по нескольку раз, симулировал в Proteus - работает как надо, уже грешу на датчик. Может кто сталкивался?
ILYAUL
Цитата(zalg @ Sep 15 2010, 21:04) *
При включении показывает температуру +85 С(0550h в первых двух считанных байтах, затем считывание прекращаю, подавая "ресет" ). Насколько я понял, так и должно быть, НО затем он начинает фиксировать изменения температуры относительно этого значения, как будто калибруется при подаче питания. И еще одна странность - младший бит байта 0 - всегда ноль, т.е. при нагреве (если коснуться датчика пальцами) температура начинает расти так - 0550h,0552h,0554h и т.д. Перепроверял все по нескольку раз, симулировал в Proteus - работает как надо, уже грешу на датчик. Может кто сталкивался?

Считывание Вы остановили , а конвертацию запустили? И дайте код посмотреть.
zalg
Опыт программирования у меня не большой, так что замечаниям по поводу оформления кода буду благодарен.

CODE
.include "m8535def.inc"

.equ clk = 0
.equ data = 1
.equ load = 7


.def hexL = r16 ; Младший байт шестнадцатиричного слова
.def hexH = r17 ; Старший байт шестнадцатиричного слова
.def hexHH = r18 ; Самый старший байт шестнадцатиричного слова
.def BCD0 = r22 ; BCD- разряды 2 и 1
.def BCD1 = r23 ; BCD- разряды 4 и 3
.def BCD2 = r24 ; BCD- разряды 6 и 5
.def BCD3 = r25 ; BCD- разряды 8 и 7

.def cnt = r19 ; Счетчик
.def tmp1 = r20 ; Рабочий регистр


;--------------------------------------------------------------

.ORG 0x0 ;?????? ?????? ?? RESET
rjmp RESET ; Reset Handler
rjmp EXT_INT0 ; IRQ0 Handler
rjmp EXT_INT1 ; IRQ1 Handler
rjmp TIM2_COMP ;TIM2_COMP Timer2 Compare Handler
rjmp TIM2_OVF ; Timer2 Overflow Handler
rjmp TIM1_CAPT ; Timer1 Capture Handler
rjmp TIM1_COMPA ; Timer1 Compare A Handler
rjmp TIM1_COMPB ; Timer1 Compare B Handler
rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
rjmp SPI_STC ; SPI Transfer Complete Handler
rjmp USART_RXC ; USART RX Complete Handler
rjmp USART_UDRE ; UDR Empty Handler
rjmp USART_TXC ; USART TX Complete Handler
rjmp ADC_ ; ADC Conversion Complete Handler
rjmp EE_RDY ; EEPROM Ready Handler
rjmp ANA_COMP ; Analog Comparator Handler
rjmp TWSI ; Two-wire Serial Interface Handler
rjmp EXT_INT2 ; IRQ2 Handler
rjmp TIM0_COMP ; Timer0 Compare Handler
rjmp SPM_RDY ; Store Program Memory Ready Handler

RESET:
ldi r16,high(RAMEND) ; Main program start
out SPH,r16 ; Set Stack Pointer to top of RAM
ldi r16,low(RAMEND)
out SPL,r16

Start:

rcall INIT_PORTS
;rcall INIT_UART
;rcall getc ;for test comunication - nullmodem
;rcall putc

;ldi r16, 0x80
;out GICR, r16
;out GIFR, r16



;ldi r18, 0x01
;ldi r19, 0x03



main:
;ttest3:
;sbic PinD,2
;rjmp ttest3


rcall Init
rcall SkipROM
rcall ConvertT
rcall Init
rcall SkipROM
rcall ReadScratchpad
;ldi r27,0x17
;ldi r26,0x15

;lsr r27
;ror r26

mov r18,r27
mov r19,r27

andi r18,0x0f
andi r19,0xf0

lsr r19
lsr r19
lsr r19
lsr r19

mov r16,r19
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT

mov r16,r18
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT

mov r20,r26
mov r21,r26

andi r20,0x0f
andi r21,0xf0

lsr r21
lsr r21
lsr r21
lsr r21



mov r16,r19
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT



mov r16,r18
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT





ttest:
rjmp ttest


;rcall DataOut






rjmp main

/*---------------------------Write Time Slots----------------------------*/

write0:
in r16,DDRC
ori r16,0x04; !!!?????????!!
out DDRC, r16
cbi PortC,2

ldi r16, 0x23;70us
rcall TmrDelay

in r16,DDRC
andi r16,0xfb
out DDRC, r16; release line

rcall delay_15us

ret

write1:
in r16,DDRC
ori r16,0x04
out DDRC, r16
cbi PortC,2

ldi r16, 0x03; 6us
rcall delay

in r16,DDRC
andi r16,0xfb
out DDRC, r16; release line

ldi r16, 0x23;70us
rcall TmrDelay

ret


/*------------------------Read Time Slots-------------------------------*/
read:
in r16,DDRC
ori r16,0x04
out DDRC, r16
cbi PortC,2

ldi r16, 0x02; 4us
rcall delay

in r16,DDRC
andi r16,0xfb
out DDRC, r16; release line


ldi r16, 0x02; 4us
rcall delay

sbic PinC,2
ori r22,0x80

ldi r16, 0x30; 50us
rcall TmrDelay

ret

read_1byte:
ldi r21,0x08
ldi r22,0x00

loop_1byte:
lsr r22
rcall read
dec r21
cpi r21,0x00
brne loop_1byte
ret
/*------------------------------------------------------------------------*/





Init:

in r16,DDRC
ori r16,0x04; !!!?????????!!
out DDRC, r16

ldi r16,0xf0;480us
cbi PortC,2
rcall TmrDelay; Reset pulse


in r16,DDRC
andi r16,0xfb; !!!?????????!!
out DDRC, r16; release line

ldi r16,0x28;80us
rcall TmrDelay

sbic PinC,2;Presence pulse
rcall Error

ldi r16,0xc8;400us
rcall TmrDelay

sbis PinC,2;check if the sensor has released line
rcall Error

ret

Send:
ldi r21,0x08

start1:
ror r20
brcs wr

rcall write0
dec r21
cpi r21, 0x00
breq end1
rjmp start1
wr:
rcall write1
dec r21
cpi r21, 0x00
breq end1
rjmp start1
end1:
ret

SkipROM:;CCh
ldi r20,0xcc
rcall Send
ret


ReadScratchpad:;BEh

ldi r20,0xBE
rcall Send

reading:

rcall read_1byte
mov r26,r22

rcall read_1byte
mov r27,r22

rcall Init

ret

ConvertT:;44h

ldi r20,0x44
rcall Send

in r16,DDRB
ori r16,0x08
out DDRB, r16
cbi PortB,3;switch LED

ldi r22,0x00

converting:

rcall read
cpi r22,0x00
breq converting


in r16,DDRB
andi r16,0xf7
out DDRB, r16
cbi PortB,3;turn off LED

ret




ConfTmr0:



ldi r17,0x02
out TIMSK, r17;Compare Match interrupt is enabled

out OCR0,r16
sei

ldi r17,0x0a
out TCCR0,r17;CTC Mode, T=2us

ret


TmrDelay:
subi r16,6
rcall ConfTmr0
ldi r18,0x00

loop9:
cpi r18, 0xff
brne loop9
cli

nop ;correction
nop
nop

ret

Error:
go:
ldi r17,0x00

ldi r16, 0x08
out DDRB, r16
cbi PortB,3;switch LED

rjmp go
ret


delay:


loop1:
dec r16
cpi r16,0x00
nop
brne loop1
ret

delay_15us:
ldi r16, 0x06

loop_15us:
dec r16
cpi r16,0x00
nop
brne loop1
ret
/*---------functions for debugging-----------------------------*/

switch_LED:

loop_LED:
ldi r16, 0x08
out DDRB, r16
cbi PortB,3;switch LED
rjmp loop_LED
ret

CIFRA:
cpi r16, 0x00
breq L0
cpi r16, 0x01
breq L1
cpi r16, 0x02
breq L2
cpi r16, 0x03
breq L3
cpi r16, 0x04
breq L4
cpi r16, 0x05
breq L5
cpi r16, 0x06
breq L6
cpi r16, 0x07
breq L7
cpi r16, 0x08
breq L8
cpi r16, 0x09
breq L9
cpi r16, 0x0A
breq LA
cpi r16, 0x0B
breq LB
cpi r16, 0x0C
breq LC
cpi r16, 0x0D
breq L0D
cpi r16, 0x0E
breq LE
cpi r16, 0x0F
breq LF

L0: ldi r16,0xC0
ret
L1: ldi r16,0xF9
ret
L2: ldi r16,0xA4
ret
L3: ldi r16,0xB0
ret
L4: ldi r16,0x99
ret
L5: ldi r16,0x92
ret
L6: ldi r16,0x82
ret
L7: ldi r16,0xF8
ret
L8: ldi r16,0x80
ret
L9: ldi r16,0x90
ret
LA: ldi r16,0x88
ret
LB: ldi r16,0x83
ret
LC: ldi r16,0xC6
ret
L0D: ldi r16,0xA1
ret
LE: ldi r16,0x86
ret
LF: ldi r16,0x8E
ret



CIFERBLAT:

lsl r16
brcs SS1
cbi PortC, data
cbi PortC, clk
sbi PortC, clk
rjmp End_SS
SS1:
sbi PortC, data
cbi PortC, clk
sbi PortC, clk
End_SS:
dec r17
cpi r17, 0x00
brne CIFERBLAT
ret

HexBCD: ; xxxx (Hex) -> 0abcde (BCD)
rcall Div10 ; hexH:hexL / 10, ??????? - ? tmp1
mov BCD0,tmp1 ; ????????? - ? hexH:hexL, tmp1 = ?????? 1
rcall Div10 ; ??????? = ?????? 2
swap tmp1 ; ?????? 2 – ? ??????? ????????
or BCD0,tmp1 ; ?????????? ??????? 2 ? 1 ? BCD0
rcall Div10 ; ??????? = ?????? 3
mov BCD1,tmp1 ; ? BCD1
rcall Div10 ; ??????? = ?????? 4
swap tmp1 ; ?????? 4 – ? ??????? ????????
or BCD1,tmp1 ; ?????????? ??????? 4 ? 3 ? BCD1
rcall Div10 ; ??????? = ?????? 5
mov BCD2,tmp1 ; ? BCD2
rcall Div10 ; ??????? = ?????? 6
swap tmp1 ; ?????? 6 – ? ??????? ????????
or BCD2,tmp1 ; ?????????? ??????? 6 ? 5 ? BCD2
rcall Div10 ; ??????? = ?????? 7
mov BCD3,tmp1 ; ? BCD3
rcall Div10 ; ??????? = ?????? 8
swap tmp1 ; ?????? 8 – ? ??????? ????????
or BCD3,tmp1 ; ?????????? ??????? 6 ? 5 ? BCD3
ret


Div10: ; ??????? hexHH:hexH:hexL ?? 10,
; ????????? – ? hexHH:hexH:hexL, ??????? - ? tmp1
clr tmp1
lsl hexL
rol hexH
rol hexHH;
rol tmp1 ; ??????? ??????? ???? ???????? ?? 10
lsl hexL ; ????? ???? ? ??????????
rol hexH ; ?????? 0
rol hexHH
rol tmp1
lsl hexL
rol hexH
rol hexHH
rol tmp1
ldi cnt,21 ; ??????? ??? ?????????? 21 ????????s
Loop10:
lsl hexL ; ????? ???????? ????? ?? 1 ??????
rol hexH
rol hexHH
rol tmp1 ; ???????????? ? tmp1
subi tmp1,10 ; ????????: ???????????? > 10 ?
brlo HB1 ; ???????, ???? ???
inc hexL ; ??????????? ??????? ??????? ?? 1
rjmp HB2
HB1:
subi tmp1,-10 ; ????????? ???????? ????????
HB2:
dec cnt ; ?????????????? ??????? ????????
brne Loop10 ; ???????, ???? ??? ?? ??? ???????
ret

DataOut:
lsl r27
lsl r27
lsl r27
lsl r27
lsl r27
lsr r26
lsr r26
lsr r26
or r26,r27

mov r16,r26
lsr r16
ldi r17,0x00
ldi r18,0x00

rcall HexBCD

ldi r16,0x00
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT

mov r16,r23
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT

mov r18,r22
mov r19,r22
andi r18,0x0f
andi r19,0xf0
lsr r19
lsr r19
lsr r19
lsr r19

mov r16,r19
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT

mov r16,r18
ldi r17,0x08
rcall CIFRA
rcall CIFERBLAT


;ttest:
;rjmp ttest

ret

/*-------------------------------------------------------------*/

INIT_UART:
ldi r16,00
out UBRRH,r16
ldi r16,25
out UBRRL,r16
ldi r16,24 ; UART for TX and RX
out UCSRB,r16
ldi r16,0x86
out UCSRC,r16
ret

getc:
sbis UCSRA,RXC
rjmp getc
in r16,UDR
ret

putc:
sbis UCSRA,UDRE
rjmp putc
out UDR,r16
ret




















INIT_PORTS:
ldi r16, 0x00
out DDRA, r16 ;??? ?????

ldi r16, 0x00
out DDRB, r16

ldi r16, 0x03
out DDRC, r16

ldi r16, 0x10 ;??? LCD ???????, ??? LED ???????? ?? 0, 2->TXD
out DDRD, r16
ret




EXT_INT0: ; IRQ0 Handler+-

reti

EXT_INT1: ; IRQ1 Handler
reti
main2:
reti
TIM2_COMP:
reti ; Timer2 Compare Handler
TIM2_OVF:
reti ; Timer2 Overflow Handler
TIM1_CAPT:
reti ; Timer1 Capture Handler
TIM1_COMPA:
reti ; Timer1 Compare A Handler
TIM1_COMPB:
reti ; Timer1 Compare B Handler
TIM1_OVF:
reti ; Timer1 Overflow Handler
TIM0_OVF:
reti; Timer0 Overflow Handler
SPI_STC:
reti ; SPI Transfer Complete Handler
USART_RXC:
reti ; USART RX Complete Handler
USART_UDRE:
reti ; UDR Empty Handler
USART_TXC:
reti ; USART TX Complete Handler

ADC_:
reti

EE_RDY:
reti ; EEPROM Ready Handler
ANA_COMP:
reti ; Analog Comparator Handler
TWSI:
reti ; Two-wire Serial Interface Handler
EXT_INT2:
reti ; IRQ2 Handler
TIM0_COMP:

ldi r17,0x00
out TCCR0,r17
ldi r17,0x00
out TIMSK, r17
ldi r17,0x00
out TCNT0,r17;reset timer

ldi r18, 0xff

reti ; Timer0 Compare Handler
SPM_RDY:
reti ; Store Program Memory Ready Handler


ARV
у меня вообще сложилось впечатление, что Code Vision-овские библиотечные функции для работы с 1-wire сделаны как-то криво... прерывания надо запрещать на все время обмена - бред какой-то... я-то с WinAVR работаю, и сам не один вариант написал для обмена 1-wire, в том числе и для "многопортового" подключения нескольких датчиков... если надо - поищу исходники - но портировать в CVAVR не буду - это уже самостоятельно вы...
ILYAUL
zalg Вы создайте свою тему всё таки.
alexeyv
to zalg
Цитата(zalg @ Sep 15 2010, 23:04) *
У меня такая проблема. Писал код "с нуля" на ассемблере, все согласно даташиту. В итоге датчик реагирует, но как то странно. При включении показывает температуру +85 С(0550h в первых двух считанных байтах, затем считывание прекращаю, подавая "ресет" ). Насколько я понял, так и должно быть, НО затем он начинает фиксировать изменения температуры относительно этого значения, как будто калибруется при подаче питания. И еще одна странность - младший бит байта 0 - всегда ноль, т.е. при нагреве (если коснуться датчика пальцами) температура начинает расти так - 0550h,0552h,0554h и т.д. Перепроверял все по нескольку раз, симулировал в Proteus - работает как надо, уже грешу на датчик. Может кто сталкивался?

1. При чтении значения (тем более при первом) необходимо дождаться завершения измерения температуры, но перед этим необходимо подать команду на старт
2. Скажите какой датчик, может у него точность измерения температуры по умолчанию задана с дискретом в один градус?
3. Лучше сделать новый топик!

To Letis.
Пишу с использованием WinAVR (на AVR-асме не пишу более 5 лет)
В одной проге было два ds18s20 на одном порту
Вот моя реализация.

В вашем случае достаточно переделать макросы onew_input, onew_out_hi, onew_out_lo под большее количество датчиков

В ds18s20.h
Код
    #define DS18S_PORT               PORTE
    #define DS18S_DDR                DDRE
    #define DS18S_PIN                PINE
    #define PIN_DS18S_1WR     (_BV(2))
    #define PIN_DS18S_1RD     (_BV(3))
    #define PIN_DS18S_2WR     (_BV(4))
    #define PIN_DS18S_2RD     (_BV(5))

  #define onew_input(par)   (DS18S_PIN  &   (par ? PIN_DS18S_2RD : PIN_DS18S_1RD))
  #define onew_out_hi(par)   DS18S_PORT &= ~(par ? PIN_DS18S_2WR : PIN_DS18S_1WR)
  #define onew_out_lo(par)   DS18S_PORT |=  (par ? PIN_DS18S_2WR : PIN_DS18S_1WR)


В ds18s20.c
Код
//*****************************************************************************
// Layer 1 - Transmit/Receive Bit
void onew_set_lo(byte ch)
{
  byte s = SREG;
  cli();
  onew_out_lo (ch);
  _delay_us   (65);
  onew_out_hi (ch);
  _delay_us   (10); //5
  SREG = s;
}
//=============================================================================
void onew_set_hi(byte ch)
{
  byte s = SREG;
  cli();
  onew_out_lo (ch);
  _delay_us   (7); //
  onew_out_hi (ch);
  _delay_us   (70); // 65
  SREG = s;
}
//=============================================================================
byte onew_get_bit(byte ch)  
{
  byte t = 0;
  byte s = SREG;
  cli();
  onew_out_lo (ch);
  _delay_us   (2);
  onew_out_hi (ch);
  _delay_us   (12); //11
  if(onew_input(ch)) t=1;
  SREG = s;
  _delay_us   (60); //45
  return t;
}
//=============================================================================
byte onew_reset(byte ch)
{
  byte t = 0;
  byte s = SREG;
  cli();
  onew_out_lo (ch);
  _delay_us   (480);
  onew_out_hi (ch);
  _delay_us   (65);
  if(!onew_input(ch)) t=1;
  sei();
  SREG = s;
  _delay_us   (415);
  return t;
}
//*****************************************************************************
serge71
to zalg:
Если младший бит "0", может всё же проверить кофигурационную ячейку разрешения датчика
Letis
Цитата
и сам не один вариант написал для обмена 1-wire, в том числе и для "многопортового" подключения нескольких датчиков... если надо - поищу исходники - но портировать в CVAVR не буду - это уже самостоятельно вы...

Виложите пожалуста код
ARV
Цитата(Letis @ Sep 16 2010, 13:20) *
Виложите пожалуста код
ну как бы вот... комментариев много - разберетесь, надеюсь.
Letis
Код несколько не понятен в силу того что пишу в Code Vision.
І вот первый вопрос.
/// УКАЗАТЕЛЬ НА ПОРТ ВВОДА-ВЫВОДА
typedef volatile uint8_t* io_ptr;

ошибка: declaration syntax error.
Как мне переписать под мою программу.
ARV
Цитата(Letis @ Sep 17 2010, 01:18) *
Как мне переписать под мою программу.
не имею понятия - я вас предупреждал сразу: CodeVision не использую и нет желания даже пробовать
xemul
Цитата(Letis @ Sep 17 2010, 01:18) *
Код несколько не понятен в силу того что пишу в Code Vision.
І вот первый вопрос.
/// УКАЗАТЕЛЬ НА ПОРТ ВВОДА-ВЫВОДА
typedef volatile uint8_t* io_ptr;

ошибка: declaration syntax error.

Посмотрите в мануале Code Vision, понимает ли он uint8_t.
Если не понимает, то или
typedef unsigned char uint8_t;
или замените все uint8_t на unsigned char.
Леонид Иванович
Для нескольких термометров делал так:

Код
//----------------------------------------------------------------------------
//--------------------------- Цифровые датчики: ------------------------------
//----------------------------------------------------------------------------

//Используются термометры DS18B20 (S20), которые подключены к портам OWPn.
//Считывание и повторный запуск преобразования производится
//в момент считывание таходатчика того же канала.
//Считываются только два байта температуры, CRC не проверяется.
//Суммарное время опроса всех термометров должно быть больше
//времени преобразования, т.е. длительность интервала счета тахометра
//не должна быть меньше 750 мс / CHANNELS.
//Считанное значение температуры заносится в массив Temp[],
//температура представлена в десятых долях градуса.
//Диапазон возможных температур составляет от TEMP_MIN до TEMP_MAX
//градусов. При отсутствии термометра показания равны TEMP_MIN.

//------------------------------- Константы: ---------------------------------

  #define OWP0   (1 << PC0) //порт цифрового термометра 0
  #define OWP1   (1 << PC1) //порт цифрового термометра 1
  #define OWP2   (1 << PC2) //порт цифрового термометра 2
  #define OWP3   (1 << PC3) //порт цифрового термометра 3
  #define OWP4   (1 << PC4) //порт цифрового термометра 4
  #define OWP5   (1 << PC5) //порт цифрового термометра 5
  
  //Направление:
  #define I_DDRC  (0)
  //Подтягивающие резисторы / начальное состояние:
  #define I_PORTC (0)
  //Макроопределения для работы с портами:
  #define Port_OWP_0(m)   (DDRC |= m)
  #define Port_OWP_Z(m)   (DDRC &= ~m)
  #define Pin_OWP(m)      (PINC & m)

//Маски термометров:
const __flash char Masks[CHANNELS] = {OWP0, OWP1, OWP2, OWP3, OWP4, OWP5};

//------------------------------- Переменные: --------------------------------

static int Temp[CHANNELS];     //текущая температура
static bool Present[CHANNELS]; //флаги присутствия термометров

//---------------------------- Прототипы функций: ----------------------------

void Start(char n);         //старт термометра
void Read(char n);          //чиение термометра
void TReset(char n);        //генерация импульса сброса
char TByte(char n, char dat); //запись/чтение байта
bool TBit(char n, bool b);  //запись/чтение бита
void Do_Crc(char b, char *crc); //вычисление CRC

//------------------ Инициализация измерителя температуры: -------------------

void Therm_Init(void)
{
  ACSR = (1<<ACD);          //запрещение аналогового компаратора
  for(char i = 0; i < CHANNELS; i++)
  {
    Temp[i] = TEMP_MIN;     //инициализация температуры
    Start(i);               //старт всех термометров
  }
}

//------------------------ Измерение температуры: ----------------------------

void Therm_Exe(char n)
{
  Read(n);                  //чтение термометра - самое первое измерение
  Start(n);                 //старт термометра
}

//-------------------------- Старт термометра: -------------------------------

void Start(char n)
{
  TReset(n);                //импульс сброса
  if(Present[n])
  {
    TByte(n, 0xCC);         //skip ROM
    TByte(n, 0x44);         //convert T
  }
}

//------------------------- Чтение термометра: -------------------------------

void Read(char n)
{
  if(Present[n])
  {
    TReset(n);              //импульс сброса
    if(Present[n])
    {
      TByte(n, 0xCC);       //skip ROM
      TByte(n, 0xBE);       //read scratchpad
#ifdef DS18B20      
      char l = TByte(n, 0xFF); //чтение младшего байта
      char h = TByte(n, 0xFF); //чтение старшего байта
      int t = WORD(h, l);   //температура с дискретностью 0.0625°C
      t = (t * 10) / 16;    //температура с дискретностью 0.1°C
#else
      char Data[9];               //данные термометра
      char Crc = 0;               //инициализация CRC
      for(char i = 0; i < 9; i++)
      {
        char b = TByte(n, 0xFF);  //чтение данных
        Do_Crc(b, &Crc);          //обновление CRC
        Data[i] = b;              //сохранение данных
      }
      int t = TEMP_MIN;
      if(!Crc)
      {
        t = WORD(Data[1], Data[0]) / 2;
        t = (t * 20 - 5 + (int)(Data[7] - Data[6]) * 20 / Data[7]) / 2;
      }
#endif      
      Temp[n] = t;
      return;
    }
  }
  Temp[n] = TEMP_MIN;       //термометр отсутствует
  return;
}

//--------------------- Генерация импульса сброса: ---------------------------

void TReset(char n)
{
  char m = Masks[n];
  char si;
  Present[n] = 0;              //сброс флага присутствия термометра
  Port_OWP_0(m);               //OWP <- 0
  Delay_us(500);               //delay 500 uS
  si = __save_interrupt();
  __disable_interrupt();       //запрещение прерываний
  Port_OWP_Z(m);               //OWP <- 1
  Delay_us(14);                //delay 14 uS
  if(Pin_OWP(m))               //если OWP = 0, то ошибка
  {
    Delay_us(52);              //delay 52 uS
    if(!Pin_OWP(m))            //если OWP = 1, то ошибка
    {
      __restore_interrupt(si); //восстанавление прерываний
      Delay_us(250);           //delay 250 uS
      if(Pin_OWP(m))           //если OWP = 0, то ошибка
      {
        Present[n] = 1;        //если ошибок нет, термометр присутствует
      }
    }
  }
  __restore_interrupt(si);     //восстанавление прерываний в случае ошибки
}

//-------------- Запись/чтение байта по однопроводной шине: ------------------

char TByte(char n, char dat)
{
  char res;
  char m = Masks[n];
  for(char i = 0; i < 8; i++)
  {
    res = res >> 1;
    if(TBit(m, dat & 1)) res |= 0x80;
     else res &= ~0x80;
    dat = dat >> 1;
  }
  return(res);
}

//--------------- Запись/чтение бита по однопроводной шине: ------------------

bool TBit(char m, bool b)
{
  char si;
  si = __save_interrupt();
  __disable_interrupt();       //запрещение прерываний
  Port_OWP_0(m);               //OWP <- 0
  Delay_us(2);                 //delay 2 uS
  if(b) Port_OWP_Z(m);         //bit = 1, OWP <- 1
  Delay_us(13);                //delay 13 uS
  bool owp = Pin_OWP(m);       //чтение порта
  Delay_us(45);                //delay 45 uS
  Port_OWP_Z(m);               //OWP <- 1
  __restore_interrupt(si);     //восстанавление прерываний
  Delay_us(2);                 //delay 2 uS
  return(owp);
}

//--------------------- Вычисление контрольной суммы: ------------------------

void Do_Crc(char b, char *crc)
{
  for(char i = 0; i < 8; b = b >> 1, i++)
    if((b ^ *crc) & 1) *crc = ((*crc ^ 0x18) >> 1) | 0x80;
     else *crc = (*crc >> 1) & ~0x80;
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.