OK

Při poskytování služeb nám pomáhají soubory cookie. Používáním našich služeb vyjadřujete souhlas s naším používáním souborů cookie. Více informací

Úvodní stránka » Arduino » Arduino v příkladech - XII. díl - Displej a měření teploty I

Arduino v příkladech - XII. díl - Displej a měření teploty poprvé

Už podle názvu zbytečný článek. O měření teploty je toho na webu až dost. My se na to podíváme úplně jinak a mohu Vám slíbit, že toto na webu nikde nenajdete.

Když jsem poprvé měřil teploty s čidly DS 18B20, pěkně jsem si nejdříve nahrál program na zjišťování adres, ty zapsal jako pevnou proměnnou pak nahrál program měření teplot s knihovnou DallasTemperature a měřil. Nějak zlobily tlačítka a i rozlišení čidla si tak nějak dělalo co chtělo. Tak si zase prošlapeme jednu slepou uličku.

Zabývat se budeme pouze čidlem DS18B20, dnes jiná ani pro běžné měření ani nepoužívám. Jedná se o kalibrované čidlo teploty s nízkou spotřebou, pro běžné účely s dostačujícím rozsahem měření, dostatečně rychlou odezvou, existují verze co můžete strčit i do vody a měřit teplotu vody v kotli, kabel lze vést bez problému desítky metrů,  nastavit rozlišení až 12 bit, vejde se do hodinek a cena je v řádech desetikorun. Čidla od stejného výrobce, např. DS 18S20 a tomu podobná, oproti DS 18B20 nepřinášejí žádnou výhodu, tedy vyjma pár ušetřených korun.

Měření teploty

To divné chování tlačítek a rozlišení je způsobeno použitou knihovnou.  Když pošleme čidlu příkaz k měření teploty, probíhá konverze, která může podle nastavení rozlišení trvat až 750 millisekund. Podle mého programu trvá 657 millisekund. Knihovna to řeší příkazem delay(), tedy čekáme. V rozlišení je drobná chybička ve výpočtu po bitovém posunu a tak si to dělá co chce. A´t dělám co dělám, můj program funguje správně i po bitovém posunu.

Vzorový program z knihovny vypadá takto:

// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;

