Teploměr na bázi čidel DS18B20

Tomáš Žák : xzakto02@stud.feec.vutbr.cz a Vojtěch Veverka : xvever06@stud.feec.vutbr.cz

Obsah:

  1. Úvod
  2. Rozbor a realizace
  3. Teplotní čidlo DS18B20
  4. Výsledné zapojení
  5. Výpis programu
  6. Závěr
  7. Použitá literatura

Úvod

        Naším cílem bylo vytvořit teploměr založený na čidlech DS18B20 od firmy Dallas, konkrétně jsme použili 4 čidla, která jsou připojena na jednom pinu mikrokontroleru ATMEGA16.

Rozbor a realizace

        Realizace teploměru je provedena na jedné desce, kde je umístěn displej WH1602A, na kterém se zobrazuje snímaná teplota z jednotlivých čidel. Pro snížení spotřeby je displej nastaven tak, že po vyčtení jednotlivých teplot se vypne jeho podsvícení. Jsou zde přítomny i dvě tlačítka, první slouží pro zapnutí displeje a vyčtení jednotlivých teplot čidel a druhé tlačítko slouží jako reset. Na desce jsou přítomna celkem čtyři čidla, z čehož jedno je umístěno přímo na desce. Další tři čidla je možné připojit pomocí svorek. Všechna čidla jsou digitální a připojena na jeden pin MCU. Jedná se o čidla od firmy Dallas, konkrétně o typ DS18B20. Naměřená teplota je vyhodnocována v MCU, v našem případě je použitý mikrokontroler ATMEGA16 od firmy Atmel.

Teplotní čidlo DS18B20

        V našem projektu je jedno čidlo umístěno přímo na desce a další tři je možné připojit přes svorky. Komunikace mezi čidly a mikrokontrolerem probíhá pomocí jednovodičové komunikace (1.wire bus). Každé čidlo má svůj unikátní 64b identifikační kód, díky této identifikaci bylo možné připojit více čidel na jeden pin. Protože používáme více čidel na jednom pinu, je nejdříve nutné použít tzv. adresace, kdy je nejdříve zjištěno kolik čidel se nachází na jednom pinu a zároveň se zjišťují i jednotlivá identifikační čísla jednotlivých čidel. Teplotní rozsah jednotlivých čidel je od -55°C do 125°C s přesností +/- 0,5°C. Pro komunikaci s jednotlivými čidly byly využity knihovny obsažené v programu CodeVisionAVR. Popis komunikace mezi čidlem a mikrokontrolerem pro náš program je následující. Nejdříve je nutné provést tzv. Presence puls, kdy je zjištěno, zda-li se na sběrnici nacházejí nějaká čidla. V případě že jsou přítomny čidla, je pro inicializaci daného čidla použit příkaz MATCH ROM, hexadecimální hodnota příkazu je 0x55h. Po tomto příkazu jednotlivá čidla čekají na příchozí identifikační kód (ROM kód). Na sběrnici tedy posíláme identifikační kód čidla, se kterým budeme dále komunikovat. Pro změření teploty a její konvertování a následné uložení do scrathpadu čidla je možné použít příkaz CONVERT, který vyšleme opět na jednovodičovou sběrnici, hexadecimální hodnota příkazu je 0x44h. Následně je s čidlem ukončena komunikace. Pro vyčtení teploty je nutné opět nutné navázat komunikaci s čidlem. Opět se pošle Presence puls jako výše, opět se pošle na sběrnici příkaz MATCH ROM a následně ROM kód daného čidla, ze kterého budeme vyčítat teplotu. Pro vyčtení konvertované teploty ze scrathpadu čidla je použit příkaz READ SCRATHPAD, jehož hexadecimální hodnota je 0xBE. Po vyslání tohoto příkazu začne čidlo na sběrnici posílat hodnotu teploty, která je pomocí příkazu w1_read (vestavěná funkce knihovny 1.wire) ukládána do proměnné. Změřená teplota je v prvních příchozích 16 bitech. První čtyři bity nám určují znamínko. Dalších 8 bitů nám určuje celočíselnou hodnotu teploty a poslední čtyři bity nám určují desetiny a setiny teploty.

Výsledné zapojení

        Výsledné schéma zapojení vytvořené v programu EAGLE je uvedeno na obr. 1.



