Skocz do zawartości
Philip

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?

Udostępnij ten post


Link to post
Share on other sites

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 🙂

Udostępnij ten post


Link to post
Share on other sites

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.

Udostępnij ten post


Link to post
Share on other sites

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...

Udostępnij ten post


Link to post
Share on other sites

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).

Udostępnij ten post


Link to post
Share on other sites

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!

Udostępnij ten post


Link to post
Share on other sites
/* ... */
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;  
 }

Udostępnij ten post


Link to post
Share on other sites
(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

Udostępnij ten post


Link to post
Share on other sites

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.

Udostępnij ten post


Link to post
Share on other sites
(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

Udostępnij ten post


Link to post
Share on other sites

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.

Udostępnij ten post


Link to post
Share on other sites
(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

Udostępnij ten post


Link to post
Share on other sites

wrzuć cały kod a nie kawałek.

Udostępnij ten post


Link to post
Share on other sites
#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.

Udostępnij ten post


Link to post
Share on other sites

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ę 😛

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Napisz odpowiedź...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...