/* * Setup function. Here we do the basics */
void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");

  // locate devices on the bus
  Serial.print("Locating devices...");
  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: ");
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");
  
  // Assign address manually. The addresses below will beed to be changed
  // to valid device addresses on your bus. Device address can be retrieved
  // by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  // Note that you will need to use your specific address here
  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };

  // Method 1:
  // Search for devices on the bus and assign based on an index. Ideally,
  // you would do this to initially discover addresses on the bus and then
  // use those addresses and manually assign them (see above) once you know
  // the devices on your bus (and assuming they don't change).
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
  
  // method 2: search()
  // search() looks for the next device. Returns 1 if a new address has been
  // returned. A zero might mean that the bus is shorted, there are no devices,
  // or you have already retrieved all of them. It might be a good idea to
  // check the CRC to make sure you didn't get garbage. The order is
  // deterministic. You will always get the same devices in the same order
  //
  // Must be called before search()
  //oneWire.reset_search();
  // assigns the first address found to insideThermometer
  //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");

  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
  sensors.setResolution(insideThermometer, 9);
 
  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC);
  Serial.println();
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  // method 1 - slower
  //Serial.print("Temp C: ");
  //Serial.print(sensors.getTempC(deviceAddress));
  //Serial.print(" Temp F: ");
  //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit

  // method 2 - faster
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}
/* * Main function. It will request the tempC from the sensors and display on Serial. */
void loop(void)
{
  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  
  // It responds almost immediately. Let's print out the data
  printTemperature(insideThermometer); // Use a simple function to print out the data
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

Vlastní program, který nečeká lze přitom napsat úplně snadno, stačí použít ty správné příkazy. Ukážeme si příklad, který využijeme i dále. Při spuštění programu si načteme adresy připojených čidel, uložíme je do paměti EEPROM a pak každých 5 vteřin budeme číst teplotu. Je to napsané tak, že se na nic nečeká. Program samostatně popisovat nebudu, je podrobně okomentovaný a je spíše na ukázku. Využít ho samozřejmě můžete kde se Vám zachce.

//------------------------------------------------------------------
// inicializace zakladnich knihoven
#include <OneWire.h> // knihovna pro komunikaci 1-wire
#include <EEPROM.h> // knihovna pro zapis do pameti eeprom
//------------------------------------------------------------------
// nastaveni nazvu pinu
#define DS_18B20          3 // vstup pro cidla DS 18B20
//------------------------------------------------------------------
// pocet cidel
#define numberOfSensors   8 // maximalni pocet cidel DS 18B20
//------------------------------------------------------------------
// Nastaveni komunikace cidel DS 18B20
OneWire ds18B20(DS_18B20); // nastaveni komunikace cidel po sbernici oneWire
//------------------------------------------------------------------
// promenne teploty
float teplota[numberOfSensors];
unsigned long casCteniTeplot; // cas posledniho cteni
boolean povolCteniTeplot = false;
byte ID_teploty; // ID pro aktualizaci teploty v pripade nastaveni teplot
unsigned long prodlevaCteniTeplot = 5000; // nastaveni periody cteni teploty
byte resolutionDS = 12; // nastaveni rozliseni cidla
//------------------------------------------------------------------
// pole adres cidel DS 18B20 - 8 pozic dalsi volna adresa 624
//const int cidlaDS_i[] = {560, 568, 576, 584, 592, 600, 608, 616};
const int cidlaDS_i = 560; // prvni adresa EEPROM pro zapis adres cidel
//------------------------------------------------------------------
void setup() {
  //------------------------------------------------------------------
  Serial.begin(9600); // seriova komunikace
  //------------------------------------------------------------------
  // vyhleda a ulozi adresy teplotnich cidel
  hledaniDS18B20(); // vyhleda a ulozi adresy teplotnich cidel
}
//------------------------------------------------------------------
void loop() {
  //------------------------------------------------------------------
  // cast programu pro cteni teplot
  if (!povolCteniTeplot) { // kdyz je zakazano cteni teplot
    if ((unsigned long)(millis() - casCteniTeplot) >= prodlevaCteniTeplot) { // cekej na uplynuti prodlevz
      spustKonverzi();
    }
  }
  else { // jinak je povoleno cteni teplot
    if (ds18B20.read()) { // zkontroluj zda jsou data k dispozici
      cteniTeplot(); // precist hodnoty cidel teploty
    }
  }
}
//------------------------------------------------------------------
// cast programu pro cteni teplot
void cteniTeplot() { // precte teploty ulozenych cidel
  byte data[12];
  byte address[8];
  byte count;
  Serial.println(F("Dalsi cteni teploty"));
  Serial.println("Doba konverze: " + (String)(millis() - casCteniTeplot) + " millis");
  ds18B20.depower();
  for (int id = 0; id < numberOfSensors; id++) { // nastav odresu EEPROM cidla
    count = 0;
    for (int i = cidlaDS_i + (id * 8); i < cidlaDS_i + (id * 8) + 8; i++) { // precti adresy
      address[count] = EEPROM.read(i);
      count++;
    }
    ds18B20.reset(); // resetuj nastaveni oneWire
    ds18B20.select(address); // vyber adresu aktualniho cidla
    ds18B20.write(0xBE); // cti zasobnik cidla
    for (int i = 0; i < 9; i++) { // precti prvnich 9 bitu, bez CRC kodu
      data[i] = ds18B20.read();
    }
    if (address[0] == 255 || data[0] == 255) teplota[id] = NULL; // kdyz neni cidlo ulozeno, nebo nejsou data k dispozici
    else {
      uint16_t temp;
      if (resolutionDS == 12) temp = 127; // 12 bit res, 750 ms
      else if (resolutionDS == 11) temp = 95; // 11 bit res, 375 ms
      else if (resolutionDS == 10) temp = 63; // 10 bit res, 187.5 ms
      else temp = 31; // 9 bit res, 93.75 ms
      if (data[4] != temp) { // kdyz neni nastaveno pozadovane rozliseni
        uint16_t tmpResolution;
        tmpResolution = (resolutionDS - 9) * 32;
        ds18B20.reset();
        ds18B20.select(address);
        ds18B20.write(0x4E);         // zapis do zasobniku
        ds18B20.write(0x00);            // TL
        ds18B20.write(0x00);            // TH
        ds18B20.write(tmpResolution);         // Nastav nove rozliseni
        ds18B20.write(0x48);         // kopiruj zasobnik
        ds18B20.reset();
      }
      int16_t raw = (data[1] << 8) | data[0];
      Serial.print("RAW: " + String(raw) + " ");
      teplota[id] = (float)raw / 16;
      Serial.print("Cidlo " + (String)(id + 1) + ": ");
      Serial.print(teplota[id], 4);
      Serial.println(" C");
    }
  }
  povolCteniTeplot = false;
  Serial.println();
}
//------------------------------------------------------------------
// konverze teplot cidel
void spustKonverzi() {
  casCteniTeplot = millis(); // nastav novy cas cteni
  ds18B20.reset(); // resetuj nastaveni oneWire
  ds18B20.write(0xCC); // nastav konverzi pro vsechny cidla
  ds18B20.write(0x44); // start interni konverze teploty
  povolCteniTeplot = true;
}
//------------------------------------------------------------------
// hleda adresy teplotnich cidel DS 18B20

void hledaniDS18B20() {
  byte address[8];
  byte id;
  ds18B20.reset_search(); // resetuj hledani
  if (ds18B20.search(address)) { // hledej adresy
    for (id = 0; id < numberOfSensors; id++) { // zapis data do displeje
      String stringText;
      for (byte i = 0; i < 8; i++) { // precti a uloz adresy
        EEPROM.write(cidlaDS_i + (id * 8) + i, address[i]);
        stringText += address[i], DEC;
        if (i < 8 - 1) stringText += ",";
      }
      Serial.println("Cidlo " + (String)(id + 1) + ": " + stringText);
      if (!ds18B20.search(address)) {
        ds18B20.reset_search();
        Serial.println(F("Zadne dalsi cidlo nenalezeno"));
        break;
      }
    }
    Serial.println("Nalezeno " + (String)(id + 1) + " cidel.");
    Serial.println();
  }
}

Klíčové věci se Vám vypisují na Serial monitor. Jenom si dejte pozor při práci s pamětí EEPROM, ať si počtem čidel nepřepíšete jiná data.

POZOR – program je napsán tak že nereflektuje parazitní napájení. Jen to zapojte pěkně poctivě, po třech drátech.

V dalším díle si to vše hezky zaplikujeme.

JB

jaroslav.bohac@arduinotech.cz

Přidat komentář

Zvýrazněné položky jsou povinné.


TOP produkty

NodeMCU s ESP8266

NodeMCU s ESP8266
350 Kč s DPH

Arduinotech GSM shield

Arduinotech GSM shield
877 Kč s DPH

Kontakt

Ing. Petr Foltýn
Kunčice pod Ondřejníkem 814, 73913
TOPlist