Atmega32 DS1820 CodeVision - nepřesná / velmi vysoká teplota

Dobrý den,
vím, že se tu tohle teplotní čidlo řešilo už několikrát, ale jsem skoro naprostý laik a proto bych potřeboval poradit přímo k mému problému. Zde je můj kód:[code]/* Multipoint thermometer with LCD display
using the Dallas Semiconductor DS1820/18S20
1 Wire bus temperature sensors

CodeVisionAVR C Compiler
© 2000-2010 HP InfoTech S.R.L.
www.hpinfotech.ro

Chip: ATmega8515
Memory Model: SMALL
Data Stack Size: 128 bytes

PLEASE MAKE SURE THAT THE CKSEL0…3 FUSE
BITS ARE PROGRAMMED TO USE THE EXTERNAL
3.6864MHz CLOCK SOURCE OF THE STK500 AND NOT
THE INTERNAL 1MHz OSCILLATOR.
The ATmega8515 chip comes from the factory
with CKSEL0…3 fuse bits set to use the
internal 1 MHz oscillator.

The DS1820/18S20 sensors are connected to
bit 6 of PORTA of the ATmega8515 as follows:

[DS1820/18S20] [STK500 PORTA HEADER]
1 GND - 9 GND
2 DQ - 7 PA6
3 VDD - 10 +5V

All the temperature sensors must be connected
in parallel

AN 4.7k PULLUP RESISTOR MUST BE CONNECTED
BETWEEN DQ (PA6) AND +5V !
*/

/* Use an 2x16 alphanumeric LCD connected
to PORTC as follows:

[LCD] [STK500 PORTC HEADER]
1 GND- 9 GND
2 +5V- 10 VCC
3 VLC- LCD contrast control voltage 0…1V
4 RS - 1 PC0
5 RD - 2 PC1
6 EN - 3 PC2
11 D4 - 5 PC4
12 D5 - 6 PC5
13 D6 - 7 PC6
14 D7 - 8 PC7
*/

// Alphanumeric LCD Module functions
// The LCD connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric menu
#include <alcd.h>
#include <ds1820.h>
#include <delay.h>
#include <stdio.h>

char lcd_buffer[33];

/* maximum number of DS1820/DS18S20 connected to the 1 Wire bus */
#define MAX_DEVICES 8

/* DS1820/DS18S20 devices ROM code storage area */
unsigned char rom_code[MAX_DEVICES][9];