Obr. 1: Schéma teploměru

        Teploměr je napájen 5V, které je přivedeno na dolní svorku. Jednotlivá čidla jsou zapojena ve svorkách nad napájecí svorkou. Horní tlačítko, které je vpravo na obrázku slouží pro zobrazení teploty a tlačítko pod ním slouží jako reset. Výsledné zapojení je uvedeno na obr. 2


Obr. 2: Výsledné zapojení teploměru

        Na třetím obrázku je zobrazena hodnota teploty změřená čidlem, které je připojeno na první svorku (Vlevo nahoře).


Obr. 3: Měření teploty

Výpis programu

/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.3 Standard
Automatic Program Generator
© Copyright 1998-2011 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : Teplotni cidla DS18B20
Version : Final
Date    : 10.4.2013
Author  : Tomas Zak, Vojtech Veverka
Company : -
Comments: Projekt do predmetu MMIA


Chip type               : ATmega16
Program type            : Application
AVR Core Clock frequency: 16,000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 256
*****************************************************/

#include <mega16.h>                                                                                // Pridani knihovny ATMEGA16
// 1 Wire Bus interface functions
#include <1wire.h>                                                                                 // Knihovna pro komunikaci s cidlem pomoci 1.wire
// DS18B20 Temperature Sensor functions
#include <ds18b20.h>                                                                               // Knihovna pro zvolene cidlo DS18B20
#include <delay.h>                                                                                 // Knihovna zpozdeni
// Alphanumeric LCD functions
#include <alcd.h>
#include <stdio.h>
#include <stdlib.h>                                                                                
#define PA6 0x40                                                                                    // Zadefinovani nazvu PA6 na adresu 0x40
#define TX DDRA |= PA6                                                                              // Zadefinovani nazvu Tx pro poslani 0 na adresu v PA6
#define RX DDRA &= ~PA6                                                                             // Zadefinovani nazvu Rx pro poslani 1 na adresu v PA61
#define RXPIN PINA&PA6                                                                              // Zadefinovani nazvu RXPIN pro zkoumani, zda-li cidlo odpovedelo
char lcd_buffer[33];


 // POZOR NUTNO NASTAVIT PŘEVOD DO FLOAT U FUNKCE SPRINTF!!!  PROJECT -> CONFIGURE -> C COMPILER 


#define MAX_DEVICES 4                                                                               //Maximalni pocet cidel pripojenych na sbernici


unsigned char rom_code[MAX_DEVICES][9];                                                             // Velikost ulozeneho ROM codu z cisdla DS18B20

unsigned char cidla;                                                                                // Globalni promenna pro ulozeni poctu cidel na sbernici


unsigned char pocet_cidel(void)                                                                     // Funkce pro vypsani poctu cidel na sbernici z prom cidla
{
    lcd_gotoxy(1,0);                                                                                // Nastaveni pozice kurzoru na prvni radek
    sprintf(lcd_buffer,"Pocet cidel: %u",cidla);                                                    // Predani hodnoty z prom cidla do pole lcd_buffer
    lcd_puts(lcd_buffer);                                                                           // Funkce pro vypsani na LCD poctu cidel, kter jsou pritomny na sbernici
    return 0;
 }    
 
 
 unsigned char ow_detect_presence(void)                                                              // Funkce pro inicializaci cidel na sbernici (resp. jejich probrani)
{                                                                                                    // Jedna se o tzv. presencni puls.
    unsigned char out=1; 
    RX;                                                                                              // Vychozi stav sbernice
    delay_us(1000);                                                                                  // Pro ustaleni
    TX;                                                                                              // Bus low
    delay_us(480);                                                                                   // Cas pro prikaz reset
    RX;                                                                                              // Uvolneni sbernice
    delay_us(70);                                                                                    // Cekani na potvrzeni teplomerem
    if(RXPIN) out=0;                                                                                 // Pokud detekovana log.1, tak teplomer na sbernici neni
        delay_us(410);                                                                               // Pauza pred dalsi komunikaci
    return out;                                                                                      // Vrati stav 1=cidlo nalezeno, 0=cidlo nenalezeno
}
 
 

                                                                                                      // Nacte teplotu z teplomeru a vrati ji ve formatu 1000+t*10
                                                                                                      // Priklad: 23.5°C = 1235, -10.5°C = 895

