Skocz do zawartości

Atmega64 + DS18B20 - problem z odczytem temperatury.


Markownik

Pomocna odpowiedź

Witam, chciałbym przedstawić swój problem, może któryś z użytkowników będzie wiedział jak mi pomóc. Jako że zacząłem niedawno swoją przygodę z mikro-kontrolerami zaczynam od najprostszych projektów. Po udanej próbie obsługi wyświetlacza (na sterowniku HD44780) wziąłem się za pisanie obsługi czujnika temperatury firmy Dallas Semiconductors DS18B20.

Czujnik pracuje w systemie 1-wire, podłączony jest normalnie (Vcc do napięcia 4,8V; GND do masy i DQ do uC) a nie w trybie pasożytniczym. Komunikacja z czujnikiem zachodzi i sądzę że czujnik przesyła informacje prawidłowo. Niestety wadliwy jest chyba fragment odpowiedzialny za przeliczanie temperatury (z hex do dec). Objawia się to tym że w temperaturze ok 19-10 stopni C (na parapecie w zimny deszczowy dzień) wyświetla ok 960.2 stopni. przy podnoszeniu temperatury do pokojowej temperatura podnosi się do 1024 po czym zmienia znak na - i zaczyna opadać od -1024 do ok -930 .. -876. Poniżej zamieszczam kody źródłowe "temp.c" i "temp.h". Chciałbym zaznaczyć że przejrzałem już sporą ilość tematów poruszających ten problem na innych forach.

temp.c

#include <avr/io.h>
#include <stdlib.h> 
#include <util/delay.h>    
#include "temp.h"
#include "lcd.h"     

int main(void){

lcdInit();
lcdClear();
lcdText("termometr");
_delay_ms(4000);
for(;;){

	unsigned char buf[12];
	float temp=0;
	lcdGoto(0,0);
	temp=read_temp();
	if(temp!=1111.1){
		dtostrf(temp,1,1,buf);
		lcdClear();
		lcdText(buf);
	}else{
		lcdClear();
		lcdText("cisza...");
	}
	_delay_ms(200);
}
return 0;
}

temp.h

#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>

#define we 7
#define port1wire PIND
#define ddr1wire DDRD
#define set1wire ddr1wire&=~_BV(we)
#define clr1wire ddr1wire|=_BV(we)

unsigned char reset_pulse(void){

unsigned char ob=0;

clr1wire;
_delay_us(480);
set1wire;
_delay_us(30);
if(bit_is_clear(port1wire, we)) ob=1; else ob=0;
_delay_us(470);
if(bit_is_set(port1wire, we)) ob=1; else ob=0;
return ob;
}

void send(char bit){

clr1wire;
_delay_us(5);
if(bit==1)
	set1wire;
_delay_us(80);
set1wire;
}

unsigned char read(void){

unsigned char ob=0;

clr1wire;
_delay_us(2);
set1wire;
_delay_us(16);
if(bit_is_set(port1wire, we)) ob=1; else ob=0;
return ob;
}

void send_byte(char byte){

unsigned char i;
unsigned char pom;

for(i=0;i<8;i++){
	pom=byte>>i;
	pom&=0x01;
	send(pom);
}
_delay_us(100);
}

unsigned char read_byte(void){

unsigned char i;
unsigned char val=0;

for(i=0;i<8;i++){
	if(read())
		val|=0x01<<i;
	_delay_us(16);
}
return val;
}

float read_temp(void){

unsigned char spr=0;
char temp1=0, temp2=0;
float temp=0;

spr=reset_pulse();
if(spr==1){
	send_byte(0xCC); //skip rom
	send_byte(0x44); //convert t
	_delay_ms(250);
	_delay_ms(250);
	spr=reset_pulse();
	send_byte(0xCC); //skip rom
	send_byte(0xBE); //read scratchpad
	temp1=read_byte();
	temp2=read_byte();
	spr=reset_pulse();
	temp=(float)(temp1+(temp2*256))/16;
}else
	temp=1111.1;
return temp;
}

tak, rezystor przepisowe 4,7k jest.

Link do komentarza
Share on other sites

