Skocz do zawartości

Kurs Arduino - #3 - UART (komunikacja z PC), zmienne


Pomocna odpowiedź

(edytowany)

melduję wykonanie zadania domowego 2.4:

#define zielona 8
#define czerwona 10

String odebraneDane = ""; //Pusty ciąg odebranych danych

void setup() {
  Serial.begin(9600); //Uruchomienie komunikacji
  pinMode(zielona, OUTPUT); //Konfiguracja wyjść
  pinMode(czerwona, OUTPUT);

  digitalWrite(zielona, LOW); //Wyłączamy diody
  digitalWrite(czerwona, LOW);
}

void loop() {
  if (Serial.available() > 0) { //Czy Arduino odebrało dane
    //Jeśli tak, to odczytujemy je do znaku końca linii i zapisz w zmiennej odebraneDane
    odebraneDane = Serial.readStringUntil('\n');

    if (odebraneDane == "zielona") { //Jeśli odebrano słowo "zielona"
      digitalWrite(zielona, HIGH); //To włączamy diodę zieloną
      delay(1000);
      digitalWrite(zielona, LOW);
    }
    else if (odebraneDane == "czerwona") { //Jeśli odebrano słowo "czerwona"
      digitalWrite(czerwona, HIGH); //To włączamy diodę czerwoną
      delay(1000);
      digitalWrite(czerwona, LOW);
    }
    else { //ani zielona ani czerwona -> zgłoś błąd
      Serial.println("Błąd. Nie znane wejście: "+odebraneDane);
    }
  }

}

i 2.5:

#define zielona 8
#define czerwona 10

String odebraneDane = ""; //Pusty ciąg odebranych danych

void setup() {
  Serial.begin(9600); //Uruchomienie komunikacji
  pinMode(zielona, OUTPUT); //Konfiguracja wyjść
  pinMode(czerwona, OUTPUT);

  digitalWrite(zielona, LOW); //Wyłączamy diody
  digitalWrite(czerwona, LOW);
}

void loop() {
  if (Serial.available() > 0) { //Czy Arduino odebrało dane
    //Jeśli tak, to odczytujemy je do znaku końca linii i zapisz w zmiennej odebraneDane
    odebraneDane = Serial.readStringUntil('\n');

    if (odebraneDane == "zielona") { //Jeśli odebrano słowo "zielona"
      digitalWrite(zielona, !digitalRead(zielona)); //To przełączamy diodę zieloną, czytając stan z wyjścia i zaprzeczając "!"
    }
    else if (odebraneDane == "czerwona") { //Jeśli odebrano słowo "czerwona"
      digitalWrite(czerwona, !digitalRead(czerwona)); //To przełączamy diodę czerwoną
    }
    else { //ani zielona ani czerwona -> zgłoś błąd
      Serial.println("Błąd. Nie znane wejście: '"+odebraneDane+"' Znam tylko 'zielona' i 'czerwona'.");
    }
  }
}

ale tu mam pytanie: dlaczego w treści jest:

Cytat

koniecznie użyj dodatkowych zmiennych typu bool, które będą pamiętały aktualny stan diod

bo wydaje mi się, że stan diody można odczytać (czyli odczytać stan wyjścia tak samo jak wejścia). Sprawdziłem i działa:

digitalWrite(zielona, !digitalRead(zielona));

Z punktu widzenia kodu, to wydaje się być najkrótsza możliwość. Ale może coś pomijam.

Intuicyjnie: nie wydaje mi się, bo przecież dodatkową zmienną też trzeba zapisać i odczytać z pamięci.

Może gdzieś w dokumentacji napisane, że odczytywanie stanu wyjścia przez digitalRead ma wady? Może jest kosztowniejsze (więcej cykli procesora)? Może trzeba trzymać stan maszyny w pamięci z jakiś innych powodów?

Czy powinienem unikać takiej konstrukcji?

Edytowano przez pawelmb
kod jako kod a nie jako załączniki
  • Lubię! 1
Link to post
Share on other sites

@pawelmb Fajnie że wrzuciłeś zadania, mam tylko prośbę dorzuć kody do treści używając bloku kodu wtedy każdy będzie mógł to obejrzeć, nawet na telefonie 😉 

Co do pytania: tak sposób który wrzuciłeś jest dobry, tak działa przełączanie. Gdybyśmy mówili o gołym mikrokontrolerze AVR to operacja ta jest banalna i tam na końcu tych funkcji coś takiego się dzieje. Odczyt to pobranie wartości 8 bitowego rejestru, zapis to ustawienie/skasowanie jednego bitu w tym rejestrze.