main()
{
unsigned char i,j,devices;
int temp;

lcd_init(16);
lcd_putsf(“CodeVisionAVR\n1 Wire Bus Demo”);
delay_ms(2000);
lcd_clear();

/* detect how many DS1820/DS18S20 devices
are connected to the 1 Wire bus */
devices=w1_search(0xf0,rom_code);
sprintf(lcd_buffer,"%u DS1820\nDevice detected",devices);
lcd_puts(lcd_buffer);
delay_ms(2000);

/* display the ROM codes for each device /
if (devices)
{
for (i=0;i<devices;i++)
{
sprintf(lcd_buffer,“Device #%u ROM\nCode is:”,i+1);
lcd_clear();
lcd_puts(lcd_buffer);
delay_ms(2000);
lcd_clear();
for (j=0;j<8;j++)
{
sprintf(lcd_buffer,"%02X ",rom_code
[j]);
lcd_puts(lcd_buffer);
if (j==3) lcd_gotoxy(0,1);
};
delay_ms(5000);
};
}
else
while (1); /* stop here if no devices were found */

/* measure and display the temperature(s) /
while (1)
{
for (i=0;i<devices;)
{
temp=ds1820_temperature_10(&rom_code
[0]);
j=’+’;
if (temp<0)
{
j=’-’;
temp=-temp;
};
sprintf(lcd_buffer,“t%u=%c%i.%u\xdfC”,++i,j,temp/90,temp%10); //o tento řádek se jedná
lcd_clear();
lcd_puts(lcd_buffer);
delay_ms(800);
};
};
}
[/code]

Program funguje, na LCD se zobrazí teplota a čidlo reaguje na její změnu (zkoušel jsem to fénem), ale teplota není správná, už si přesně nepamatuju kolik teploměr ukazoval, bylo to něco okolo 180 °C. Trochu pomohlo jak vidíte v kódu, že jsem místo deseti dělil devadesáti, ale i přesto je někdy odchylka až 2 °C (po ustálení samozřejmě), což by podle toho co jsem vyčetl z datasheetu vyčetl mělo být cca půl stupně. Tak vás tedy prosím o radu, jak získat správnou teplotu.

Čip: Atmega32
Soft: Codevision

:arrow_right: administrator: přejmenováno z “Atmega32 DS1820 CodeVision Example”**

Nemal by si tu teplotu posunuť o 1bit do prava namiesto delenia 90tim

odchylka od coho? Ako vies ze to cim merias je presnejsie ako DS18B20?
Ustalenie merias v olejovom vyhrievanom a premiesavanom kupeli tak ako sa maju kalibrovat teplomery (asi najjednoduchsi sposob) alebo len tak na stole?
Lebo napriklad ja mam na roznych miestach na stole pri zavretych dverach a plastovych oknach (stol je mimo tah okno - dvere) rozdiel cca +/- 1,5°C. To iste plati o vyske nad stolom. Obdobne vysledky zobrazila termovizna kamera.

Tak by ma velice zaujimalo voci comu mas odchylku az 2°C.

no vhodne je to merať teplomerom digitalnym ktorým sa meria teplota tela.

Mám s tím také problémy, pořád mi to ukazuje -255.93 a čidlo nereaguje, dokázal by mi někdo poradit :

[code]

#include <mega32.h>
#include <delay.h>
#include <stdio.h>

// 1 Wire Bus interface functions
#include <1wire.h>
char buffer[16];
void read_temperature(char *buffer);

// DS1820 Temperature Sensor functions
#include <ds1820.h>

// maximum number of DS1820 devices
// connected to the 1 Wire bus
#define MAX_DS1820 8
// number of DS1820 devices
// connected to the 1 Wire bus
unsigned char i,j,ds1820_devices;
// DS1820 devices ROM code storage area,
// 9 bytes are used for each device
// (see the w1_search function description in the help)
unsigned char ds1820_rom_codes[MAX_DS1820][9];

// Alphanumeric LCD functions
#include <alcd.h>

// Declare your local variables here
#define SKIP_ROM 0xCC
#define CONVERT_T 0x44
#define READ_SCRAT 0xbe
void main(void)
{
// Declare your local variables here

// Input/Output Ports initialization
// Port A initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRA=(0<<DDA7) | (0<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// Port C initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=Out
DDRC=(0<<DDC7) | (0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (1<<DDC0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=P Bit0=0
PORTC=(0<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (1<<PORTC1) | (0<<PORTC0);

// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0 output: Disconnected
TCCR0=(0<<WGM00) | (0<<COM01) | (0<<COM00) | (0<<WGM01) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0<<AS2;
TCCR2=(0<<PWM2) | (0<<COM21) | (0<<COM20) | (0<<CTC2) | (0<<CS22) | (0<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<OCIE0) | (0<<TOIE0);

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
MCUCSR=(0<<ISC2);

// USART initialization
// USART disabled
UCSRB=(0<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (0<<RXEN) | (0<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);

// Analog Comparator initialization
// Analog Comparator: Off
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
SFIOR=(0<<ACME);

// ADC initialization
// ADC disabled
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);

// SPI initialization
// SPI disabled
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);

// TWI initialization
// TWI disabled
TWCR=(0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWEN) | (0<<TWIE);

// 1 Wire Bus initialization
// 1 Wire Data port: PORTD
// 1 Wire Data bit: 0
// Note: 1 Wire port settings are specified in the
// Project|Configure|C Compiler|Libraries|1 Wire menu.
w1_init();

// Determine the number of DS1820 devices
// connected to the 1 Wire bus
ds1820_devices=w1_search(0xf0,ds1820_rom_codes);

/* display the ROM codes for each device /
if (ds1820_devices)
{
for (i=0;i<ds1820_devices;i++)
{
sprintf(buffer,“Zarizeni #%u ROM\nKod:”,i+1);
lcd_clear();
lcd_puts(buffer);
delay_ms(2000);
lcd_clear();
for (j=0;j<8;j++)
{
sprintf(buffer,"%02X ",ds1820_rom_codes
[j]);
lcd_puts(buffer);
if (j==3) lcd_gotoxy(0,1);
};
delay_ms(5000);
};
}
else
while (1); /* stop here if no devices were found */

// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTB Bit 0
// RD - PORTB Bit 1
// EN - PORTB Bit 2
// D4 - PORTB Bit 4
// D5 - PORTB Bit 5
// D6 - PORTB Bit 6
// D7 - PORTB Bit 7
// Characters/line: 16
lcd_init(16);
lcd_gotoxy(0,0);
lcd_puts(“Teplota”);

#asm(“cli”); // zakaz preruseni
PORTC.0=1; // 1 indikuje zhasnutou diodu, kdyby tam byla 0, tak by dioda svitila

while (1)
{
// LEDFlasher
if(PINC.1==0) // pokud stisknu tlacitko
{
PORTC.0=0; // rozsvitim diodu
delay_ms(100); // necham nejakou dobu svitit
PORTC.0=1; // zhasnu diodu
delay_ms(1000); // v pripade, ze bych tlacitko drzel a nepustil, tak abych videl blikani, musim dat nejake zpozdeni
};
read_temperature(buffer);
delay_ms(5000);
}
}