unsigned int zmer(unsigned char vyber_cidlo)                                                          // Funkce pro zmereni teploty a prevod teploty do desetinne podoby
{
 unsigned char desetiny,j,scratchpad[9];
 signed char teplota;
 unsigned int tmp = 0, i=0;
 
    #asm ("cli");                                                                                      // Zakaze vsechna preruseni
    TX;                                                                                                // Nastavime 0 na adrese 0x40
     ow_detect_presence();                                                                             // Presencni puls
     
   
     w1_write(0x55);                                                                                   // Zapsani prikazu MATCH ROM na sbernici pro vyber cidla 
     i=0;
      
    j=vyber_cidlo;
   
    do                                                                                                  // Cyklus pro zapsani ROM CODE daneho cidla pro sbernici 1.wire
         w1_write(rom_code[j][i]);
    while (++i<8);
    
    w1_write(0x44);                                                                                     // Prikaz CONVERT T (konvertovani aktulni zmerene teploty do digitalni podoby
 
    delay_ms(300);                                                                                      // Zpozdeni potrebne pro konvertovani teploty 
  
 
    TX;
    ow_detect_presence();

 
     w1_write(0x55);
     i=0; 
  
     j=vyber_cidlo;
  
    do
        w1_write(rom_code[j][i]);
    while (++i<8);
 
    w1_write(0xBE);                                                                                     // Vyslani prikazu READ SCRATHPAD na sbernici 
   
    i=0;
    do                                                                                                  // Cyklus pro ulozeni vyctene teploty do prom. scratchpad
        scratchpad[i]=w1_read();
    while (++i<9);
     
  
 
 
 teplota = (scratchpad[0] & 0x0F0) >> 4 | (scratchpad[1] & 0x0F) << 4 ;                                 // Do prom. teplota ukladame do spodnich 4 bitu, 4 horni bity z prom scrachtpad[0]
                                                                                                        // A do hornich 4 bitu prom. teplota ukladame 4 spodni bity z prom. scratchpad [1] 
 tmp = 10 * teplota + 1000;                                                                             
 desetiny = (scratchpad[0] & 0x0F) * 0.625;                                                             // Do prom. Desetiny ukladam spodni 4 bity z prom scrathpad[0] a nasobim je konstantou 

 if(tmp<1000) tmp -= desetiny; else tmp += desetiny;
 if((tmp<700)||(tmp>2200)) tmp=0;                                                                       // Nastaveni meze teplot do kterych teplomer meri
 
 #asm ("sei");                                                                                          // Povoleni preruseni 
 
 
 return (unsigned int)tmp;                                                                              // Predani teploty 

} 




interrupt [EXT_INT1] void ext_int1_isr(void)                                                            // Externi preruseni vyvolane stiskem tlacitka
{
  
  
    float temperature;
    float teplota;
    unsigned char vyber=-1;
   
    #asm("cli");
    PORTB.0=1;                                                                                          // Poslani logicke 1 na PORT B pro roznuti displeje
    
    if(cidla>3 || cidla == 3)
    {
                                                                                                         
    vyber=2;                                                                                            // Promenna pro vyber daneho cidla
      temperature= zmer(vyber);                                                                         // Zavolani funkce zmer a ulozeni do prom temperature
      teplota = (temperature-1000)/10;                                                                  // Prepocet teploty na spravny tvar
     
     
     lcd_gotoxy(1,0);
     lcd_putsf("Cid.Deska:");
         
     lcd_gotoxy(4,1);
     sprintf(lcd_buffer,"%+.2f\xb2C",teplota);
     lcd_puts(lcd_buffer);
     delay_ms(5000);
     lcd_clear();
     
      }
      
      
      if(cidla>1 || cidla==1)
      {
     

     vyber=0;
      temperature= zmer(vyber);
      teplota = (temperature-1000)/10;
    
      lcd_gotoxy(1,0);
     lcd_putsf("Cid. Svr.1:");
         
     lcd_gotoxy(4,1);
     sprintf(lcd_buffer,"%+.2f\xb2C",teplota);
     lcd_puts(lcd_buffer);
     delay_ms(5000);
     lcd_clear();
     
     }  
     
     if(cidla>4 || cidla==4)
     {

          vyber=3;
      temperature= zmer(vyber);
      teplota = (temperature-1000)/10;
     
     
     lcd_gotoxy(1,0);
     lcd_putsf("Cid. Svr.2:");
         
     lcd_gotoxy(4,1);
     sprintf(lcd_buffer,"%+.2f\xb2C",teplota);
     lcd_puts(lcd_buffer);
     delay_ms(5000);
     lcd_clear(); 
     
     }
     
     
     if(cidla>2 || cidla==2)
     { 
     
         vyber=1;
      temperature= zmer(vyber);
      teplota = (temperature-1000)/10;
     
     
     lcd_gotoxy(1,0);
     lcd_putsf("Cid. Svr.3:");
         
     lcd_gotoxy(4,1);
     sprintf(lcd_buffer,"%+.2f\xb2C",teplota);
     lcd_puts(lcd_buffer);
     delay_ms(5000);
     lcd_clear();
     }


  PORTB.0=0;                                                                                                       // Uzemneni PINU 0 na PORTU B pro zhasnuti displeje
  #asm("sei");
}






