Skocz do zawartości

Wielozadaniowość, millis, automatyka domowa


Pomocna odpowiedź

Sprintf to jest rodzaj printf'a z tego co wyczytałem. Wypisuje na ekranie łańcuchy danych np %d liczba typu int, %f liczba zmiennoprzecinkowa. Tych printf'ów jest jeszcze więcej tylko nie wszystkie chyba działają w C++. Różnią się zajmowaną pamięcią, a ich składnia jest dość zagmatwana. 😃 Wyczytałem także, że przy złym ich używaniu (sprintf) może dojść do przepełnienia bufora.

ethanak, teraz pytanie, bo chyba bez powodu tego nie napisałeś, 😉 jak użyć go w programie z RTC? Chcesz, aby liczby (data, godzina) wyświetlały się określonej postaci?

Ty nie wyczytuj w jakichś podejrzanych miejscach tylko skorzystaj z oficjalnej dokumentacji. Akurat rodzina funkcji *printf jest bardzo dobrze udokumentowana. Najlepiej skorzystać z dokumentacji dla Linuksa (ten sam kompilator). A jak? Po prostu wpisujesz w przeglądarkę "man sprintf" i w odpowiedzi dostajesz link do linuksowego manuala.

To jeszcze nie wszystko. Jako że avr-libc (czyli biblioteka, z której korzysta Arduino) jest okrojoną wersją glibc, trzeba też sprawdzić jakie są różnice między oryginalną funkcją a tą, z której korzystamy. W tym celu wchodzimy na stronę dokumentacji (zapisz sobie ten link bo Ci będzie jeszcze nie raz potrzebny), stamtąd wybieramy moduł stdio i już czytamy... no i widzimy, że w podstawowej wersji nie ma wyświetlania wartości zmiennoprzecinkowych (czyli nie będzie działać %f - na szczęście nie jest nam to do niczego potrzebne).

Składnia jest prosta jak rogalik, wymaga jedynie zapamiętania sobie paru zasad które zresztą zawsze można mieć pod ręką choćby na stronie manuala w zakładce przeglądarki (z czasem same się zapamiętają, nie trzeba wkuwać na pamięć).

Jak użyć... no, tak jak napisałeś: do wyświetlania daty/godziny w określonej postaci.

Przykładowo:

char bufor[20]; // długość wypisywanego napisu plus jeden dla kończącego zera
sprintf(bufor,"%4d/%02d/%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
lcd.setCursor(0,0);
lcd.print(bufor);

Oczywiście za year, month i tak dalej podstawiasz wywołania rtc.cośtam() masz pięknie sformatowaną i wypisaną datę i godzinę... tyle że na dwudziestoznakowym wyświetlaczu, a Ty masz szesnaście. Możesz jako zadanie domowe przemyśleć, co chcesz wyświetlać (czy na pewno potrzebny jest rok? A może chcesz mieć dzień tygodnia?)

Jeśli obawiasz się, że źle wyliczyłeś długość napisu i sprintf może wyleźć poza dostępny bufor - zawsze możesz użyć snprintf, a tutaj już trzeba dobrze się postarać aby zrobić błąd 🙂

Jeszcze jedno: oczywiście, możesz użyć funkcji strftime - taki odpowiednik sprintfa specjalizowany do wyświetlania czasu. Na razie jednak pozostańmy przy sprintfie, jako że funkcja jest bardziej uniwersalna i najprawdopodobniej skorzystasz z niej w jeszcze kilku miejscach programu. A jak pisałem wcześniej - nie ma sensu robienie kilku rzeczy na raz, bo ani jedna z nich nie wyjdzie dobrze 🙂

Dodam, że na razie mój główny program z automatem, klawiaturą i czujnikami temp. To jest ponad 50% pamięci Arduino. Trzeba ostrożnie używać tych sprintf, żeby nie zapchać pamięci. Myślałem, że można użyć zmiennych o mniejszych zakresach gdzie to możliwe.

A odróżniasz pamięć programu od pamięci danych?

Przecież ile razy byś tego sprintfa nie użył, i tak w kodzie będzie tylko raz. Tak samo bufor sprintfa - przecież możesz mieć jeden wystarczający na najdłuższy wypisywany string, nie musisz ich mieć piętnastu. A najdłuższy bufor który Ci będzie potrzebny to 17 bajtów...

Poza tym czy naprawdę myślisz, że jak zaczniesz stosować jakieś swoje wynalazki (jeden do wyświetlania czasu, drugi temperatury, trzeci i czwarty czegoś tam jeszcze) to kod wynikowy będzie mniejszy niż przy użyciu dobrze zoptymalizowanej funkcji, jaką jest sprintf?

Co do wielkości kodów: mój programik (kolorowy wyświetlacz graficzny, czujnik temperatury i wilgotności, prędkościomierz woltomierz i olejarka łańcucha do motocykla plus oczywiście zegarek, łącznie z funkcjami ustawiania wszelkich parametrów, z kolorowymi ikonkami i różnymi bajerami) zostawił mi jeszcze jakieś 100 bajtów w pamięci kodu na Pro Mini. I oczywiście był tam sprintf...

Zrobiłem takie coś:

[...]
char bufor[10];
char bufor2[8];
void setup(){
[...]}

void loop() {
 DateTime now = rtc.now();
 sprintf(bufor,"%4d/%02d/%02d", now.year(), now.month(), now.day());
 lcd.setCursor(0,0);
 lcd.print(bufor);
 sprintf(bufor2,"%02d:%02d:%02d", now.hour(), now.minute(), now.second());
 lcd.setCursor(0,1);
 lcd.print(bufor2);

 delay(1000);
}

Nie ma problemu i data wyświetla się w pierwszej linijce, a godzina w drugiej. Czasami zegar się stopuje lub wyświetlają się kosmiczna data/godzina np.2165/165/165, a jak zresetuje Arduino lub poruszam kabelkami to leci dalej (uwzględniając sekundy, które już minęły).

No to polutuj te druty, bo na płytce stykowej to można sobie z kolorowych drucików zrobić wielce gustowny obrazek.

Po kiego grzyba Ci potrzebny bufor i bufor2? Nie można w jednym? Wiem że masz mnóstwo pamięci w Arduino ale jak tak będziesz bufory robił to pojutrze się skończy.

Po co one są statyczne? Żeby siedziały i pamięć zajmowały? Za dużo masz?

Coś takiego:

void display_date(void)
{
   char bufor[10];
   sprintf(bufor, cośtam);
  ... /* i tak dalej */
}

void loop(void)
{
   /* kawałek kodu */
   display_date();
  /* dalszy kawałek kodu */
}

Kiedy będzie przydzielona pamięć dla bufora, a kiedy będziesz mógł ją wykorzystać do innych celów?

po chwili namysłu

Jeśli Ci się jakieś kosmiczne liczby wyświetlają użyj snprintf zamiast sprintf - będzie bezpieczniej!

/* ... */
void loop (void){
Rtc();
}

void Rtc (void){
 DateTime now = rtc.now();
 sprintf(bufor,"%4d/%02d/%02d", now.year(), now.month(), now.day());
 lcd.setCursor(0,0);
 lcd.print(bufor);
 sprintf(bufor,"%02d:%02d:%02d", now.hour(), now.minute(), now.second());
 lcd.setCursor(0,1);
 lcd.print(bufor);
 delay(1000);
}

Napisałem taki kod, ale nie mogę sprawdzić, bo mi ten mój scalak przestał działać, wcale nie liczy czasu. 🤯 snprintf'a też nie sprawdziłem. Będę musiał kupić coś nowego i chyba kupię gotowy moduł zamiast bawić się z tym scalakiem.

W między czasie napisałem automat do moich czujników. ethanak, jeśli robię coś źle, to sprostuj moje myślenie. Generalnie ma to działać tak: Stan dataGodzina wyświetla się cały czas, na razie jest to sam napis "Data Godzina", bo nie mam zegara. Z tego stanu można przejść do jakiegokolwiek innego stanu wciskając odpowiedni przycisk na klawiaturze. Tak samo z tych stanów można przejść do innych stanów oprócz dataGodzina, bo do niego przechodzi się automatycznie po 10 sekundach bezczynności w danym stanie. Zrozumiałe? 🙂 Napotkałem jeden problem, np. jestem w stanie temperaturaPokoj i przechodzę do stanu wilgotnoscDht i odlicza się już podczas tej czynności 10s i nawet jeśli będę sobie te temp. przełączał to po jednokrotnym odliczeniu się 10s wracam do stanu dataGodzina zamiast przechodzić sobie między stanami w nieskończoność.

Chodzi mi oto, aby po wejściu w jakikolwiek stan 10s odliczało się od nowa.

void loop() {
 char klawisz = 0;                       //zmienna do przechowywania znaków klawiszy
 klawisz = klawiatura.getKey();

 sensors.requestTemperatures();          //Pobranie temperatury czujnika
 int wilgotnosc = dht.getHumidity();     //Pobranie informacji o wilgotności
 int temperatura = dht.getTemperature(); //Pobranie informacji o temperaturze

 aktualnyCzas = millis();

 switch (przelaczenie){
   case dataGodzina:
     lcd.setCursor(0,0);
     lcd.print("Data Godzina");
     if(klawisz == '1'){                //Jeśli wciśnięty przycisk '1', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaPokoj;
       lcd.clear();
     }
     if(klawisz == '2'){                //Jeśli wciśnięty przycisk '2', to wyświetla się temperatura na dworze
       przelaczenie = temperaturaDwor;
       lcd.clear();
     }
     if(klawisz == '3'){                //Jeśli wciśnięty przycisk '3', to wyświetla się wilgotność pokoju
       przelaczenie = wilgotnoscDht;
       lcd.clear();
     }
     if(klawisz == '4'){                //Jeśli wciśnięty przycisk '4', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaDht;
       lcd.clear();
     }
     if(aktualnyCzas - zapamietanyCzas >= 10000UL){
     zapamietanyCzas = aktualnyCzas;
     przelaczenie = dataGodzina;
   }
   break;

   case temperaturaPokoj:                              
     lcd.setCursor(0,0);
     lcd.print("Temp Pokoj:");
     lcd.setCursor(0,1);
     lcd.print(sensors.getTempC(termometrPokoj));
     lcd.setCursor(6,1);
     lcd.print("*C");

     if(klawisz == '2'){                //Jeśli wciśnięty przycisk '2', to wyświetla się temperatura na dworze
       przelaczenie = temperaturaDwor;
       lcd.clear();
     }
     if(klawisz == '3'){                //Jeśli wciśnięty przycisk '3', to wyświetla się wilgotność pokoju
       przelaczenie = wilgotnoscDht;
       lcd.clear();
     }
     if(klawisz == '4'){                //Jeśli wciśnięty przycisk '4', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaDht;
       lcd.clear();
     }
     if(aktualnyCzas - zapamietanyCzas >= 10000UL){
     zapamietanyCzas = aktualnyCzas;                 
     przelaczenie = dataGodzina;
     lcd.clear();
  }
  break;

  case temperaturaDwor:                                 
     lcd.setCursor(0,0);
     lcd.print("Temp. Dwor:");
     lcd.setCursor(0,1);
     lcd.print(sensors.getTempC(termometrDwor));
     lcd.setCursor(6,1);
     lcd.print("*C");

     if(klawisz == '1'){                //Jeśli wciśnięty przycisk '1', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaPokoj;
       lcd.clear();
     }
     if(klawisz == '3'){                //Jeśli wciśnięty przycisk '3', to wyświetla się wilgotność pokoju
       przelaczenie = wilgotnoscDht;
       lcd.clear();
     }
     if(klawisz == '4'){                //Jeśli wciśnięty przycisk '4', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaDht;
       lcd.clear();
     }
     if(aktualnyCzas - zapamietanyCzas >= 10000UL){
     zapamietanyCzas = aktualnyCzas;                 
     przelaczenie = dataGodzina;
     lcd.clear();
  }
  break;

 case wilgotnoscDht:
     lcd.setCursor(0,0);
     lcd.print("Wilgotnosc:");
     lcd.setCursor(0,1);
     lcd.print(wilgotnosc);
     lcd.setCursor(3,1);
     lcd.print("%RH");

     if(klawisz == '1'){                //Jeśli wciśnięty przycisk '1', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaPokoj;
       lcd.clear();
     }
     if(klawisz == '2'){                //Jeśli wciśnięty przycisk '2', to wyświetla się temperatura na dworze
       przelaczenie = temperaturaDwor;
       lcd.clear();
     }
     if(klawisz == '4'){                //Jeśli wciśnięty przycisk '4', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaDht;
       lcd.clear();
     }
     if(aktualnyCzas - zapamietanyCzas >= 10000UL){
     zapamietanyCzas = aktualnyCzas;                 
     przelaczenie = dataGodzina;
     lcd.clear();
  }
  break;

  case temperaturaDht:
     lcd.setCursor(0,0);
     lcd.print("Temp. DHT11:");
     lcd.setCursor(0,1);
     lcd.print(temperatura);
     lcd.setCursor(3,1);
     lcd.print("*C");

     if(klawisz == '1'){                //Jeśli wciśnięty przycisk '1', to wyświetla się temperatura pokoju
       przelaczenie = temperaturaPokoj;
       lcd.clear();
     }
     if(klawisz == '2'){                //Jeśli wciśnięty przycisk '2', to wyświetla się temperatura na dworze
       przelaczenie = temperaturaDwor;
       lcd.clear();
     }
     if(klawisz == '3'){                //Jeśli wciśnięty przycisk '3', to wyświetla się wilgotność pokoju
       przelaczenie = wilgotnoscDht;
       lcd.clear();
     }
  if(aktualnyCzas - zapamietanyCzas >= 10000UL){
     zapamietanyCzas = aktualnyCzas;                 
     przelaczenie = dataGodzina;
     lcd.clear();
  }
  break;  
 }
(edytowany)

Przede wszystkim: robisz podstawowy błąd powielając ten sam kod w kilku miejscach - i z programu robi się zupełnie nieczytelny tasiemiec.

A gdyby tak wywalić zmianę zmiennej "przełączenie" w ogóle poza switcha? I w dodatku ukryć ją w odpowiedniej funkcji?

Spróbujmy...

Jako że "przelaczenie" jest (tak wynika z kodu) zmienną globalną, a nie wiem do czego będziesz jeszcze używać klawiatury - stwórzmy sobie funkcję przyjmującą odczytany znak i zwracającą informację, czy znak został skonsumowany.

A więc...

bool przelacz(char znak)
{
  int old_przelacz = przelaczenie;
  switch(znak) {
    case '1' : przelaczenie = temperaturaPokoj; break;
    case '2' : przelaczenie = temperaturaDwor; break;
    case '3' : przelaczenie = wilgotnoscDht; break;
    case '4' : przelaczenie = temperaturaDht; break;
  }
  return old_przelacz != przelaczenie;
}

      

I teraz w loop możemy zrobić coś takiego:

void loop() {
 char klawisz = 0;                       //zmienna do przechowywania znaków klawiszy
 klawisz = klawiatura.getKey();

 sensors.requestTemperatures();          //Pobranie temperatury czujnika
 int wilgotnosc = dht.getHumidity();     //Pobranie informacji o wilgotności
 int temperatura = dht.getTemperature(); //Pobranie informacji o temperaturze

 aktualnyCzas = millis();
 if (przelacz(klawisz)) {
   zapamietanyCzas = aktualnyCzas; // od tego momentu odliczamy 10 sekund...
 } else if (przelaczenie != dataGodzina && aktualnyCzas - zapamietanyCzas >= 10000UL) {
   // minęło 10 sekund kiedy wyświetlaliśmy coś innego niż data
   // a więc wracamy do daty. Nie musimy zapamiętywać czasu bo nie będzie nam potrzebny
   przelaczenie = dataGodzina;
 }
 switch (przelaczenie) {
    case dataGodzina:
    // kod wyświetlania daty
    break
    // i tak dalej...
 }

Zauważ: nie wnikam tu w sensowność pobierania wilgotności w czasie wyświetlania temperatury w pokoju, ale to już sobie rozwiążesz sam.

Tak jakby nieco krócej, prawda? 🙂

(po edycji)

Zapomniałem wstawić czyszczenie ekranu po zmianie trybu wyświetlania... ale mam nadzieję że wstawisz cleara we właściwym miejscu!

 

Edytowano przez ethanak
skleroza
  • Pomogłeś! 1

Działa 😁 Mam jedno pytanie do kodu: char znak z funkcji przelacz jest równoznaczny z char klawisz z loop? Obydwa char'y działają na klawisze klawiatury?

Do zegara wrócę chyba po wakacjach, bo za niedługo wyjeżdżam i nie będzie czasu na Arduino. Teraz można wrócić do biblioteki Bounce2.

(edytowany)

A popatrz dokładnie w kod i odpowiedz sobie na pytanie, dlaczego to to samo i skąd.się to bierze.

I jak na początku mówiłem to jest "coś w rodzaju" a nie gotowy kod i różne błędy, literówki i tym podobne masz poprawić i nie komentować 🙂

Edytowano przez ethanak
Bo tak

Głupie pytanie.😁 Mapowanie klawiatury

Z tą biblioteką zmieniłem tyle:

#include "Bounce2.h"

Bounce debouncer = Bounce();
[...]

void setup() {
  Serial.begin(9600);
  lcd.begin(16,2);                  //Deklaracja typu
  lcd.clear();                      //Wyczyszczenie

  sensors.begin();                  //Inicjalizacja czujników

  dht.setup(CzDHT);                 //Inicjalizacja DHT11

  pinMode(KONTAKTRON,INPUT_PULLUP); //Deklaracja dla kontaktronu jako wyjście
  pinMode(BUZZER,OUTPUT);           //Deklaracja buzzera wyjście
  pinMode(PIR,INPUT);               //Deklaracja czujnika ruchu jako wejście

  debouncer.attach(KONTAKTRON);
  debouncer.interval(5);
}
void loop() {
  char klawisz = 0;                       //zmienna do przechowywania znaków klawiszy
  klawisz = klawiatura.getKey();
  
  sensors.requestTemperatures();          //Pobranie temperatury czujnika
  int wilgotnosc = dht.getHumidity();     //Pobranie informacji o wilgotności
  int temperatura = dht.getTemperature(); //Pobranie informacji o temperaturze

  aktualnyCzas = millis();

  debouncer.update();
  int wartosc = debouncer.read();
  [...]
  
 switch(stan){
    case czyOtworzonoDrzwi:
    if(wartosc == HIGH){              //Jeśli drzwi otwarte
        if(aktualnyCzas - zapamietanyCzas >=500UL){ //Ile upłynęło
        zapamietanyCzas = aktualnyCzas;
        tone(BUZZER,glosnosc1);                     //Odtwarzam dźwięk1
        stan = odegranoDzwiek1;                     //Przełączam na stan2
      }
    }
    break;
    
    case odegranoDzwiek1:
    if(aktualnyCzas - zapamietanyCzas >=500UL){    //Jeśli upłynął czas
        zapamietanyCzas = aktualnyCzas;
        tone(BUZZER,glosnosc2);                    //Odtwarzam dźwięk2
        stan = odegranoDzwiek2;                    //Przełączam na stan3
      }
     break;

      case odegranoDzwiek2:
      if(aktualnyCzas - zapamietanyCzas >=500UL){  //Jeśli upłynął czas
        zapamietanyCzas = aktualnyCzas;
        noTone(BUZZER);                            //Nie odtwarzam dźwięków
        stan = czyZamknietoDrzwi;
      }
      break;

      case czyZamknietoDrzwi:
      if(wartosc == HIGH){           //Jeśli drzwi otwarte
      } else {                                     //Nic nie robię
        if(aktualnyCzas - zapamietanyCzas >=500UL){
          stan = czyOtworzonoDrzwi;                //Jeśli nie przełączam na stan1
          zapamietanyCzas = aktualnyCzas;
        }
      }
      break;
   }
}

Podłączyłem wszystko do zasilacza, czyli tak jakby miało już oficjalnie działać i po jakimś czasie dosłownie kilku sekund buzzer siedzi cicho i nie ma tych cichutkich pyknięć. Chyba biblioteka swoje zrobiła. Dzięki ethanak za pomoc i poświęcony czas.

  • 10 miesiące później...
(edytowany)

Witam,

Odkurzam projekt. Brałem się za niego jakoś na feriach zimowych. Wtedy obrobiłem obudowę, szynę 5V, GND, 3.3V, czujniki. 😉Teraz chcę jeszcze bardziej udoskonalić projekt o ręczne ustawianie godziny na początku włączania Arduino. Poza tym wszystko działa jak zamierzałem od początku.

Problematyczne jest, że za każdym razem przy ponownym włączeniu zasilania data i godzina pozostaje z ostatniego wgrywania programu. Próbowałem w jakiś sposób napisać funkcję, która przypisze przyciski na klawiaturze jako odpowiednie liczby np. '1' w rzeczywistości jest 1, '2' - 2 itd., ale to co napisałem nie ma prawa działać. Biblioteka RTClib też nie pozwala jakoś za bardzo na oddzielenie od siebie roku, miesiąca, dnia, godziny, minuty i sekundy. Są one raz ustawiane i koniec.

Myślałem jeszcze o jakimś zapisie daty i godziny przy wyłączaniu zasilania, tylko pytanie gdzie? Jakaś dodatkowa karta pamięci?

void loop() {
  switch(...){
  [...]
 case ... :  //Odpowiedni case dla godziny w pętli głównej
 klawisz();
  }
}

void (klawisz){
  DateTime written = rtc.written();
  klawisz '0' = int zero;
  int zero = 0; 
  klawisz '1' = int jedynka; //'1' klawisz jest typu char
  int jedynka = 1;
  [...] //od 0-9

  switch(ustawCzas){
    case sprawdzenieRtc:       //sprawdzenie czy moduł RTC działa
    if (! rtc.isrunning()) {
    lcd.setCursor(0,0);
    lcd.print("RTC is NOT running!");
    } else {
      lcd.clear();
      ustawCzas = ustawRok;    //jeśli tak, ustawiamy rok
    }
    break;

    case ustawRok:
    //Co teraz? Jeśli odebrano 4 cyfry z klawiatury, to ...
   char rok [5]; //tblica do przechowywania roku
   sprintf(rok,"%4d",written.year());
   lcd.setCursor(0,0);
   lcd.print(rok);
   ustawCzas = ustawMiesiac;
      break;

   case ustawMiesiac:
    //Co teraz? Jeśli odebrano 4 cyfry z klawiatury, to ...
   char miesiac [4]; //tablica do przechowywania miesiąca 
   sprintf(miesiac,"/%4d",written.month());
   lcd.setCursor(0,5);
   lcd.print(miesiac);
   ustawCzas = ustawDzien;
      break;

   case ustawDzien:
   [...]
      break;

   case godzina:
   rtc.adjust(DateTime(rok,miesiac,dzien,godzina,minuta,sekunda);
     lcd.clear();
     Rtc();
   if(klawisz == '*'){ //Ponowne ustawienie daty i godziny
    ustawCzas = sprawdzenieRtc;
   }
              break;
 }
}
void Rtc(void){
  char bufor [11];
  DateTime now = rtc.now();
  if(aktualnyCzas - zapamietanyCzas >= 1000UL){
  zapamietanyCzas = aktualnyCzas;
  sprintf(bufor,"%4d/%02d/%02d", now.year(), now.month(), now.day());
  lcd.setCursor(0,0);
  lcd.print(bufor);
  sprintf(bufor,"%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  lcd.setCursor(0,1);
  lcd.print(bufor); 
  }
 }

W załączniku wrzucam zdjęcia jak to na razie wygląda. 😎 Prosiłbym o pomoc @ethanak jeśli byłoby to możliwe.

Pozdrawiam Philip

IMG_20190629_151120.jpg

IMG_20190629_151134.jpg

Edytowano przez Philip
#define CzDALLAS A0
#define CzDHT 15
#define KONTAKTRON 16
#define BUZZER 17
#define PIR 18

//Dołączenie bibliotek
#include <LiquidCrystal.h>
#include <Keypad.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <DHT.h>
#include "RTClib.h"
#include <Wire.h>
#include "Bounce2.h"

const byte ROWS = 4;            //ile wierszy
const byte COLS = 4;            //ile kolumn
byte rowPins[ROWS]={3,2,1,0};   //piny wierszy
byte colPins[COLS]={4,5,6,7};   //piny kolumn
char keys[ROWS][COLS]={         //mapowanie klawiatury
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

//Deklaracja podłączeń urządzeń
LiquidCrystal lcd(8,9,10,11,12,13);                                     //Wyświetlacz
Keypad klawiatura = Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS); //Klawiatura
OneWire oneWire(CzDALLAS);                                              //Podłączenie do A0 czujników Dallas
DallasTemperature sensors(&oneWire);                                    //Informacja do biblioteki      
DHT dht;                                                                //Czujnik wilgotności DHT11
Bounce debouncer = Bounce();                                            //Debouncing
RTC_DS1307 rtc;                                                         //Deklaracja zegara

DeviceAddress termometrPokoj = {0x28,0x95,0x18,0xFD,0x9,0x0,0x0,0x64};  //Adres czujnika temp. pokoju
DeviceAddress termometrDwor = {0x28,0x28,0x4F,0xBA,0x9,0x0,0x0,0x8B};   //Adres czujnika temp. na dworze

//Zmienne do liczenia czasu
unsigned long aktualnyCzas = 0;             
unsigned long zapamietanyCzas = 0;

//Zmienne do zmiany glośności buzzera i otworzenia drzwi
int glosnosc1 = 500;                        
int glosnosc2 = 1000;
int stan = 1;

//Zmienna do przelaczania opcji menu
int przelaczenie = 1;

 enum {
  czyOtworzonoDrzwi = 1,
  odegranoDzwiek1,
  odegranoDzwiek2,
  czyZamknietoDrzwi
 };

 enum {
  dataGodzina = 1,
  temperaturaPokoj,
  temperaturaDwor,
  wilgotnoscDht,
  temperaturaDht,
  wyczyszczenie,
 };
 
void setup(void) {
  Serial.begin(9600);
  lcd.begin(16,2);                  //Deklaracja typu
  lcd.clear();                      //Wyczyszczenie

  sensors.begin();                  //Inicjalizacja czujników

  dht.setup(CzDHT);                 //Inicjalizacja DHT11

  pinMode(KONTAKTRON,INPUT_PULLUP); //Deklaracja dla kontaktronu jako wyjście
  pinMode(BUZZER,OUTPUT);           //Deklaracja buzzera wyjście
  pinMode(PIR,INPUT);               //Deklaracja czujnika ruchu jako wejście

  debouncer.attach(KONTAKTRON);
  debouncer.interval(5);

if(!rtc.begin()) {
   lcd.setCursor(0,0);
   lcd.print("Nie moge znalezc RTC");
   while (1);
  }
 if(!rtc.isrunning()){
   lcd.clear();
   lcd.setCursor(0,0);
   lcd.print("RTC nie dziala");
 } else {
  rtc.begin();
  rtc.adjust(DateTime(2019, 6, 29, 15, 9, 0)); //Ustawienie daty i godziny
  }
}

 void Rtc(void){
  char bufor [11];
  DateTime now = rtc.now();
  if(aktualnyCzas - zapamietanyCzas >= 1000UL){
  zapamietanyCzas = aktualnyCzas;
  sprintf(bufor,"%4d/%02d/%02d", now.year(), now.month(), now.day());
  lcd.setCursor(0,0);
  lcd.print(bufor);
  sprintf(bufor,"%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  lcd.setCursor(0,1);
  lcd.print(bufor); 
  }
 }

bool przelacz(char klawisz){
  int old_przelacz = przelaczenie;
  switch(klawisz){
    case '1':
    przelaczenie = temperaturaPokoj;
    lcd.clear();
    break;
    case '2':
    przelaczenie = temperaturaDwor;
    lcd.clear();
    break;
    case '3':
    przelaczenie = wilgotnoscDht;
    lcd.clear();
    break;
    case 'A':
    przelaczenie = temperaturaDht;
    lcd.clear();
    break;
    case 'D':
    przelaczenie = wyczyszczenie;
    lcd.clear();
  }
  return old_przelacz != przelaczenie;
  }

void loop(void) {
  char klawisz = 0;                       //zmienna do przechowywania znaków klawiszy
  klawisz = klawiatura.getKey();
  
  sensors.requestTemperatures();          //Pobranie temperatury czujnika
  int wilgotnosc = dht.getHumidity();     //Pobranie informacji o wilgotności
  int temperatura = dht.getTemperature(); //Pobranie informacji o temperaturze

  aktualnyCzas = millis();

  debouncer.update();
  int wartosc = debouncer.read();

  if(przelacz(klawisz)){                 //Przy 10 sekundach bezczyności autmatyczne ustawienie daty i godziny
    zapamietanyCzas = aktualnyCzas;
  } else if(przelaczenie != dataGodzina && aktualnyCzas - zapamietanyCzas >= 10000UL){
    przelaczenie = dataGodzina;
    lcd.clear();
  }
  
  switch (przelaczenie){
    case dataGodzina:
      Rtc();
    break;

    case temperaturaPokoj:                              
      lcd.setCursor(0,0);
      lcd.print("Temp Pokoj:");
      lcd.setCursor(0,1);
      lcd.print(sensors.getTempC(termometrPokoj));
      lcd.setCursor(6,1);
      lcd.print("*C");
   break;

   case temperaturaDwor:                                 
      lcd.setCursor(0,0);
      lcd.print("Temp. Dwor:");
      lcd.setCursor(0,1);
      lcd.print(sensors.getTempC(termometrDwor));
      lcd.setCursor(6,1);
      lcd.print("*C");
    break;

  case wilgotnoscDht:
      lcd.setCursor(0,0);
      lcd.print("Wilgotnosc:");
      lcd.setCursor(0,1);
      lcd.print(wilgotnosc);
      lcd.setCursor(3,1);
      lcd.print("%RH");
    break;

   case temperaturaDht:
      lcd.setCursor(0,0);
      lcd.print("Temp. DHT11:");
      lcd.setCursor(0,1);
      lcd.print(temperatura);
      lcd.setCursor(3,1);
      lcd.print("*C");
   break; 

    case wyczyszczenie:
    lcd.clear();
    break;

  }

  switch(stan){
    case czyOtworzonoDrzwi:
    if(wartosc == HIGH){                            //Jeśli drzwi otwarte
        if(aktualnyCzas - zapamietanyCzas >=500UL){ //Ile upłynęło
        zapamietanyCzas = aktualnyCzas;
        tone(BUZZER,glosnosc1);                     //Odtwarzam dźwięk1
        stan = odegranoDzwiek1;                     //Przełączam na stan2
      }
    }
    break;
    
    case odegranoDzwiek1:
    if(aktualnyCzas - zapamietanyCzas >=500UL){    //Jeśli upłynął czas
        zapamietanyCzas = aktualnyCzas;
        tone(BUZZER,glosnosc2);                    //Odtwarzam dźwięk2
        stan = odegranoDzwiek2;                    //Przełączam na stan3
      }
     break;

      case odegranoDzwiek2:
      if(aktualnyCzas - zapamietanyCzas >=500UL){  //Jeśli upłynął czas
        zapamietanyCzas = aktualnyCzas;
        noTone(BUZZER);                            //Nie odtwarzam dźwięków
        stan = czyZamknietoDrzwi;
      }
      break;

      case czyZamknietoDrzwi:
      if(wartosc == HIGH){                         //Jeśli drzwi otwarte
      } else {                                     //Nic nie robię
        if(aktualnyCzas - zapamietanyCzas >=500UL){
          stan = czyOtworzonoDrzwi;                //Jeśli nie przełączam na stan1
          zapamietanyCzas = aktualnyCzas;
        }
      }
      break;
   }
}  

To jest cały kod, który działa, bez tego co napisałem w poprzednim poście.

A gdyby tak faktycznie wstawić moduł Bluetooth (pisałeś o tym w jednym z pierwszych postów) i... napisać aplikację (bardzo prostą!) w Qt i ustawiać czas na uC na aktualny z Twojego telefonu jednym kliknięciem przycisku? Mógłbyś się wtedy całkowicie pozbyć klawiatury. Masz prawie wszystko dostępne w kursie a część dotycząca BT pojawi się niebawem. 

Do nauki będziesz miał więcej ale chyba warto. W razie problemów z Qt pomogę 😛

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...