Skocz do zawartości

Kurs Arduino - #6 - kontynuacja UART, serwomechanizmy


Komentator

Pomocna odpowiedź

(edytowany)

@pawelmackowski fajnie że działasz dalej z programem. Taka drobna rada - dla zachowania estetyki kodu polecam automatyczne formatowanie kody. Skrót: Ctrl+T 😉 

17 godzin temu, ceiem napisał:

Zad. 6.1.

@ceiem A w tym zadaniu jest informacja żeby linika wyświetliła się tylko raz, a jak jest w tym przypadku? W warunku jest sprawdzanie stanu więc pewnie będzie się wypisywać jak tylko będzie możliwość. Może spróbuj wykryć moment wciśnięcia przycisku (zbocze).

Edytowano przez Gieneq
Link do komentarza
Share on other sites

Cytat

Następnie po wciśnięciu przycisku podłączonego do Arduino wysyłaj jeden raz linijkę zawierającą informacje

To co masz zrobione jest dobre, ale to jest trochę bardziej wymagające 🙂 

Link do komentarza
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

(edytowany)

Sytuacja jest taka: wciskasz przycisk - wyświetla się jedna linia tekstu i koniec. Możesz dalej trzymać przycisk, puścić, nic się innego nie dzieje. Kolejny raz klikasz i znowu tylko 1 linia.

W takim pseudokodzie to może być coś takiego: Jeżeli ostatnio nie był wciśnięty przycisk i teraz jest wciśnięty to wypisz tekst. 🙂 

Edytowano przez Gieneq
Link do komentarza
Share on other sites

Zadanie 6.1

#define FotorezystorJeden A5
#define Potencjometr A4
#define FotorezystorDrugi A3
#define Przycisk 8

int counter = 0;  //licznik ile razy wcisnieto przycisk
int valFoto1 = 0; //zmienne do przechowywania wartosci odczytanych z peryferiow
int valFoto2 = 0;
int valPotencjometr = 0;

void setup() {
  Serial.begin(9600);  //rozpoczęcie komunikacji przez UART
  pinMode(Przycisk, INPUT_PULLUP);   //przypisanie przycisku pod pin

}

void loop() {
  valFoto1 = analogRead(FotorezystorJeden);  //odczytanie wartosci z peryferiow
  valFoto2 = analogRead(FotorezystorDrugi);
  valPotencjometr = analogRead(Potencjometr);

  if (digitalRead(Przycisk) == LOW) {
    counter += 1;   //za kazdym kliknieciem przycisku ilosc klikniec bedzie sie zwiekszac o 1
    Serial.print("Fotorezystor 1: ");
    Serial.print(valFoto1);
    Serial.print(", Fotorezystor 2: ");
    Serial.print(valFoto2);
    Serial.print(", Potencjometr: ");
    Serial.print(valPotencjometr);
    Serial.print(" Przycisk wciśnięto ");
    Serial.print(counter);
    Serial.print(" razy.\n");
    delay(1000);  //opoznienie zeby z kazdym wcisnieciem przycisku wyswietlalo nam wartosci tylko raz a nie kilka na raz
  }
}

Efekt w monitorze portu szeregowe: 

image.thumb.png.a968851f3864ca5b851e28f1f80ac288.png

Zadanie 6.2

#define Zielona 9
#define Czerwona 8

int odebraneDane = 0;

void setup() {
  Serial.begin(9600);

  pinMode(Zielona, OUTPUT);
  pinMode(Czerwona, OUTPUT);

  digitalWrite(Zielona, LOW);
  digitalWrite(Czerwona, LOW);
}