Funkcja Arduino jak spojrzysz na implementację (na gicie najszybciej znajdziesz jej kod) to jest tam sporo treści związanej ze sprawdzaniem argumentów, ale to na tym etapie nie rzutuje na wynik. Dlatego proponowany sposób jest dobry, podobnie samo ustawianie i kasowanie - też można tak zrobić.

Sugestia w pytaniu jest dla osób nie tak sprytnych 🙂 więc jak znasz coś lepszego, to feel free. Sky is the limit, albo RAM is the limit 😄 

Można jednak zauważyć pewną wadę takiego rozwiązania, ale ona objawi się jakbyś rozbudowywał program - więcej komend, więcej się dzieje, wtedy zbudowanie pewnej warstwy abstrakcji po stronie Arduino, która nie jest ultra wydajna, ale wygląda dobrze i jest łatwa w rozbudowie. Ten przykład nie obrazuje tego, ale czasem lepiej jest napisać więcej kodu, więcej funkcji, rozdzielić coś ale ładnie opisać, żeby przy najbliższej zmianie nie było potrzeby refaktoryzacji (przepisaniu) połowy kodu 😄 

  • Pomogłeś! 1
Link to post
Share on other sites

@Gieneq  Słuszna uwaga, poprawiłem wpis na blok kodu (założyłem, że kod taki prosty, że szkoda czasu oglądać, a wrzuciłem bardziej pro forma, ale może ktoś coś zauważy, więc poprawione).

Odnośnie 2.5 - ok, czyli przyjmuję, że to dobre rozwiązanie (zmyliło mnie słowo "koniecznie użyjcie"). Warstwa abstrakcji - tak, to jasne, często się przydaje, natomiast w tym przypadku, jeżeli odczytanie stanu wyjścia nie jest "droższe" to jednak zbędna komplikacja. Tak jest dużo przejrzyściej 🙂

Link to post
Share on other sites
18 godzin temu, pawelmb napisał:

Czy powinienem unikać takiej konstrukcji?

Ja tylko dodam, że odczytanie wartości ze zmiennej i z pinu to dwie różne rzeczy. Możemy upraszczając powiedzieć, że ze zmiennej odczytujesz stan jaki chciałbyś żeby był na pinie, a z pinu to co tam naprawdę jest. A uwierz mi - w bardziej skomplikowanych programach to niekoniecznie musi być to samo 🙂

Link to post
Share on other sites

Hej

Trochę rozbudowałem zadanie z poprzedniego tematu, czyli światła drogowe. Dorzuciłem do niego kilka warunków oraz komunikaty. Otrzymałem coś takiego:

#define d_czerwona 8
#define d_zolta 9
#define d_zielona 10
#define przycisk 11

boolean swiatla_stan; //stan światel, włączone/wyłączone
boolean swiatla_kontrola = false; //zmienna do sprawdzenia, czy stan świateł uległ zmianie

void setup () {
  
    Serial.begin(9600);   //Uruchomienie transmisji
    
    pinMode (d_czerwona, OUTPUT);
    pinMode (d_zolta, OUTPUT);
    pinMode (d_zielona, OUTPUT);
    
    pinMode (przycisk, INPUT_PULLUP); //odczytanie stanu przycisku
    
//wyłączenie wszystkich diód
    digitalWrite (d_czerwona, LOW);
    digitalWrite (d_zolta, LOW);
    digitalWrite (d_zielona, LOW);
    
    Serial.println("Kontrola sygnalizacji świetlnej");
    
    swiatla_stan = false;
    digitalWrite (d_czerwona, HIGH);
    delay (50);
    digitalWrite (d_czerwona, LOW);
    digitalWrite (d_zolta, HIGH);
    delay (50);
    digitalWrite (d_zolta, LOW);
    digitalWrite (d_zielona, HIGH);
    delay (50);
    digitalWrite (d_zielona, LOW);

    delay (1000);
      
//      Serial.println("swiatla_stan = " + swiatla_stan);  Nie można wyświetlić wartośći zmiennej typu BOOLEAN
//      Serial.println("swiatla_kontrola = " + swiatla_kontrola);
}

