Arduino v příkladech - XIII. díl - Displej a měření teploty podruhé
Navazujeme na předchozí díl praktickým příkladem.
Měření teploty na displeji
Konečně něco, co dělá něco užitečného. Ukážeme si měření teploty ještě jinak a současně ho zobrazíme na displeji, umožníme měnit rozlišení a přiřadit čidla k jednotlivým místnostem. Ušetří Vám to práci při psaní programu, prostě napíšete a pak v klidu přiřadíte čidla, nebo ho někdy prostě vyměníte. Pokud čidlo není přiřazeno, nebo je odpojeno, vrací Vám to do proměnné teploty hodnotu NULL. S tím se už dá pracovat.
//------------------------------------------------------------------
// inicializace zakladnich knihoven
#include <OneWire.h> // knihovna pro komunikaci 1-wire
#include <EEPROM.h> // knihovna pro zapis do pameti eeprom
#include <SPI.h> // knihovna pro komunikacni rozhrani SP
#include <TFT_ILI9341.h> // knihovna displeje
#include <UTouch.h> // knihovna dotykové části
//------------------------------------------------------------------
// nastaveni nazvu pinu
//#define sclk 13 // Don't change, this is the hardware SPI SCLK line
//#define miso 12 // Don't change, this is the hardware SPI MISO line
//#define mosi 11 // Don't change, this is the hardware SPI MOSI line
#define TFT_CS 10 // Chip select for TFT display, don't change when using F_AS_T
#define TFT_DC 9 // Data/command line, don't change when using F_AS_T
//#define TFT_RST 8 // Reset, you could connect this to the Arduino reset pin
#define TOUCH_CLK 7 // Touch SCLK
#define TOUCH_CS 6 // Touch chip select
#define TOUCH_DIN 5 // Touch MOSI
#define TOUCH_DOUT 4 // Touch MISO
#define DS_18B20 3 // vstup pro cidla DS 18B20
#define TOUCH_IRQ 2 // Touch IRQ
//------------------------------------------------------------------
// 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 tempResolution; // pomocna promenna pro upravu 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 resolutionAdd = 559; // adresa EEPROM nastaveni rozliseni cidla
const int cidlaDS_i = 560; // prvni adresa EEPROM pro zapis adres cidel
//------------------------------------------------------------------
// Promenne a nastaveni vstupu displej
TFT_ILI9341 tft = TFT_ILI9341(TFT_CS, TFT_DC);
// UTouch(byte clk, cs, din, dout, irq)
UTouch touch(TOUCH_CLK, TOUCH_CS, TOUCH_DIN, TOUCH_DOUT, TOUCH_IRQ);
//------------------------------------------------------------------
// Promenne displej
unsigned long casProdlevyDotyk; // cas posledniho dotyku
const byte prodlevaDotyk = 200; // nastaveni prodlevy mezi dotykem
boolean vypniDotyk = true; // povoleni
byte TFT_rotation = 2; // nastaveni otoceni displeje
byte TOUCH_rotation; // nastaveni orientace dotykove plochy
int x; // radek x displej
int y; // radek y displej
byte stranka = 0; // cisla zobrazenych stranek
byte IDmistnosti; // pomocna hodnota pro prirazeni cidla mistnosti
//------------------------------------------------------------------
// Vytvoreni promennych pro tlacitka
struct defineButton {
int x;
int y;
int width;
int height;
int color;
char* text;
byte font;
};
//------------------------------------------------------------------
// Vytvoreni jednotlivych tlacitek
defineButton buttonNastaveni = {60, 260, 120, 50, TFT_LIGHTGREY, "NASTAVENI", 2};
defineButton buttonZpet = {60, 260, 120, 50, TFT_LIGHTGREY, "ZPET", 2};
defineButton buttonCidlo = {40, 40, 160, 50, TFT_LIGHTGREY, "VYBER CIDLA", 2};
defineButton buttonSmazat = {40, 110, 160, 50, TFT_LIGHTGREY, "SMAZAT CIDLA", 2};
defineButton buttonRozliseni = {40, 180, 160, 50, TFT_LIGHTGREY, "NASTAVENI ROZLISENI", 2};
defineButton buttonStorno = {130, 260, 100, 50, TFT_LIGHTGREY, "STORNO", 2};
defineButton buttonUlozit = {10, 260, 100, 50, TFT_LIGHTGREY, "ULOZIT", 2};
defineButton button1 = {0, 40, 240, 27};
defineButton button2 = {0, 67, 240, 27};
defineButton button3 = {0, 94, 240, 27};
defineButton button4 = {0, 121, 240, 27};
defineButton button5 = {0, 148, 240, 27};
defineButton button6 = {0, 175, 240, 27};
defineButton button7 = {0, 202, 240, 27};
defineButton button8 = {0, 229, 240, 27};
defineButton buttonUP = {10, 100, 60, 60, TFT_GREEN};
defineButton buttonDOWN = {170, 100, 60, 60, TFT_GREEN};
//------------------------------------------------------------------
void setup() {
tft.init(); // inicializace TFT displeje
tft.setRotation(TFT_rotation); // nastaveni orientace displeje
tft.setTextColor(TFT_BLACK); // nastaveni barvy pisma
//------------------------------------------------------------------
if (TFT_rotation == 0 || TFT_rotation == 2) TOUCH_rotation = PORTRAIT; // nastaveni otoceni dotykove plochy
else if (TFT_rotation == 1 || TFT_rotation == 3) TOUCH_rotation = LANDSCAPE; // nastaveni otoceni dotykove plochy
touch.InitTouch(TOUCH_rotation); // inicializuje dotykovou plochu
touch.setPrecision(PREC_MEDIUM); // nastavi citlivost dotykove plochy
//------------------------------------------------------------------
// pokud neni zadano nastav rozliseni
if (EEPROM.read(resolutionAdd) < 9 && EEPROM.read(resolutionAdd) > 12) EEPROM.write(resolutionAdd, 9);
//------------------------------------------------------------------
// zobrazeni uvodni stranky
stranka0();
}
//------------------------------------------------------------------
void loop() {
//------------------------------------------------------------------
// cteni dotykoveho displeje
if (touch.dataAvailable()) { // kontrola prijatych dat z dotykoveho panelu
dotyk(); // spust program dotyk
}
//------------------------------------------------------------------
// 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
if (stranka == 0) aktualizujTeploty(); // aktualizuj uvodni stranku s teplotami
}
}
}
//------------------------------------------------------------------
void dotyk() {
//------------------------------------------------------------------
// omezeni opakovaneho stisku tlacitka
if (!vypniDotyk) { // kdyz je dotyk vypnuty
if ((unsigned long)(millis() - casProdlevyDotyk) >= prodlevaDotyk) { // pokud uplynula stanovena doba
vypniDotyk = true; // zapni dotyk
}
}
//------------------------------------------------------------------
// cteni hodnot z dotykoveho displeje
if (vypniDotyk) { // kdyz je dotyk zapnuty
casProdlevyDotyk = millis(); // nastav novy cas pro vypocet prodlevy
vypniDotyk = false; // vypni docasne dotyk
touch.read(); // pokud jsou data precte je a ulozi do promenych
x = touch.getX();
y = touch.getY();
//------------------------------------------------------------------
// overeni stisku tlacitka a spusteni souvisejici akce
if ((x != -1) && (y != -1)) { // a když není x a y menší než 0 ...
if (stranka == 0) { // kkyz je zobrazena stranka 0
if (checkTouch(&buttonNastaveni)) { // kdyz je stisknuto tlacitko nastaveni
vyberNastaveni(); // nakresli stranku vyber nastaveni
}
}
else if (stranka == 1) { // kkyz je zobrazena stranka vyber nastaveni
if (checkTouch(&buttonZpet)) { // kdyz je stisknuto tlacitko zpet
stranka0(); // nakresli stranku vyber nastaveni
}
else if (checkTouch(&buttonCidlo)) { // kdyz je stisknuto tlacitko prirazeni cidla
vyberMistnosti(); // nakresli stranku vyber nastaveni
}
else if (checkTouch(&buttonSmazat)) { // kdyz je stisknuto tlacitko prirazeni cidla
smazCidla(); // nakresli stranku vyber nastaveni
spustKonverzi(); // nacti teploty
povolCteniTeplot = true; // aktualizuj teploty
stranka0(); // nakresli stranku vyber nastaveni
}
else if (checkTouch(&buttonRozliseni)) { // kdyz je stisknuto tlacitko prirazeni cidla
zmenRozliseni(); // nakresli stranku vyber nastaveni
}
}
else if (stranka == 2) { // kdyz je zobrazena stranka vyber mistnosti
if (checkTouch(&buttonZpet)) { // kdyz je stisknuto tlacitko zpet
vyberNastaveni(); // nakresli stranku vyber nastaveni
}
else if (checkTouch(&button1)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 0; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
else if (checkTouch(&button2)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 1; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
else if (checkTouch(&button3)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 2; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
else if (checkTouch(&button4)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 3; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
else if (checkTouch(&button5)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 4; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
else if (checkTouch(&button6)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 5; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
else if (checkTouch(&button7)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 6; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
else if (checkTouch(&button8)) { // kdyz je stisknuto tlacitko prirazeni cidla
IDmistnosti = 7; // nastaveni ID mistnosti
vyberCidla(); // nakresli stranku vyber cidla
}
}
else if (stranka == 3) { // kkyz je zobrazena stranka zmena rozliseni
if (checkTouch(&buttonStorno)) { // kdyz je stisknuto tlacitko zpet
vyberNastaveni(); // nakresli stranku vyber nastaveni
}
else if (checkTouch(&buttonUlozit)) { // kdyz je stisknuto tlacitko ulozit
EEPROM.write(resolutionAdd, tempResolution); // uloz rozliseni do pameti
spustKonverzi(); // nacti teploty
povolCteniTeplot = true; // aktualizuj teploty
vyberNastaveni(); // nakresli stranku vyber nastaveni
}
else if (checkTouch(&buttonUP)) { // kdyz je stisknuto tlacitko nahoru
tempResolution++;
tempResolution = min(tempResolution, 12);
rozliseni();
}
else if (checkTouch(&buttonDOWN)) { // kdyz je stisknuto tlacitko dolu
tempResolution--;
tempResolution = max(tempResolution, 9);
rozliseni();
}
}
else if (stranka == 4) { // kkyz je zobrazena stranka vyber cidla
if (checkTouch(&buttonZpet)) { // kdyz je stisknuto tlacitko zpet
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button1)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(0); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button2)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(1); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button3)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(2); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button4)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(3); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button5)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(4); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button6)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(5); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button7)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(6); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
else if (checkTouch(&button8)) { // kdyz je stisknuto tlacitko prirazeni cidla
zapisAdresDS18B20(7); // prirad cidlo k mistnosti
vyberMistnosti(); // nakresli stranku vyber mistnosti
}
}
}
}
}
//------------------------------------------------------------------
// kontrola zda bylo stisknuto tlacitko
boolean checkTouch (struct defineButton *b) {
boolean press = false; // hodnota pro potvrzeni stisku
//------------------------------------------------------------------
if ((x >= b->x && x <= (b->x + b->width)) && (y >= b->y && y <= (b->y + b->height))) {
press = true; // nastav novou hodnotu
}
return press; // vrat hodnotu
}
//------------------------------------------------------------------
// uvodni stranka
void stranka0() {
stranka = 0; // nastaveni cisla stranky
tft.fillScreen(TFT_WHITE); // vycisti plochu
tft.drawCentreString("TEPLOTY", 120, 10, 4); // zobrazeni textu
vypisMistnosti(); // zobraz nazvy mistnosti
drawButton(&buttonNastaveni); // nakresli tlacitko
aktualizujTeploty(); // aktualizuj teploty
}
//------------------------------------------------------------------
// vypis mistnosti
void vypisMistnosti() {
int yText = 40; // promenna pro umisteni textu
int py = 27; // promenna pro odstup textu
for (int i = 0; i < numberOfSensors; i++) { // vypsani texu
char text1[20] = "Mistnost "; // vytvor promennou pro text
char text2[10]; // priprav promennou pro text
itoa(i + 1, text2, 10); // preved int na char
strcat(text1, text2); // sluc texty
if (stranka == 0) { // kdyz je zobrazena hlavni stranka
tft.drawString(text1, 10, yText + (py * i), 4); // zobrazeni textu
tft.drawRightString("C", 230, yText + (py * i), 4); // zobrazeni textu
}
else if (stranka == 2) { // kdyz je zobrazena stranka vyber mistnosti
tft.drawCentreString(text1, 120, yText + (py * i), 4); // zobrazeni textu
}
}
}
//------------------------------------------------------------------
// aktualizace teplot
void aktualizujTeploty() {
int yText = 40; // promenna pro umisteni textu
int py = 27; // promenna pro odstup textu
for (int i = 0; i < numberOfSensors; i++) { // vypsani texu
tft.fillRect(140, yText + (py * i), 70, py, TFT_WHITE); // vycistime pole pro zapis teploty
char text1[10]; // priprav promennou pro text
if (teplota[i] == NULL) { // kdyz nenni nactena zadna teplota
tft.drawRightString("NA", 200, yText + (py * i), 4); // zobrazeni textu
}
else {
dtostrf(teplota[i], 7, 1, text1); // jinak preved float na text
tft.drawRightString(text1, 200, yText + (py * i), 4); // zobrazeni textu
}
}
}
//------------------------------------------------------------------
// stranka pro vyber nastaveni
void vyberNastaveni() {
stranka = 1; // nastaveni cisla stranky
tft.fillScreen(TFT_WHITE); // vycisti plochu
tft.drawCentreString("NASTAVENI", 120, 10, 4); // zobrazeni textu
drawButton(&buttonCidlo); // nakresli tlacitko
drawButton(&buttonSmazat); // nakresli tlacitko
drawButton(&buttonRozliseni); // nakresli tlacitko
drawButton(&buttonZpet); // nakresli tlacitko
}
//------------------------------------------------------------------
// stranka pro vyber mistnosti
void vyberMistnosti() {
stranka = 2; // nastaveni cisla stranky
tft.fillScreen(TFT_WHITE); // vycisti plochu
tft.drawCentreString("VYBER MISTNOSTI", 120, 10, 4); // zobrazeni textu
vypisMistnosti(); // zobraz nazvy mistnosti
drawButton(&buttonZpet); // nakresli tlacitko
}
//------------------------------------------------------------------
// stranka pro zmenu rozliseni
void zmenRozliseni() {
int xb;
int yb;
int wy;
byte bw = 16;
stranka = 3; // nastaveni cisla stranky
tft.fillScreen(TFT_WHITE); // vycisti plochu
tft.drawCentreString("ZMENA ROZLISENI", 120, 10, 4); // zobrazeni textu
// kresleni sipek
drawButton(&buttonUP); // nakresli tlacitko
drawButton(&buttonDOWN); // nakresli tlacitko
// nastaveni promennych
xb = buttonUP.x;
yb = buttonUP.y + 2;
wy = buttonUP.width;
// kresleni obrysu sipky
tft.fillRect(xb + (wy / 2) - (bw / 2) - 2, yb + 20 - 2, bw + 4, 30 + 4, TFT_WHITE);
tft.fillTriangle(xb + (wy / 2), yb + 5 - 3, xb + 10 - 4, yb + 30 + 2, xb + wy - 10 + 4, yb + 30 + 2, TFT_WHITE);
// kresleni sipky
tft.fillRect(xb + (wy / 2) - (bw / 2), yb + 20, bw, 30, TFT_DARKGREY);
tft.fillTriangle(xb + (wy / 2), yb + 5, xb + 10, yb + 30, xb + wy - 10, yb + 30, TFT_DARKGREY);
// nastaveni promennych
xb = buttonDOWN.x;
yb = buttonDOWN.y - 2;
wy = buttonDOWN.width;
// kresleni obrysu sipky
tft.fillRect(xb + (wy / 2) - (bw / 2) - 2, yb + 10 - 2, bw + 4, 30 + 4, TFT_WHITE);
tft.fillTriangle(xb + (wy / 2), yb + wy - 5 + 3, xb + 10 - 4, yb + wy - 30 - 2, xb + wy - 10 + 4, yb + wy - 30 - 2, TFT_WHITE);
// kresleni sipky
tft.fillRect(xb + (wy / 2) - (bw / 2), yb + 10, bw, 30, TFT_DARKGREY);
tft.fillTriangle(xb + (wy / 2), yb + wy - 5, xb + 10, yb + wy - 30, xb + wy - 10, yb + wy - 30, TFT_DARKGREY);
// kresleni zbytku tlacitek
drawButton(&buttonStorno); // nakresli tlacitko
drawButton(&buttonUlozit); // nakresli tlacitko
//kresleni rozliseni cidel
tempResolution = EEPROM.read(resolutionAdd); // naplneni pomocne promenne
rozliseni(); // zobraz rozliseni
}
//------------------------------------------------------------------
// kresleni rozliseni cidla
void rozliseni() {
char text[10]; // priprav promennou pro text
itoa(tempResolution, text, 10); // preved int na char
tft.fillRect(buttonUP.x + 80, buttonUP.y, buttonUP.width, buttonUP.width, TFT_WHITE); // vycisti plochu pro kresleni
tft.drawCentreString(text, 120, buttonUP.y + (buttonUP.width / 2) - 10, 4); // zobrazeni textu
}
//------------------------------------------------------------------
// stranka pro vyber cidla
void vyberCidla() { // stranka pro vyber cidla
stranka = 4; // nastaveni cisla stranky
tft.fillScreen(TFT_WHITE); // vycisti plochu
tft.drawCentreString("VYBER CIDLA", 120, 10, 4); // zobrazeni textu
drawButton(&buttonZpet); // nakresli tlacitko
hledaniDS18B20(); // vyhledej a zobraz pripojena cidla
}
//------------------------------------------------------------------
// precte teploty ulozenych cidel
void cteniTeplot() {
byte data[12]; // lokalni prommena
byte address[8]; // lokalni prommena
byte count; // lokalni prommena
byte resolutionDS;; // // lokalni prommena
uint16_t tmpResolution; // lokalni prommena
uint16_t temp; // lokalni prommena
// napln promenne
resolutionDS = EEPROM.read(resolutionAdd); // nastav rozliseni cidla
tmpResolution = (resolutionDS - 9) * 32; // nastav promennou
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
// vypni Onewire (pro parazitni napajieni
ds18B20.depower();
// precti teploty a uloz je do promennych
for (int id = 0; id < numberOfSensors; id++) { // nastav odresu EEPROM cidla
count = 0; // resetuj count
for (int i = cidlaDS_i + (id * 8); i < cidlaDS_i + (id * 8) + 8; i++) { // precti adresy
address[count] = EEPROM.read(i); // precti adresy
count++; // zvys count o 1
}
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(); // napln promennou
}
if (address[0] == 255 || data[0] == 255) teplota[id] = NULL; // kdyz neni cidlo ulozeno, nebo nejsou data k dispozici
else { // jinak
if (data[4] != temp) { // kdyz neni nastaveno pozadovane rozliseni
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];
teplota[id] = (float)raw / 16;
}
}
povolCteniTeplot = false;
}
//------------------------------------------------------------------
// spusti teplotni konverzi 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
void hledaniDS18B20() { // hleda adresy teplotnich cidel DS 18B20
byte address[8];
byte id;
char text[40]; // pomocna promenna pro zobrazeni textu
int yText = 40; // promenna pro umisteni textu
int py = 27; // promenna pro odstup textu
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 zobraz adresy
stringText += address[i], DEC;
if (i < 8 - 1) stringText += ",";
}
stringText.toCharArray(text, stringText.length() + 2);
tft.drawString(text, 10, yText + (py * id), 2); // zobrazeni textu
if (!ds18B20.search(address)) {
ds18B20.reset_search();
break;
}
}
}
}
//------------------------------------------------------------------
// zapise vybranou adresu do EEPROM
void zapisAdresDS18B20(byte count) {
byte address[8];
if (ds18B20.search(address)) { // ksyz je adresa k dispozici
for (byte id = 0; id < 8; id++) { // projdi data do count
if (id == count) { // kdyz je id adresy rovno stisknutemu tlacitku
for (byte i = 0; i < 8; i++) { // zapis adresy
EEPROM.write(cidlaDS_i + (IDmistnosti * 8) + i, address[i]); // uloz hodnotu do EEPROM
}
break; // ukonci hledani
}
if (!ds18B20.search(address)) { // kdyz nejsou k dispozici zadne adresy
ds18B20.reset_search(); // resetuj hledani
break; // ukonci program
}
}
}
}
//------------------------------------------------------------------
// funkce pro smazani adres cidel
void smazCidla() { // smazat vsechna cidla z pameti EEPROM
for (byte id = 0; id < (numberOfSensors * 8) + 8; id++) { // projdi vsechny adresydata do count
EEPROM.write(cidlaDS_i + id, 255); // uloz hodnotu do EEPROM
}
}
//------------------------------------------------------------------
// funkce kresleni tlacitka
void drawButton(struct defineButton *b) {
int xText; // pozice textu
int yText; // pozice textu
//------------------------------------------------------------------
tft.fillRoundRect(b->x - 1, b->y - 1, b->width + 2, b->height + 2, 10, TFT_BLACK); // zobrazeni obrysu
tft.fillRoundRect(b->x, b->y, b->width, b->height, 10, b->color); // zobrazeni tlacitka
//------------------------------------------------------------------
xText = b->x + (b->width/2); // urceni pozice x pro zobrazeni textu
//------------------------------------------------------------------
if (b->font == 4 ) yText = (b->y + (b->height / 2)) - 10; // urceni pozice y pro font 4
else if (b->font == 2 ) yText = (b->y + (b->height / 2)) - 8; // urceni pozice y pro font 2
else yText = (b->y + (b->height / 2)) - 3; // urceni pozice y pro font 1
//------------------------------------------------------------------
tft.drawCentreString(b->text, xText, yText, b->font); // zobrazeni textu
}
I když je poctivě okomentovaný, pojďme si ho popsat. Na úvodní stránce se zobrazují teploty jednotlivých místností. Ke každé místnosti lze přiřadit konkrétní čidlo, které se uloží do paměti EEPROM. Také lze nastavit rozlišení čidel, které se také ukládá do paměti EEPROM. Je tam ještě funkce, která všechna čidla z paměti vymaže. Program zobrazuje pouze uložená čidla. Po zapojení budou všechny teploty v hodnotě NA.
Jak to funguje
Po načtení nezbytných částí v úvodu programu, nám v hlavní smyčce běží pouze dvě části, kontrolujeme zda není stisknuto nějaké tlačítko a pak jednou za 5 vteřin spouštíme čtení teplot a jejich aktualizaci na displeji. Pokud stiskneme tlačítko, zobrazíme se nám požadovaná stránka. Pro vytvoření tlačítek je použito pole struct, protože se některá tlačítka opakují, ušetříme tak místo.
Při stisku výběr čidla se nám otevře stránka s výběrem místnosti. Po stisku požadované místnosti program otevře stránku výběr čidla, prohledá sběrnici a vypíše adresy všech dostupných čidel. Po stisku vybraného čidla, uloží adresu čidla na pozici, která odpovídá pozici místnosti a to odpovídá pozici v poli teplot. Snadno tak při čtení víme, které čidlo patří které místnosti. Samozřejmě jedno čidlo můžete přiřadit více místnostem.
Při stisku smazat čidla program projde všechny adresy EEPROM a uloží zde hodnotu 255.
Při stisku nastavení rozlišení si uloží nastavené rozlišení z EEPROM do proměnné, kterou tlačítky měníte v rozsahu 9-12. Při stisku ulož, zapíše hodnotu do EEPROM.
Měření teplot probíhá tak, že jednou za 5 vteřin se odešle příkaz všem čidlům ke konverzi teploty. Pak se cyklicky kontrolují čidla, zda mají připraveny teploty ke čtení. Pokud ano, program volá čidla v pořadí jak jsou uloženy v EEPROM. Pokud není čidlo uloženo, nebo data nejsou k dispozici, uloží do proměnné teplota hodnotu NULL. Pokud souhlasí rozlišení, uloží teplotu do proměnné. Pokud ne, spustí část pro nastavení nového rozlišení. Nové rozlišení je tedy k dispozici až při dalším čtení.
Závěr
Máme program co nám ušetří práci při programování. Takto můžete kompilovat v podstatě cokoliv a provádět údržbu systému bez nového programování. Přitom naprogramovat to není tak těžké.
I když nám hlavně displej zabírá mnoho místa, stále je ho i v UNO dost na program pro spínání a ukládání hodnot. Zbylo nám 11 volných pinů. Klidně to stačí na ovládání topení až v 5 místnostech, 3 výstupy si necháme na kotel, 2 na hodinový modul a 1 na SD modul.
Příště se podíváme na práci s časem, konkrétně hodinovým modulem a mimo jiné si ukážeme jak ho přes displej nastavit.
JB