void loop() {

  Serial.print("Podaj jaką diodę mamy uruchomić ('C' -> czerwona, 'Z' -> zielona: \n");
  while (Serial.available() == 0) {
    delay(1000);
  }
  if (Serial.available() > 0) {    //jeśli Arduino otrzymało jakieś dane
    odebraneDane = Serial.read();    //przypisujemy wpisane dane do zmiennej odebraneDane


    switch (odebraneDane) {
      case 'Z':     //jeśli odebrana wartosc brzmi Zielona to zapalamy zieloną diodę
        digitalWrite(Zielona, HIGH);
        delay(1000);
        digitalWrite(Zielona, LOW);
        break;

      case 'C':    //tu zapalamy czerwoną diodę
        digitalWrite(Czerwona, HIGH);
        delay(1000);
        digitalWrite(Czerwona, LOW);
        break;
    }
  }
  delay(1000);
}

Działa, tylko nie mogę sobie poradzić z jedną rzeczą. 
Na początku pyta raz czy chcemy uruchomić diodę czerwoną czy zieloną.
Po wybraniu jednorazowo opcji, np. Z, zapala diodę zieloną, czeka sekundę i ją gasi.
Ale wtedy pytanie pojawia się zamiast raz, dwa razy z rzędu chwilę po sobie.

Może ktoś podpowie jak usunąć ten nie zbyt istotny natomiast mało estetyczny aspekt. 

Zadanie 6.3 

Dodałem 2 przyciski po wciśnięciu jednego serwomechanizm wskazuje wartość minimalną, po wciśnięciu drugiego wskazuje wartość maksymalną. 

#include <Servo.h> //biblioteka odpowiedzialna za serwomechanizm
#define fotorezystor A5  //zadeklarowanie pinów dla peryferiów 
#define przyciskMIN 6
#define przyciskMAX 7

Servo serwomechanizm;
byte pozycja = 0;                                      //aktualna pozycja serwa w skali 0-180 stopnii
int pozycjaPoprzednia = 0;
int valMIN = 0; //wartosc minimalna dla swiatla
int valMAX = 958; //wartosc maksymalna

void setup() {
  serwomechanizm.attach(11);
  Serial.begin(9600);                 //rozpoczęcie komunikacji przez UART
  pinMode(przyciskMIN, INPUT_PULLUP);
  pinMode(przyciskMAX, INPUT_PULLUP);
}

void loop() {
  int odczytCzujnika = analogRead(fotorezystor);

  while (digitalRead(przyciskMAX) == LOW)
  {
    valMAX = odczytCzujnika;
    delay(100);
  }

  while (digitalRead(przyciskMIN) == LOW)
  {
    valMIN = odczytCzujnika;
    delay(100);
  }

  //odczytujemy wartosc z fotorezystora
  pozycja = map(odczytCzujnika, valMIN, valMAX, 180, 0);  //mapujemy ja na mozliwy zakres ruchu serwomechanizmu
  pozycja = constrain(pozycja, 180, 0);

  if (abs(pozycja - pozycjaPoprzednia) > 5)               //sprawdzamy czy różnica jest większa niż 5 stopni
  {
    serwomechanizm.write(pozycja);                        //wykonujemy ruch
    pozycjaPoprzednia = pozycja;                          //nadpisujemy aktualną pozycje jako poprzednia
  }

  Serial.println("Aktualna wartość fotorezystora: ");
  Serial.println(odczytCzujnika);                         //wysyłamy wartość do terminala UART
  delay(300);
}

Zadanie 6.4

Poniosło mnie z kolorami. Ale korzystałem wyłącznie z tego co miałem pod ręką w domu rodzinnym 😄 

117883844_727599501132230_5226670907055830536_n.thumb.jpg.6b024bcc90d036630d69cd873d7bd330.jpg

 

Edytowano przez samemilerzeczy
  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Nagraliśmy z bratem też krótki filmik na którym widać lekko 'upośledzone' działanie naszego czujnika natężenia światła. Musiałbym jakoś stabilnie przymocować cały serwomechanizm żeby to wytrzymało bez trzymania przeze mnie. Ale nie mam przy sobie taśmy dwustronnej, a nie chce tego na ten moment zaklejać sztyftem i niepotrzebnie brudzić 😛 