void loop () {

    if (digitalRead(przycisk) == LOW) { //włączenie cyklu świateł
      swiatla_stan = true;
      digitalWrite (d_zolta, LOW);
      digitalWrite (d_zielona, HIGH);
      delay (2000);
      digitalWrite (d_zielona, LOW);
      digitalWrite (d_zolta, HIGH);
      delay (600);
      digitalWrite (d_zolta, LOW);
      digitalWrite (d_czerwona, HIGH);
      delay (200);
      digitalWrite (d_czerwona, LOW);
      digitalWrite (d_zolta, HIGH);
      delay (600);
      digitalWrite (d_zolta, LOW);
    }
    else
    { //wyłączenie wszystkich diód
      swiatla_stan = false;
      digitalWrite (d_czerwona, LOW);
      digitalWrite (d_zolta, LOW);
      digitalWrite (d_zielona, LOW);
      digitalWrite (d_zolta, HIGH);
      delay (500);
      digitalWrite (d_zolta, LOW);
      delay (500);
    }
    if (swiatla_stan == swiatla_kontrola) {
      if (swiatla_kontrola == false) {
        swiatla_kontrola = true;
        Serial.println("UWAGA: sygnalizacja drogowa wyłączona!");
      }
      else
      {
        swiatla_kontrola = false;
        Serial.println("Sygnalizacja działa poprawnie");
      }
    }
}

W funkcji setup, kontrolnie chciałem wyświetlić wartość zmiennej typu boolean, ale chyba nie wiem jak to zrobić. Czy dla zmiennych typu boolean można zamiennie zamiast true/false wykorzystywać 1/0? Czy powinienem na coś zwrócić uwagę w celu optymalizacji zamieszczonego kodu programu? I jeszcze jedno, czy można wyczyścić zawartość okna Monitoru portu szeregowego? Próbowałem coś znaleźć w internecie, ale jedyne co znalazłem, to wstawienie pustych linii, w celu iluzorycznego wyczyszczenia okna.

 

Pozdrawiam

Darek

  • Lubię! 1
Link to post
Share on other sites
11 godzin temu, Darod napisał:

Czy dla zmiennych typu boolean można zamiennie zamiast true/false wykorzystywać 1/0?

@Darod tak można, bo true i false są po prostu zdefiniowane w środowisku jako 1 i 0. To tylko różnica "dla człowieka" komputera widzi to zawsze jako 1 lub 0.

11 godzin temu, Darod napisał:

Czy powinienem na coś zwrócić uwagę w celu optymalizacji zamieszczonego kodu programu?

W tak stosunkowo małych programach raczej nie ma dużego pola do popisu w kwestii optymalizacji, więc nie musisz się tym martwić. Raczej wiele tutaj się nie zmieni 🙂

11 godzin temu, Darod napisał:

I jeszcze jedno, czy można wyczyścić zawartość okna Monitoru portu szeregowego?

Nie, nie ma takiej możliwości. Monitor portu szeregowo po prostu wyświetla to co zostanie do niego wysłane. Nie ma możliwości, aby z poziomu Arduino wpłynąć na informacje, które zostały już wcześniej do niego wysłane. Pozostaje "ręczne" czyszczenie okna przez użytkownika.

  • Lubię! 1
Link to post
Share on other sites

Hej

Mam jeszcze jedno pytanie, które nie daje mi spokoju. Na wszystkich rysunkach z dotychczasowych lekcji, do każdej diody połączony był rezystor. Czy takie podłączenie jak na załączonym zdjęciu jest poprawne?

Pozdrawiam

Darek

1613511404526.jpg

Link to post
Share on other sites

@Darod (uprzedzam, że się nie znam, sam się uczę dopiero, natomiast wg mnie:) Jeżeli dobrze czytam rysunek, chciałbyś podłączyć jeden (o większej oporności) rezystor a za nim, równolegle względem siebie, 3 diody.

No to tu: Kurs podstaw elektroniki jest napisane:

Cytat

Nie powinno się łączyć samych diod równolegle, nawet jeśli są tego samego koloru! Napięcie przewodzenia każdej z nich będzie nieco inne, przez co niektóre będą świeciły słabo, a niektóre mogą się uszkodzić, ponieważ popłynie przez nie większość prądu.

Czyli nie jest poprawnie (choć może się zdarzyć przypadkiem, że zadziała).

Link to post
Share on other sites
(edytowany)

@Darod No właśnie, na każdym jest osobny rezystor więc i tu powinien być. Rezystor może być wspólny ale muszą być ku temu warunki (zbliżone napięcie przewodzenia, duży zapas rezystancji = za mały prąd na diodzie o najmniejszym spadku, itp.), a gdy masz kilka różnych kolorów (tj. każda dioda ma inne napięcie przewodzenia) to każda musi mieć osobny rezystor. Czyli tak jak zacytował @pawelmb

 