void read_temperature(char *buffer){
unsigned char temperature[2];

//conversion 2 byte to digit and decimal
unsigned char digit;
unsigned int decimal;

//Reset, skip ROM and start temperature conversion
//reset_ds();
w1_write(SKIP_ROM);
w1_write(CONVERT_T);

//Wait until conversion is complete
while(!w1_read()); //DS18B20 send 1 for conversion is done

//Reset, skip ROM and send command to read Scratchpad
//reset_ds();
w1_write(SKIP_ROM);
w1_write(READ_SCRAT);

//Read Scratchpad (only 2 first bytes)
temperature[0]=w1_read(); //low byte
temperature[1]=w1_read(); //high byte

digit = (temperature[1]<<4)&0xf0; //form 2 bytes to byte for conversion
digit |= (temperature[0]&0xf0)>>4;

decimal = (temperature[0]&0xf)*625; //625 create whole number (over 8b therefore uint16_t)
decimal/=100; //only 2 decimal place (1000 - one decimal place)

//display
lcd_clear();
lcd_gotoxy(0,0);
lcd_puts(“Teplota:”);

if (digit>=127)
{
lcd_gotoxy(0,1);
lcd_putchar(’-’);
}

lcd_gotoxy(1,1);
sprintf(buffer, “%3d.”, digit);
lcd_puts(buffer);
sprintf(buffer, “%d”, decimal);
lcd_puts(buffer);
}

[/code]*

dagid4: Co dělá funkce ds1820_temperature_10 ?
Pokud posílá součet teplot posledních 10 měření, pak výslednou teplotu dostaneš tak, že hodnotu vydělíš 10, pokud posílá součet posledních deseti hodnot z čidla jako 2 byty (resp. int) bez přepočtu, pak bys měl dělit 160. Čidlo posílá data tak, že když přečtu 0b00000000_00010000 => 0x00_10, tak dostanu hodnotu 16 (dec.), ale ve skutečnosti je to 16x1/16° = 1°C. Proto dělit 160-ti. Ale je to jenom věštění z koule.