Następnym razem umiejętności nagrywania brata jak i umiejętności edycji filmów wideo moje zostaną poprawione i dodamy do tego jakąś melodyjkę. 

  • Lubię! 2
Link do komentarza
Share on other sites

5 godzin temu, samemilerzeczy napisał:

odebraneDane = Serial.read(); //przypisujemy wpisane dane do zmiennej odebraneDane aż do spacji

 

A kto Ci takich bajek naopowiadał o jakiejś spacji? Serial.read() pobiera dokładnie jeden znak z bufora UART. Czyli w Twoim przypadku sprawa wygląda tak:

  • Program pyta o coś tam
  • Czeka na znak
  • Ty wysyłasz np. znak 'C' i znak nowej linii
  • Program pobiera C z bufora UART
  • Program zapala czerwoną diodę na sekundę
  • Program pyta o coś tam
  • Program pobiera znak nowej linii z bufora UART
  • Program nie robi nic
  • Program pyta o coś tam...

A jak się tego pozbyć? Napisać program prawidłowo.

Link do komentarza
Share on other sites

1 godzinę temu, ethanak napisał:

A kto Ci takich bajek naopowiadał o jakiejś spacji? Serial.read() pobiera dokładnie jeden znak z bufora UART. Czyli w Twoim przypadku sprawa wygląda tak:

  • Program pyta o coś tam
  • Czeka na znak
  • Ty wysyłasz np. znak 'C' i znak nowej linii
  • Program pobiera C z bufora UART
  • Program zapala czerwoną diodę na sekundę
  • Program pyta o coś tam
  • Program pobiera znak nowej linii z bufora UART
  • Program nie robi nic
  • Program pyta o coś tam...

A jak się tego pozbyć? Napisać program prawidłowo.

Początkowo było Serial.readStringUntil('\n');  bo miałem trochę inny zamiar na to zadanie. Kod zmieniłem a komentarz został stary, mój błąd 😅

 

Link do komentarza
Share on other sites

@ethanak

1. Błąd znika gdy ustawię w monitorze portu szeregowego opcję brak zakończenia linii.

  • Nowa linia oznacza, że za każdym razem gdy wyślemy tekst będzie on zakończony nową linią. Rozumiem to tak, że arduino dostanie jakby dwie dane: nasz tekst i znak nowej linii i dlatego 2 razy pojawia mi się wtedy zapytanie o kolor diody którą chce zapalić. 
  • Brak zakończenia linii oznacza, że wiadomości czekają na odbiór w buforze i zostają odczytane dopiero z najbliższą wiadomością, którą zakończymy znakiem nowej linii. Także mamy tylko jedną daną w związku z czym tylko jedno pytanie o kolor diody. 

2. Błąd znika również gdy pozostawię zakończenie nową linią  natomiast zmodyfikuje program tak żeby odbierał cały string jako dane wejściowe a nie tylko jeden znak. 

#define Zielona 9
#define Czerwona 8

String odebraneDane = "";
byte kolor = 0;

void setup() {
  Serial.begin(9600);

  pinMode(Zielona, OUTPUT);
  pinMode(Czerwona, OUTPUT);

  digitalWrite(Zielona, LOW);
  digitalWrite(Czerwona, LOW);
}

void loop() {

  Serial.print("Podaj czy uruchomić diodę ZIELONĄ czy CZERWONĄ: \n");

  while (Serial.available() == 0) {
    delay(1000);
  }

  if (Serial.available() > 0) {    //jeśli Arduino otrzymało jakieś dane
    odebraneDane = Serial.readStringUntil('\n');    //przypisujemy wpisane dane do zmiennej odebraneDane
  }

  if (odebraneDane == "zielona") {
    kolor = 1;
  } else if (odebraneDane == "czerwona") {
    kolor = 2;
  }

  switch (kolor) {
    case 1:     //jeśli odebrana wartosc brzmi Zielona to zapalamy zieloną diodę
      digitalWrite(Zielona, HIGH);
      delay(1000);
      digitalWrite(Zielona, LOW);
      break;

    case 2:    //tu zapalamy czerwoną diodę
      digitalWrite(Czerwona, HIGH);
      delay(1000);
      digitalWrite(Czerwona, LOW);
      break;

    default:
      Serial.println("Nie posiadamy takiego koloru!"); 
      break;
  }

  delay(1000);
}

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

