Ingo Electronics


    HOME                                                           Stellaris LM4F120 LaunchPad


Stellaris LM4F120  LauncPad.    DS18B20 OneWire Library and  example of use

Ši tema skirta parodyti kaip naudoti DS1820/DS18B20/DS18S20 skaitmeninį temperatūrinį sensorių.

Yra gana paprasta pajungti kelis DS1820 sensorius ant vienos linijos, reikalinga tik du maitinimo laidai ir vienas duomenų laidas, kaip parodyta žemiau esančiame paveikslėlyje.

onewire_sch

Kiekvienas DS1820 sensorius turi unikalų 64-bitų kodą, kuris yra naudojamas  komandoms adresuoti.

Jeigu linijoje yra tik vienas sensorius, tai adresavimas nenaudojamas, ir į sensorių kreipiamasi tiesiogiai.

 Funkcijų biblioteka, kuri čia aprašyta, palaiko vieną arba keletą DS1820 sensorių.

 
Šiam projektui reikalingi du papildomi failai.

Atliekame veiksmus kaip buvo aprašyta prieš tai buvusioje temoje, t.y
į StellarisWare direktorijoje sukurtą aplanką MyLib įkeliame
DS1820 funkcijų bibliotekos du failus: One_Wire_lib.c ir One_Wire_lib.h.

Sukuriame naują CSS projektą ir projekto direktorijoje pridedame naują aplanką kurį taip pat galime pavadinti kaip tik norime, pvz. user_lib
Naujas aplankas CCS projekto direktorijoje sukuriamas taip:

File->New->Folder----Folder name: --- įrašome pavadinimą -----Finish

 
Toliau galimi du variantai:
1.Jeigu DS1820 pajungimo nekeisime ir mikrokontroleris dirbs 50Mhz, t.y nustatymai paliekami pagal nutylėjimą (default), tuomet užtenka tik nurodyti kelią(link'ą) iki reikiamo c failo:
- Su dešiniu pelės klavišu pasirenkame Add Files..susirandame anksčiau sukurtą MyLibaplanką ir jame pažymime failą One_Wire_lib.c  spaudžiam Open atsidariusiame lange pažymime Link to files , spaudžiamOK .

Projekto direktorijoje atsiranda naujas failas su nedidele rodikle, rodyklė reiškia kad tai yra nuoroda į šį failą.
Šį naujai atsiradusį failą pelės pagalba nutempiame į jau anksčiau projekto direktorijoje sukurtą aplanką user_lib
Tuom OneWire failų bibliotekos įkėlimas baigiamas, programos kode nurodome:

 #include "MyLib/ One_Wire_lib.h "

 reikia atkreipti dėmesį, kad yra nurodoma direktorija MyLib, o ne user_lib.
Turime gauti vaizdą kaip parodyta pav.:

Capture17

 
2.Jeigu LCD prijungimą prie mikrokontrolerio norime pakeisti arba mikrokontroleris dirbs kitokiu, nei 50Mhz dažniu, tuomet patartina į projekto direktoriją įkelti pilnas reikiamų failų kopijas,šiuo atveju reikalinga įkelti abu c ir h failus.
- Su dešiniu pelės klavišu pasirenkame Add Files... susirandame anksčiau sukurtą MyLib aplanką, jame pasižymime abu failus One_Wire_lib.c ir One_Wire_lib.h spaudžiam Open atsidariusiame lange pažymim Copy files, spaudžiam OK.
Abu failai (šių failų kopijos) atsiranda projekto direktorijoje, kuriuos pelės pagalba nutempiame į anksčiau projekto direktorijoje sukurtą aplanką user_lib
Dabar atsidarius šiuos failus iš projekto direktorijos, galime juos redaguoti, orginalūs failai esantysMyLib išliks nepakitę.
Tačiau dabar programos kode, nurodome #include "user_lib/ One_Wire_lib.h ", atkreipdami dėmesį, į tai kad yra nurodoma user_lib, o ne MyLib.
Turime gauti vaizdą kaip parodyta pav.:

 Capture18

One_Wire_lib.c ir One_Wire_lib.h galima parsisiūsti iš čia: Link

 
Jeigu reikia DS1820 pajungti prie kurio nors kito mikrovaldiklio pino ar porto, arba mikrovaldiklis dirba kitokiu dažniu, negu defaul, tuomet One_Wire_lib.h faile reikia paredaguoti  keletą žemiau parodytų eilučių(pažymėta raudonai):

//!!!You can rewrite these two lines as you need
//by default DS18B20 is connected to PORTA PIN6

#define onewire_Peripheral     SYSCTL_PERIPH_GPIOA
#define port_output            GPIO_PORTA_BASE
#define Pin_IO                 GPIO_PIN_6

 //by default these definitions are  is for 50 MHz processor speed
//you must recalculate definitions if you are using another as shown

#define delay_250us   4166     // =(SysCtlClockGet()/3000000)*250   //for example  (50000000/3000000)*250=4166
#define delay_200us   3333     // =(SysCtlClockGet()/3000000)*200
#define delay_50us    833      // =(SysCtlClockGet()/3000000)*50
#define delay_30us    500      // =(SysCtlClockGet()/3000000)*30
#define delay_20us    333      // =(SysCtlClockGet()/3000000)*20
#define delay_10us    166      // =(SysCtlClockGet()/3000000)*10
#define delay_1us     8        // =(SysCtlClockGet()/3000000)/2

 

 Kaip jau buvo minėta, keletas sensorių gali būti pajungti ant vieno ir to paties laido, tokiu atveju reikia nustatyti kiekvieno daviklio adresą (64-bitų kodą). Kaip tai yra padaroma programiniu būdu, bus parodyta vėliau, dabar paimame paprastesnį variantą, kai linijoje yra tik vienas daviklis, tuomet daviklio adresas nereikalingas:

 
Programos kode pirmiausia rašome:

onewire_init();

Ši funkcija nurodys prie kokio porto ir kokio pino yra pajungtas sensorius.

Sekanti eilutė turėtų būti funkcija:

 write_scr(0x00,0x00,RESOLUTION_10bit);

Su šia funkcija yra nustatoma kokia rezoliucija bus vykdoma konvertacija ir perduodami duomenys mikrovaldikliui. Galime nustatyti 9,10,11,12 bitų rezoliucijas pasirinkę iš One_Wire_lib.h failo.

 
Toliau galime pereiti į while ciklą:

Pirmiausia rašoma funkcija:

temp_convert();

tai komanda sensoriui išmatuoti šiuo metu esamą temperatūros reikšmę. Po šios komandos reikia davikliui duoti šiek tiek laiko kol bus vykdoma konvertacija, kuo didesnė rezoliucija, tuom reikalingas didesnis laikas, tiksliau apie tai galima pasiskaityti DS1820 aprašyme.

Po to jau galime nuskaityti temp. reikšmę su funkcija  read_ds1820_one(); - ši funkcija yra naudojama kai linijoje yra tik vienas daviklis ir netikrinama ar teisingai perduoti/priimti duomenys t.y CRC.  Šios funkcijos rezultatas, priklausomai nuo pasirinktos rezoliucijos yra 9,10,11 arba 12 bitų skaičius, iš kurių pirmi aštuoni bitai iš kaires yra sveikasis skaičius, like bitai, priklausomai nuo rezoliucijos, yra skaičiai po kablelio.  Skaičius po kablelio išskiriame su funkcija fraction(unsigned int temp_byte);

Su gautomis temp. reikšmėmis galime daryti ką tik norime, perduoti displėjų,pasiusti duomenis į PC, įrašyti į eeprom ar pagal apibrėžtas sąlygas valdyti kokį nors įrenginį ir t.t

Žemiau pateikto kodo pavyzdyje, temp reikšmė perduodama į LCD displėjų, kurio pajungimas ir programavimas buvo aprašytas ankstesnėje temoje.

 

Programavimo pavyzdys:
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

#include "inc/hw_types.h"

#include "inc/hw_memmap.h"

#include "inc/hw_sysctl.h"

#include "inc/hw_gpio.h"

#include "driverlib/sysctl.h"

#include "driverlib/gpio.h"

#include "driverlib/stdlib.h"//for ltoa(..);

#include "MyLib/LCD_16x2_595_lib.h"

#include "user_lib/One_Wire_lib.h"

 

//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

unsigned int  TD1temp;

 

unsigned int  TD1temp_fract;

 

char buf[9];

 

unsigned int nr;

//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

void main() {

 

           // Setup the system clock to run at 50 Mhz from PLL with crystal reference

           SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

 

              SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

 

              GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);

              GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0x00);

 

 

                  LCD_16x2_595_init();

 

                     LCD_595_Init();

 

                     Lcd_595_Cmd(LCD_CURSOR_OFF);

 

                     Lcd_595_text(2,4,"Elektronika");

 

                     onewire_init();

            //!!! init DS18B20 resolution

                     write_scr(0x00,0x00,RESOLUTION_10bit);

 

 

              while(1){

 

                     temp_convert();

                     SysCtlDelay(6250000);//conversion time 750ms

 

                     TD1temp = read_ds1820_one();

 

                     TD1temp_fract = fraction(TD1temp);

 

                     TD1temp = TD1temp >>4;

 

              if(signFlag == 0){Lcd_595_Chr(1, 5, '+');};

              if(signFlag == 1){Lcd_595_Chr(1, 5, '-');};

 

                     ltoa(TD1temp, buf);

                     Lcd_595_text(1,6,buf);

                     Lcd_595_Chr_Cp('.');

 

                     ltoa(TD1temp_fract, buf);

                     Lcd_595_text_Cp(buf);

}

 

}