void main(void)
{

float temperature;
float teplota;
unsigned char vyber=-1;

    DDRB=0x01;
    DDRD=0xF7;

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: On
    // INT1 Mode: Low level
    // INT2: Off
    GICR|=0x80;
    MCUCR=0x00;
    MCUCSR=0x00;
    GIFR=0x80;

    lcd_init(16);                                                                                                   // Inicializace displeje

    cidla=w1_search(0xf0,rom_code);                                                                                 // Zavolani funkce pro vyhledani cidel, ulozeni jejich rom codu a ulozeni jejich poctu do prom cidla
    
    PORTB.0=1;
    pocet_cidel();                                                                                                  // Zavolani funkce pro vypis poctu cidel na displej
    delay_ms(2000);                                                                                                 // Doba rozsviceni displeje
    lcd_clear();                                                                                                    // Vycisteni dispeleje
    lcd_gotoxy(2,0);
    lcd_putsf("Inicializace");
                                                                                                                                                               
     
    if(cidla>3 || cidla==3)
    {     
       
     vyber=2;
      
     temperature= zmer(vyber);
     teplota = (temperature-1000)/10;
    
    }
     
              
     if(cidla>1 || cidla==1)
     {
     
     vyber=0;


     temperature= zmer(vyber);
     teplota = (temperature-1000)/10;
    
     } 
    
    
    if(cidla>4 || cidla==4)
    { 
     
      vyber=3;


      temperature= zmer(vyber);
      teplota = (temperature-1000)/10;
         
     }
     
     
     if(cidla>2 || cidla==2)
     {     
     
      vyber=1;


      temperature= zmer(vyber);
      teplota = (temperature-1000)/10;
    
     }
      
     delay_ms(2000);                                                                                                
     lcd_clear();
     
     lcd_gotoxy(2,0);
     lcd_putsf("Pro teplotu");
     lcd_gotoxy(1,1);
     lcd_putsf("Horni tlacitko");
     
     delay_ms(2000);                                                                                                
     lcd_clear();
     
     PORTB.0=0;

#asm("sei");
while (1)

      {   
     
   
     
      }   
  
}

Závěr

        Cílem projektu bylo vytvořit funkční teploměr, který bude schopen měřit teplotu ze čtyř čidel připojených na jednom pinu mikrokontroleru. Výsledný navržený teploměr je plně funkční. Aby spotřeba teploměru nebyla zbytečně velká, bylo použito vypínání podsvětlení displeje. Při zmáčknutí horního tlačítka tedy dojde nejdříve k zapnutí podsvětlení displeje a následně jsou vyčítány teploty jednotlivých čidel. V případě možného provozu na baterii by bylo možné ještě využít funkce sleep mode u mikrokontroleru pro ještě větší úsporu. Dolní tlačítko je využito pro reset teploměru.


Celý projekt je možné stáhnout zde

Použitá literatura


[1] http://www.hw.cz/navrh-obvodu/software/codevisionavr.html/
[2] http://www.builder.cz/cz/forum/tema-1272313-teplomer-s-ds18b20/
[3] FRÝZA,T., FEDRA Z., ŠEBESTA. J.: Mikroprocesorová technika - Laboratorní cvičení. Vývojová deska ATmega16. str. 45. Dostupné na WWW: https://krel.feec.vutbr.cz/VYUKA/M_EST/MMIA/Texty/bmpt_laboratore.pdf