29 minut temu, samemilerzeczy napisał:

1. Błąd znika gdy ustawię w monitorze portu szeregowego opcję brak zakończenia linii.

To nie jest poprawienie błędu, tylko marzenie, że dane wejściowe będą akurat takie a nie inne (inaczej: zamiatanie pod dywan, ulubiony sposób działania programistów PHP)... co będzie, gdy zamiast monitora z Arduino IDE będziesz chciał użyć jakiegokolwiek innego, który akurat takiej funkcjonalności nie posiada? Albo wprowadzisz dwa znaki (np. CZ)?

 

30 minut temu, samemilerzeczy napisał:

Błąd znika również gdy pozostawię zakończenie nową linią  natomiast zmodyfikuje program tak żeby odbierał cały string jako dane wejściowe a nie tylko jeden znak. 

A to jest prawidłowy sposób poprawienia błędu. Oczywiście nie jedyny możliwy, ale prawidłowy.

Nie jest natomiast prawidłowa inna konstrukcja:

32 minuty temu, samemilerzeczy napisał:

while (Serial.available() == 0) {
	delay(1000);
}
if (Serial.available() > 0) { //jeśli Arduino otrzymało jakieś dane
	odebraneDane = Serial.readStringUntil('\n'); //przypisujemy wpisane dane do zmiennej odebraneDane
}

 

Zastanów się: czy po wyjściu z pętli while istnieje możliwość, że Serial.available() jest mniejsze lub równe zeru?

I jeszcze drobiazg: z przyczyn czysto technicznych zmienna odebraneDane powinna być lokalna w loop(), a nie globalna. Nie chcę się tu rozpisywać na temat niebezpieczeństw związanych z taką a nie inną deklaracją, ale jeśli kogoś to baaaaaardzo interesuje, warto poczytać o ograniczeniach funkcji malloc() i free() w mikrokontrolerach (np. na stronie poświęconej avr-libc). W takim prostym programie raczej nic nie grozi, ale jak się człowiek przyzwyczai do czegoś to potem można przeżyć traumę (np. "dlaczego mój program przestaje działać po jakimś czasie" - autentyczny przypadek z forum).

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

@ethanak

Wychodzi na to, że już po jednokrotnym wykonaniu pętli zawsze coś będzie znajdywało się w buforze. W związku z czym warunek 

while (Serial.available() == 0) 

nie będzie już w ogóle spełniony (chyba, że w jakiś sposób resetowałbym bufor). Tak samo czytając trochę z ciekawości o funkcjach malloc() i free() powodem dla którego program może przestać działać jest zapchanie pamięci "lukami" spowodowanymi właśnie np takim niepotrzebnym warunkiem.

To taka upośledzona teoria zrozumiała na mój język, ale teoria w 90% przypadków wydaje się prosta. Gorzej jest z implementacją w praktyczne zastosowania..

Więc myśląc o tym jak uniknąć stosowania takiej konstrukcji jak while ( Serial.available() == 0) wpadłem póki co tylko na jedno rozwiązanie. 

  • Wrzucić zapytanie o kolor diody do wyświetlenia w SETUP tak żeby było wywoływane tylko raz. I wtedy jeśli chciałbym np móc dokonać wyboru znowu to zresetowanie tego buforu tak żeby zapytało ponownie.

Nawet dla mnie brzmi to głupio. Ale szukając pomocy w sieci nie znalazłem zbyt wiele alternatywnych rozwiązań za to znalazłem mnóstwo próśb żeby nie używać tej konstrukcji bo jest błędna. Także prosiłbym o HELP! 

Link do komentarza
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!

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.