//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

 

 

Jeigu norima patikrinti ar teisingai iš DS1820 yra priimami duomenys, tuomet viską darome kaip ir prieš tai, tik vietoje funkcijos read_ds1820_one(); panaudojame funkciją read_ds1820_one_crc(); kuri papildomai grąžina du parametrus: crc_byte – tai baitas kurį siunčia DS1820 ir crc8 – tai baitas kurį paskaičiuoja mikrokontroleris.

Jeigu šie du baitai yra vienodi, skaitome, kad duomenys yra priimti teisingai. Žemiau yra pateiktas kodo pvz. , kuriame indikacijai papildomai dar yra įvestas  PORTF PIN1 (RED LED).

 

Programavimo pavyzdys:
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

#include "inc/hw_types.h"

#include "inc/hw_memmap.h"

#include "inc/hw_sysctl.h"

#include "inc/hw_gpio.h"

#include "driverlib/sysctl.h"

#include "driverlib/gpio.h"

#include "driverlib/stdlib.h"//for ltoa(..);

#include "MyLib/LCD_16x2_595_lib.h"

#include "user_lib/One_Wire_lib.h"

 

//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

unsigned int  TD1temp;

unsigned int  TD1temp_fract;

char buf[9];

unsigned int nr;

 

//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

void main() {

 

           // Setup the system clock to run at 50 Mhz from PLL with crystal reference

           SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

 

              SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

              GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);

              GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);

 

 

                  LCD_16x2_595_init();

 

                     LCD_595_Init();

 

                     Lcd_595_Cmd(LCD_CURSOR_OFF);

 

                     Lcd_595_text(2,4,"Elektronika");

 

                     onewire_init();

                     //!!! init DS18B20 resolution

                     write_scr(0x00,0x00,RESOLUTION_10bit);

 

 

              while(1){

 

                     temp_convert();

                     SysCtlDelay(12500000);//conversion time

 

                     TD1temp = read_ds1820_one_crc();

 

                     if((crc_byte==crc8)&&(crc_byte!=0x00))

                     {

                     GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);

 

                     TD1temp_fract = fraction(TD1temp);

 

                     TD1temp = TD1temp >>4;

 

              if(signFlag == 0){Lcd_595_Chr(1, 5, '+');};

              if(signFlag == 1){Lcd_595_Chr(1, 5, '-');};

 

                     ltoa(TD1temp, buf);

                     Lcd_595_text(1,6,buf);

                     Lcd_595_Chr_Cp('.');

 

                     ltoa(TD1temp_fract, buf);

                     Lcd_595_text_Cp(buf);

                     }

                     else

                     {

                           GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);

                     }

 

}//end while

 

}//end main

//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''




Kaip jau buvo minėta anksčiau, keletas daviklių gali būti prijungti prie vienos linijos. Darbo metu, tam  kad sensorius suprastu ar mikrovaldiklis kreipiasi būtent į jį, reikalinga nustatyti kiekvieno daviklio adresą (unikalus 8 baitų  kodas).  Kaip tai programiniu būdu daroma yra parodyta sekančiame pvz.:

Kaip ir prieš tai buvusiame pvz. Pradedama nuo funkcijos;

onewire_init();

Duodama komanda Reset:

Reset();

Toliau yra rašomas sensorių paieškos algoritmas:

Pagal default maksimalus daviklių kiekis yra 4. Jeigu yra planuojama pajungti daugiau daviklių, tuomet One_Wire_lib.h faile pakeičiame dviklių skaičių, redaguodami žemiau parodytą eilutę:

#define ds1820_quant  4        //sensors points on the line

 