Ja bym radził odczytać cały scratchpad z DS1820 i sprawdził CRC. Z tymi czujnikami wcale nie tak łatwo się dogadać. Możliwe że błąd jest w samej transmisji po 1-wire.

Możesz też spróbować zmienić temp0, temp1 z char na coś większego. Możliwe, że kompilator źle rozumie:

temp=(float)(temp1+(temp2*256))/16; 
  • Pomogłeś! 1
Link do komentarza
Share on other sites

temperatura jest zapisana w 16 bitach, następnie zmieniasz je na 16 bajtów reprezentująca tą liczbę w kodzie ascii, wiec może wystarczyło by zmienić twoja tablice buf[12] na buf[16]

  • Lubię! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Podpisanie innego typu zmiennej nie pomogło (no, teraz po przekroczeniu 1024 "stopni" przechodzi na 3072, a nie -1024...). Zmienianie rozmiaru tablicy buf[] również. Tutorial zamieszczony w 1. odpowiedzi daje ciekawe wyniki, ale jako że nie chce spędzić nad tym kolejnej nocy, sprawdzaniem CRC i głębszą analizą komunikacji z czujnikiem zajmę się jutro rano.

Edit:

No cóż... błędy były w czasach. Skorzystałem w końcu z innej biblioteki i działa. Oto poprawione pliki temp.h i temp.c (dla osób które w przyszłości będą się zmagać z podobnymi problemami):

temp.h

#include <avr/io.h> 
#include <util/delay.h> 

#define DQ 7
#define SET_DQ DDRD &= ~_BV(DQ) 
#define CLR_DQ DDRD |= _BV(DQ) 
#define IN_DQ PIND & _BV(DQ) 

void ow_reset(void) 
{ 
  CLR_DQ;                                    // stan niski na linii 1wire 
  _delay_us(480);                            // opóźnienie 480us 
  SET_DQ;                                    // stan wysoki na linii 1wire 
  _delay_us(480);                            // opóźnienie 480 us 
} 

void ow_write_bit(char b)                  // procedura zapisu bitu na linię 1wire 
{ 
  CLR_DQ;                                    // stan niski na linii 1wire 
  _delay_us(10);                             // opóźnienie 10us 
  if(b) SET_DQ;                              // jeśli b<>0 to ustaw stan wysoki na linii 
  _delay_us(100);                            // opóźnienie 100us 
  SET_DQ;                                    // stan wysoki na linii 1wire 
} 

char ow_read_bit(void) 
{ 
  CLR_DQ; 
  _delay_us(2); 
  SET_DQ; 
  _delay_us(12); 
  if(IN_DQ) return 1; else return 0; 
} 

unsigned char ow_read_byte(void) 
{ 
  unsigned char i; 
  unsigned char value = 0; 
  for (i=0;i<8;i++) 
  { 
     if(ow_read_bit()) value|=0x01<<i; 
     _delay_us(47); 
  } 
  return(value); 
} 

void ow_write_byte(char val) 
{ 
  unsigned char i; 
  unsigned char temp; 
  for (i=0; i<8; i++) 
  { 
     temp = val >> i; 
     temp &= 0x01; 
     ow_write_bit(temp); 
  } 
} 

temp.c

#include <avr/io.h>
#include <stdlib.h> 
#include <util/delay.h>    
#include "temp2.h"
#include "lcd.h"     

int main(void){

DDRD = 0xFE; 
lcdInit();
char msb, lsb,  temp; 
float celcius;  

lcdClear();
lcdText("termometr");
_delay_ms(4000);
for(;;){		

       unsigned char tab[6];

	ow_reset(); 
	ow_write_byte(0xCC); 
	ow_write_byte(0x44); 
	for (uint8_t a = 0; a < 25; a++) 
		_delay_ms(30); // (30) =750ms (40) =1000ms 
	ow_reset(); 
	ow_write_byte(0xCC); 
	ow_write_byte(0xBE); 
	lsb = ow_read_byte(); 
	msb = ow_read_byte(); 
	celcius =  msb << 8 | lsb ; 
	celcius/=16; 
	temp = msb << 4| lsb >> 4; 
	lcdClear();
	lcdGoto(0,0);
	lcdText("Temp: "); 
	lcdText(dtostrf(celcius, 2, 4, tab)); 
}
return 0;
}
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.