Anonymní:

//Reset, skip ROM and start temperature conversion
 //reset_ds();
 w1_write(SKIP_ROM);
 w1_write(CONVERT_T);

Musíš odpoznámkovat reset_ds();. Každá komunikace s čidlem začíná RESET pulzem. To totiž není reset čidla, ale reset komunikace, takže pokud nepošleš reset, tak nezahajuješ komunikaci s čidlem.

Ta funkce jenom vrací načtenou hodnotu 10x vynásobenou - takže pro zobrazení hodnotu musíš vydělit těma deseti:

sprintf(lcd_buffer,"t%u=%c%i.%u\xdfC",++i,j,temp/10,temp%10);

nevím kdes vzal tu blbost dělit devadesáti
sprintf(lcd_buffer,“t%u=%c%i.%u\xdfC”,++i,j,temp/90,temp%10);

Aještě jedna věc - jsi si jistý,že máš opravdu DS1820? - ten už se totiž nějakou dobu nedělá a neprodává. Nahradil ho typ DS18B20 a ten má jinou inicializaci, takže ten tvůj příklad z CV ti nebude fungovat.

V CV najdeš ale i příklad pro DS18B20 - ale tam funkce čtení teploty vrací už hodnotu v desetinné čárce (float) a aby ti displej zobrazoval správnou hodnotu musíš v "Configure project/C compiller/(s)printf features " nastavit float,width,precision.

Lou: Pro upřesnění - Dallas vyrábí čidla DS18B20 a DS18S20. Čidla se od sebe liší přesnosstí a rozlišením.

Obě čidla vrací teplotu jako 16-bitovou hodnotu. Pokud je rutina psaná pro DS1820 a přepočítává načtenou hodnotu na float, bude přepočet fungovat pouze s čidlem DS18S20 (nebo musíš pro DS18B20 výsledek ještě vydělit 8). Protože původní DS1820 je převodník s rozlišením 0,5°C. Pokud jsi použil čidlo DS18B20, tak musíš počítat s tím, že teplota = načtená hodnota/16. Čidlo DS18B20 má nastavitelné rozlišení 9-12 bitů. V případě nastavení na rozlišení jenom 11 bitů je pak bit 0 nedefinovaný. Pro 10 bitů nejsou v načtené hodnotě definovány bity 1,0 a pro 9 bitů pak nejsou definovány bity 2,1,0. Pokud tedy rutina pouze přečte 16-bitové číslo a nic jiného, pak platí pro :
DS18B20 -> teplota = hodnota/16
DS18S20 -> teplota = hodnota/2

Upřesnění pro Balůa:

Tazatel používá knihovní funkce Codevisionu - ta funkce ve svém těle dělá přesně to co píšeš, ale vrací vypočítanou hodnotu buď 10x vynásobenou, aby se vyhnuli používání float - to u DS1820.

nebo u DS18B20, ale i DS18S20 - při inicializaci si přečte scratch pad a podle toho se zařídí jak má přepočítávat výsledek - vrací pak naměřenou a přepočítanou hodnotu už ve tvaru float - třeba 25,5 .

A ještě na doplnění - u DS18B20 při 9 bitovém převodu je přesnost taky 0,5 stupně (jako u DS1820), ale doba převodu pouhých 93 ms - proti 750ms u 12bitového převodu - já používám těch 9bitů- je mi jedno, jestli mi to ukazuje telpotu 21,5 nebo přesnějších, ale 8x pomalejších 21,4 - nemluvě o tom, že přesnost měření je stejně ±0,5 stupně, tak na co měřit na desetiny :slight_smile: .

CodeVision nepoužívám (vlastě C nepoužívám pro mcu prakticky vůbec - zatím všechno assembler - a to včetně celkem rozsáhlých projektů), takže jsem nevěděl, že je takhle inteligentně napsaná.