//ds1820_nm – yra daviklio elės numeris
 

                              OWFirst();

                     ds1820_nm =0;

                     for (nr = 0; nr<8; nr++) {

                     ds1820_code [ds1820_nm] [nr] = ROM_NO[nr];

                     }

 

                     while(OWNext()){

                     ds1820_nm ++;

                     for (nr = 0; nr<8; nr++) {

                     ds1820_code [ds1820_nm] [nr] = ROM_NO[nr];

                     }

                     }

 

 Po šio kodo, mikrovaldiklis į buferį  ds1820_code [ds1820_nm] [nr] surašo visus linijoje esančių sensorių adresus.

 

Toliau, kaip ir ankstesniame pvz. rašome funkciją  kuri nustato kokia rezoliucija bus vykdoma konvertacija ir perduodami duomenys mikrovaldikliui. Ši funkcija konvertavimo rezoliuciją įrašys visiems davikliams  tokią, kokia buvo užduota funkcijoje. Jeigu būtų reikalingi davikliai su skirtingomis rezoliucijomis, tuomet nesunku savarankiškai pasirašyti reikalingą funkciją.

Tuom sensorių inicializacija yra baigiama ir galima pereiti į while ciklą. Viskas išlieka tas pats, tik dabar naudojame funkcijas :

read_ds1820_multi_one(X);

arba

read_ds1820_multi_one_crc(X);

kur vietoje X įrašome daviklio eilės numerį pvz.: 1,2,3...ir t.t

 

// Programavimo pavyzdys:

#include "inc/hw_types.h"

#include "inc/hw_memmap.h"

#include "inc/hw_sysctl.h"

#include "inc/hw_gpio.h"

#include "driverlib/sysctl.h"

#include "driverlib/gpio.h" 

#include "driverlib/stdlib.h"//for ltoa(..);

#include "MyLib/LCD_16x2_595_lib.h"

#include "user_lib/One_Wire_lib.h"

 

//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

unsigned int  TD1temp;

unsigned int  TD1temp_fract;

char buf[9];

unsigned int nr;

unsigned int ds1820_nm;  //termodaviklio eiles numeris

 

 

//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

void main() {

 

           // Setup the system clock to run at 50 Mhz from PLL with crystal reference

           SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

 

              SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

              GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);

              GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);

 

 

                  LCD_16x2_595_init();

 

                     LCD_595_Init();

 

                     Lcd_595_Cmd(LCD_CURSOR_OFF);

 

                     Lcd_595_text(2,4,"Elektronika");

 

                     onewire_init();

 

                     Reset();

 

                     OWFirst();

                     ds1820_nm =0;

                     for (nr = 0; nr<8; nr++) {

                     ds1820_code [ds1820_nm] [nr] = ROM_NO[nr];

                     }

 

                     while(OWNext()){

                     ds1820_nm ++;

                     for (nr = 0; nr<8; nr++) {

                     ds1820_code [ds1820_nm] [nr] = ROM_NO[nr];

                     }

                     }

 

 

            //lcd displejuje parodome kiek mikrovaldiklis rado pajungtu sensoriu

                     ds1820_nm =ds1820_nm+1;

                     ltoa(ds1820_nm, buf);

                     Lcd_595_text(1, 1, "Pajungta") ;

                     Lcd_595_text(2, 1, buf) ;

                     SysCtlDelay(25000000);

                     Lcd_595_Cmd(LCD_CLEAR);

 

                     //konvertavimo rezoliucija nustatoma visiems davikliams iskart ir vienoda

                     //!!! init DS18B20 resolution

                     write_scr(0x00,0x00,RESOLUTION_10bit);

 

                     Lcd_595_Cmd(LCD_CLEAR);

 

 

              while(1){

 

                     temp_convert();

                     SysCtlDelay(12500000);//conversion time

 

                     TD1temp = read_ds1820_multi_one_crc(1);

 

                     if((crc_byte==crc8)&&(crc_byte!=0x00))

                     {

                     GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);

 

                     TD1temp_fract = fraction(TD1temp);

 

                     TD1temp = TD1temp >>4;

 

              if(signFlag == 0){Lcd_595_Chr(1, 5, '+');};

              if(signFlag == 1){Lcd_595_Chr(1, 5, '-');};

 

                     ltoa(TD1temp, buf);

                     Lcd_595_text(1,6,buf);

                     Lcd_595_Chr_Cp('.');

 

                     ltoa(TD1temp_fract, buf);

                     Lcd_595_text_Cp(buf);

                     }

                     else

                     {

                           GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);

                     }

 

}//end while

 

}//end main

//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''