Edytowano przez Gieneq
Link to post
Share on other sites

Czemu kod (Serial.println("Witaj " + odebraneDane + "!");) działa, ale kiedy odebrane dane będą jakaś zmienną np. int już nie? Wyrzuca błąd error: invalid operands of types 'const char*' and 'const char [2]' to binary 'operator+'.

Gdybym chciał żeby mi odmierzało czas i wyświetlało np. Minęło już (a = a + 1000) sekund. To nie można tego zrobić w jednej linijce. 

 


int czas = 0;

void setup() {
  Serial.begin(9600); //Uruchomienie komunikacji
}
 
void loop() {

Serial.println("Minelo juz " + czas + "sekund");
 delay(1000);
 czas = czas + 1000;
  }

 

Link to post
Share on other sites

@meerlin94 to jest dobre pytanie 🙂  a odpowiedź to sptrawdzenie dokumentacji string, a głównie w dokumentacji konkatenacji (dodawania).

Dodawanie stringów z czymś jest błędem, bo prowadzi do niejednoznaczności:

Cytat

Caution: You should be careful about concatenating multiple variable types on the same line, as you may get unexpected results. 

Ma to też mniejszy sens, po co dodawać kilka napisów, cośtam konwertować, zużywać pamięć, jak można wypisać stringi w osobnym princie i to stringi zapisane jako stałe we flashu (uzywając macra F()), a zmienną osobno. Wyjdzie szybciej i mniej zażytego RAMu. Więc coś takiego będzie lepsze:

Serial.print(F("Minelo juz "));
Serial.print(czas);
Serial.println(F(" sekund."));

 

  • Lubię! 2
Link to post
Share on other sites
(edytowany)
#define zielona 8 // definicja wyjścia 8
#define czerwona 9 // definicja wyjścia 9

boolean zielonaData = ""; 
boolean czerwonaData = "";

String odebraneDane = ""; //Pusty ciąg odebranych danych
 
void setup() {
  Serial.begin(9600); //Uruchomienie komunikacji
  pinMode(zielona, OUTPUT); //Konfiguracja wyjść
  pinMode(czerwona, OUTPUT); // Konfiguracja wyjść
  
  digitalWrite(zielona, LOW); //Wyłączamy diody
  digitalWrite(czerwona, LOW); //Wyłączamy diody
  boolean zielonaData = false;  
  boolean czerwonaData = false;
}
 
void loop() {
  if(Serial.available() > 0) { //Czy Arduino odebrało dane
    //Jeśli tak, to odczytujemy je do znaku końca linii i zapisz w zmiennej odebraneDane
    odebraneDane = Serial.readStringUntil('\n'); 
    
    if (odebraneDane == "zielona") { //Jeśli odebrano słowo "zielona"
      if (zielonaData == false){ // jesli dioda jest wylaczona
        digitalWrite(zielona, HIGH); //To włączamy diodę zieloną
           zielonaData = true; // dioda jest wlaczona
          Serial.println (" Poprawne dane świecimy");
            } else{
        digitalWrite(zielona,LOW); // wylacz diode
        Serial.println (" Poprawne dane gasimy");
        zielonaData = false; // dioda wylaczona
      }

    } else if (odebraneDane == "czerwona") { //Jeśli odebrano słowo "czerwona"
     if (czerwonaData == false){ // jesli dioda jest wylaczona
        digitalWrite(czerwona, HIGH); //To włączamy diodę zieloną
           czerwonaData = true; // dioda jest wlaczona 
          Serial.println (" Poprawne dane świecimy");
            } else{
        digitalWrite(czerwona,LOW); // wylacz diode
        Serial.println (" Poprawne dane gasimy");
        czerwonaData = false; // dioda jest wylaczona 
      }
        
    }
    else{ 
      Serial.println (" błedne dane");
    }
   
    }
    }

Zastanawiam się, czy jest to normalne, że musze wpisać dwa razy na samym początku "zielona/czerwona" aby dioda zaczęła świecić? Sytuacja jest tylko podczas pierwszego wpisania. 
Początkowy stan dawałem również na true ale nic to nie zmieniło :C 

Edytowano przez cenzar
Link to post
Share on other sites

@cenzar witam na forum 🙂 

Mieszasz typy danych, nie możesz do booleana dać "" bo jest to informacja że zmienna jest stringiem.

Link to post
Share on other sites
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

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!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

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

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.