Skocz do zawartości

Kurs Arduino - #4 - Przetwornik ADC


Pomocna odpowiedź

zadanie 4.5 

#define diodaZielona 2
#define diodaZolta 3
#define diodaCzerwona 4
#define przycisk 8
#define buzzer 9
String liczba="";//odpowiedz gracza
int odczytanaWartosc=0;//wartosc potencjometru
int liczbaGracza=0;//przekonwertowana odpowiedz gracza
int zycia=0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);//transmisja
pinMode(diodaZielona,OUTPUT);
pinMode(diodaZolta,OUTPUT);
pinMode(diodaCzerwona,OUTPUT);
pinMode(przycisk,INPUT_PULLUP);
pinMode(buzzer,OUTPUT);

Serial.println("Witaj w grze!");
delay(2000);
Serial.println("Podaj liczbe od 0 do 1023, mozesz pomylic sie o +/-50. Masz 3 zycia.");
delay(2000);
Serial.println("Przekrec potencjmetr i nacisnij przycisk!");
while(digitalRead(przycisk)==HIGH){}//program czeka na wcisniecie przycisku
odczytanaWartosc=analogRead(A5);//podana liczba to odczyt z analog 5
Serial.print("Podaj liczbe:"); 
}

void loop() {
  // put your main code here, to run repeatedly:
while(Serial.available()==0){}//czekanie na odpowiedz gracza
if(Serial.available()>0){//jezeli odebrano dane to
liczba=Serial.readStringUntil('\n');//odczytaj je do koncia lini i zapisz w zmiennej liczba
liczbaGracza=liczba.toInt();//przekonwertowana odpowiedz gracza
Serial.print(liczbaGracza);
}
if(liczbaGracza -50<=odczytanaWartosc && liczbaGracza +50>=odczytanaWartosc){//warunek wygranej
digitalWrite(diodaZielona,HIGH);//dioda zielona zapala sie
Serial.println();
Serial.println("Brawo wygrales!");
delay(2000);
Serial.print("Liczba na potencjometrze wynosi:");
Serial.println(odczytanaWartosc);
}
else if(zycia==0){//gdy jest pudlo
digitalWrite(diodaZolta,HIGH);//dioda zolta zapala sie po raz 1
digitalWrite(buzzer,HIGH);//buzzer on
Serial.println();//odstep
Serial.println("Nie trafiles, sprobuj ponownie.");
delay(2000);
digitalWrite(diodaZolta,LOW);//dioda zolta gasnie
digitalWrite(buzzer,LOW);//buzzer off
Serial.println("Zostaly Ci dwie proby!");
delay(2000);
Serial.print("Podaj liczbe od 0 do 1023:");
zycia++;
}
else if(zycia==1){//gdy jest drugie pudlo
digitalWrite(diodaZolta,HIGH);//dioda zolta zapala sie po raz 2
digitalWrite(buzzer,HIGH);//buzzer on
Serial.println();//odstep
Serial.println("Nie trafiles ponownie!");
delay(2000);
digitalWrite(diodaZolta,LOW);//dioda zolta gasnie
digitalWrite(buzzer,LOW);//buzzer off
Serial.println("Zostala Ci tylko jedna proba! Wykorzystaj ja!");
delay(2000);
Serial.print("Podaj liczbe od 0 do 1023:");
zycia++; 
}
else if(zycia==2){//gdy jest trzecie pudlo
digitalWrite(diodaZolta,HIGH);//dioda zolta zapala sie po raz 3 
digitalWrite(diodaCzerwona,HIGH);//dioda czerwona zapala sie
digitalWrite(buzzer,HIGH);//buzzer on
Serial.println();//odstep
Serial.println("Niestety szczescie Ci nie sprzyjalo.");
delay(2000);
Serial.println("Nie udalo Ci sie wygrac!");
zycia++;
delay(2000);
digitalWrite(buzzer,LOW);//buzzer off
}
else {
digitalWrite(diodaZolta,LOW);//dioda zolta gasnie
digitalWrite(diodaCzerwona,HIGH);//dioda czerwona zapala sie
Serial.println();//odstep
Serial.println("To juz koniec gry!");
}
}

zadanie4.6

#define diodaZielona1 2
#define diodaZielona2 3
#define diodaZolta 4
#define diodaCzerwona1 5
#define diodaCzerwona2 6

int foto1;
int foto2;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
pinMode(diodaZielona1,OUTPUT);
pinMode(diodaZielona2,OUTPUT);
pinMode(diodaZolta,OUTPUT);
pinMode(diodaCzerwona1,OUTPUT);
pinMode(diodaCzerwona2,OUTPUT);
  
digitalWrite(diodaZielona1,LOW);
digitalWrite(diodaZielona2,LOW);
digitalWrite(diodaZolta,LOW);
digitalWrite(diodaCzerwona1,LOW);
digitalWrite(diodaCzerwona2,LOW);
}

void loop() {
  // put your main code here, to run repeatedly:
foto1=analogRead(A5);
foto2=analogRead(A4);

if(foto1<foto2){
digitalWrite(diodaZielona1,HIGH);
digitalWrite(diodaZielona2,HIGH);
digitalWrite(diodaZolta,LOW);
digitalWrite(diodaCzerwona1,LOW);
digitalWrite(diodaCzerwona2,LOW);
}
else if(foto1-150<=foto2 && foto1+150>=foto2){
digitalWrite(diodaZielona1,LOW);
digitalWrite(diodaZielona2,LOW);
digitalWrite(diodaZolta,HIGH);
digitalWrite(diodaCzerwona1,LOW);
digitalWrite(diodaCzerwona2,LOW);
}
else if(foto1>foto2){  
digitalWrite(diodaZielona1,LOW);
digitalWrite(diodaZielona2,LOW);
digitalWrite(diodaZolta,LOW);
digitalWrite(diodaCzerwona1,HIGH);
digitalWrite(diodaCzerwona2,HIGH);
}
else{
  digitalWrite(diodaZielona1,LOW);
digitalWrite(diodaZielona2,LOW);
digitalWrite(diodaZolta,LOW);
digitalWrite(diodaCzerwona1,LOW);
digitalWrite(diodaCzerwona2,LOW);
}
delay(50);
}

 

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

Bardzo interesujący kurs! W części "Prosty woltomierz" wkradł się jednak drobny błąd. Przeliczając z wartości sygnału analogowego na napięcie, powinno się dzielić raczej przez 1023 (wartość odpowiadającą maksymalnemu napięciu), a nie przez 1024 (liczbę możliwych wartości). Łatwo to unaocznić zwiększając precyzję w funkcji wypisującej wynik i ustawiając potencjometr w skrajnym położeniu:

Serial.println(5.0*odczytanaWartosc/1024,3)

Dostaniemy wartość 4.995. Po zmianie na 1023:

Serial.println(5.0*odczytanaWartosc/1023,3)

uzyskujemy oczekiwane 5.000.

Link do komentarza
Share on other sites

@pczachor1 witam na forum 🙂 Temat ten powraca często (nie tylko w kontekście tego kursu), zachęcam do lektury całego poniższego tematu, z którego dowiesz się dlaczego dzielnie przez 1024 jest poprawne: https://forbot.pl/forum/topic/11985-przeliczanie-adc-na-v-dzielenie-przez-1023-czy-1024/

Jeśli wolisz inne źródła to zapoznaj się z tym artykułem: https://forum.allaboutcircuits.com/threads/why-adc-1024-is-correct-and-adc-1023-is-just-plain-wrong.80018/

Temat ten jest jednak mało intuicyjny. W Internecie znaleźć można rozwiązania z dzieleniem przez 1023 i 1024, ale ta druga wersja jest właściwsza (patrząc od strony budowy przetworników ADC).

  • Pomogłeś! 1
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

@Treker dziękuję za szybką odpowiedź i rzeczywiście, zwracam honor! Faktycznie zrobiłem błędne założenie na temat znaczenia wartości zwracanej przez ADC.  Temat istotnie ciekawy i "kontrowersyjny" – zanim napisałem mojego poprzedniego posta, zajrzałem na oficjalną stronę Arduino i nawet tam robią ten błąd (https://www.arduino.cc/en/Tutorial/BuiltInExamples/ReadAnalogVoltage), choć teraz widzę, że na ichnim forum też jest wątek wyjaśniający poprawność dzielenia przez 1024.

Chyba całe zamieszanie (przynajmniej po mojej stronie) stąd, że 1023 – jako maksymalna wartość zwracana przez przetwornik – wydaje się na pierwszy rzut oka laika odpowiadać 5V, podczas gdy teraz już rozumiem, że w rzeczywistości odpowiada przedziałowi od 4.995V do 5V (czyli po przekroczeniu 5V wchodzilibyśmy już teoretycznie w wartość 1024). Może warto umieścić podane przez Ciebie linki w kursie? Żeby za jakiś czas kolejny mądrala znowu nie próbował odkryć koła na nowo jak ja? 🙂

Edytowano przez pczachor1
Drobna korekta językowa.
  • Lubię! 1
Link do komentarza
Share on other sites

Witajcie, skończyłem tą część kursu. Nie mam tylko bladego pojęcia, jak zrobić zadania domowe. Nie wiem nawet o co zapytać, więc stwierdziłem, że pójdę dalej a do tych zadań wrócę pod koniec kursu. Ale tak w ogóle to świetny kurs, odwalacie kawał świetnej roboty. 🙂

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

#define zielona 7
#define druga 5 //żółta
#define czerwona 3
#define przycisk 13

float liczba = 0.00;
float volty = 0.00;
int szanse = 3;
bool wykrywacz = 0;

void setup () {
  pinMode(zielona, OUTPUT);
  pinMode(druga, OUTPUT);
  pinMode(czerwona, OUTPUT);
  pinMode(przycisk, INPUT_PULLUP);
  Serial.begin(9600);
  digitalWrite(zielona, LOW);
  digitalWrite(druga, LOW);
  digitalWrite(czerwona, LOW); 
}

void loop() {
  if (digitalRead(przycisk)==LOW && (wykrywacz == 0)) {
    Serial.println("Podaj liczbę!");
    delay(1000);
    wykrywacz = 1;
  }
  if(Serial.available() > 2 && wykrywacz == 1) {
    liczba = Serial.parseFloat();
    volty = analogRead(A0);
    volty = volty * (5.0/1024.0);    
    liczba = liczba - volty;      
    if((-0.21 < liczba) && (liczba < 0.21)) {
      Serial.println("dobrze!");
      Serial.println(liczba);
      digitalWrite(zielona, HIGH);
      delay(1000);
      digitalWrite(zielona, LOW);
      szanse = 3;
    }
    if(!(-0.21 < liczba) || !(liczba < 0.21)) {
      Serial.println(liczba);    
      digitalWrite(druga, HIGH);
      delay(1000);
      digitalWrite(druga, LOW);
      szanse--;
      delay(1000);
      
    }
  }    
  if (szanse==0) {
    digitalWrite(czerwona, HIGH);
    delay(1000);
    digitalWrite(czerwona, LOW);
    wykrywacz = 0;
    szanse = 3; 
  }           
}

Zadanie z prostą grą (przerobione na zgadywanie napięcia).

Mam pytania;

Jak zeskalować zmienną float w funkcji map()?

Jak wyczyścić bufor za pomocą komendy?

Czy istnieje jakiś prostszy sposób do zapisania zakresu liczb do if-a?

Dlaczego potencjometr nie ma rezystora zabezpieczającego? [(Skrajna pozycja powinna w moim mniemaniu robić zwarcie)]

Czy ktoś może mi wytłumaczyć, jak to się stało, że w skrajnej pozycji potencjometru wyłączyła mi się całkowicie płytka? (myślałem, że ją spaliłem)

Link do komentarza
Share on other sites

Funkcja map() składa się wewnątrz z long int'ów, więc możesz se zrobić dzielnik int(liczba_int)=liczba*(4 294 967 295/twoj_dzielnik). Przez zmienną twoj_dzielnik dostosowujesz (pseudo) dokładność konwersji floata na int'a jaką chcesz osiągnąć. Jeżeli chodzi o 3-pytanie to możesz robić takie if'y: if(-0.21<liczba<0.21){...} else{...}. W przypadku skrajnej pozycji potencjometru masz rację, przydałby się dodatkowy rezystor, a jeżeli chodzi o twoje obawy to nie martw się bo projektanci Arduino defakto to przewidzieli i dali w obwodzie zasilania z USB komparator, który w razie przekroczenia wartości 5V odcina zasilanie dostarczane przez USB.

Edytowano przez XPapekX
Link do komentarza
Share on other sites

Jak widzę na rysunkach do kursu, potencjometr jest zawsze podłączony we właściwy sposób  - krańce do zasilania i masy, a suwak zaś do wejścia ADC. W takim układzie nie możliwości wywołania zwarcia. Jeśli zwarcie występuje przy skrajnym położeniu suwaka, to znaczy że suwak jest podłączony do zasilania lub masy.

Komparator w Arduino UNO nie ma za zadanie wykrywanie zwarcia, lecz odłącza zasilanie z portu USB w momencie podłączenia zasilania do wejścia Vin tak, aby cały układ był zasilany tylko z jednego źródła.

Bufor wejściowy możemy wyczyścić tak:

  while (Serial.available() > 0) Serial.read();

 W początkach Arduino funkcja Serial.flush() czyściła bufor wejściowy, ale teraz robi inne rzeczy.

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

#define dno_1 3
#define dno_2 5
#define centrum 7
#define szczyt_2 9
#define szczyt_1 11

float volty_1 = 0;
float volty_2 = 0;

void setup() {
  Serial.begin(9600);
  pinMode(dno_1, OUTPUT);
  pinMode(dno_2, OUTPUT);
  pinMode(centrum, OUTPUT);
  pinMode(szczyt_2, OUTPUT);
  pinMode(szczyt_1, OUTPUT);
  digitalWrite(dno_1, LOW);
  digitalWrite(dno_2, LOW);
  digitalWrite(centrum, LOW);
  digitalWrite(szczyt_2, LOW);
  digitalWrite(szczyt_1, LOW);
}

void loop() {
  volty_1 = analogRead(A5);
  volty_1 = volty_1 * (5.0/1024.0);
  volty_2 = analogRead(A0);
  volty_2 = volty_2 * (5.0/1024.0);
  volty_1 = volty_1 - volty_2;
  if((0.51 > volty_1) && (volty_1 > -0.51)) {
    digitalWrite(centrum, HIGH);
  } else {digitalWrite(centrum, !HIGH);}
  if ((0.51 < volty_1) && (volty_1 < 1.5)) {
    digitalWrite(dno_2, HIGH);
  } else {digitalWrite(dno_2, LOW);}
  if ((1.5 < volty_1) && (volty_1 < 3.0)) {
    digitalWrite(dno_1, HIGH);
  } else {digitalWrite(dno_1, LOW);}
  if ((-0.51 > volty_1) && (volty_1 > -1.5)) {
    digitalWrite(szczyt_2, HIGH);
  } else {digitalWrite(szczyt_2, LOW);}     
  if ((-1.5 > volty_1) && (volty_1 > -3.0)) {
    digitalWrite(szczyt_1, HIGH);
  } else {digitalWrite(szczyt_1, LOW);}
  delay(1000);    
}

To coś do wykrywania gdzie mocniej świeci.

A propos potencjometru. Później normalnie działał, mimo, że go nie przestawiałem. Po za tym co to za różnica czy zasilanie idzie do suwaka czy nie jak oba wyprowadzenia są do masy (nie nie podpiąłem obu nóżek do masy)?

Link do komentarza
Share on other sites

Moja wersja 4.5 po 2 dniowej wojnie z tym programem w końcu mi się udało 😄 

 

4.5

 

//Konfiguracja pinów wyj nazwa = numer pinu

#define green 2

#define red 9

#define yellow 10

#define button 11

//Zmienne

bool wyslano = false;

bool game_on = false;

String LiczbaUserT = "" ;

int LiczbaUserL = 0;

int proby = 0;

int W_Pot = 0;

int W_P1 = 0;

int W_P2 = 0;

//Ropoczęcie programu

void setup() {

//Konfiguracja wyjść pod diodę LED

  pinMode(green, OUTPUT);

  pinMode(yellow, OUTPUT);

  pinMode(red, OUTPUT);

  pinMode(button, INPUT_PULLUP); //Przycisk



  digitalWrite(green, LOW);

  digitalWrite(yellow, LOW);

  digitalWrite(red, LOW);



  Serial.begin(9600);//Rozpoczecie komunikacji

  Serial.println( "Witaj w ZGADNIJ LICZBĘ");

  Serial.println("Zakręć potencjonometrem i wciśnij przycisk"); //Wysłanie instrukcji

//To chyba potrzebne może nie, powinno resetować zmienne do wymaganych  

  proby = 3;

  wyslano = false;

  game_on = false;

  LiczbaUserT = "" ;

  LiczbaUserL = 0;

  W_Pot = 0;

  W_P1 = 0;

  W_P2 = 0;

  }



void loop() {



  if(digitalRead(button) == LOW ) { //Jeśli przycisk wciśnięty pozwól rozpocząć grę

    game_on = true;

  }

  if(game_on == true){ //Gra

      if(proby != 0){

        W_Pot = analogRead(A5); //Wartość potencjometru

        W_P1 = W_Pot - 50; //Zmienne +- 50

        W_P2 = W_Pot + 50;

        while(wyslano == false) {

          Serial.println("Podaj Liczbę");

          wyslano = true;

        }  

        while(Serial.available() > 0){ // Nie wiem czy musi być while, ale w jakiejś chwili słabości wstawiłem

          LiczbaUserT = Serial.readStringUntil("\n"); //Użytkownik podaje swoją odpowiedź

          LiczbaUserL = LiczbaUserT.toInt();

          if(W_P2 >LiczbaUserL && LiczbaUserL > W_P1){ //Porównanie czy zgadza się warunek i może wygrać

            digitalWrite(green, HIGH); //Jeśli zgadł wygrywa

            Serial.println("Gratulacje!");            

          }else{ //Jesli nie gra dalej

            proby = proby - 1;

            digitalWrite(yellow, HIGH);

            delay(1000);

            digitalWrite(yellow, LOW);

            wyslano = false;

        }



        }

        }else {

          digitalWrite(red, HIGH); //Przegrana

        }

  }

}

 

Mój pomysł jest taki, użyłem wszystkiego co obecnie było w kursie. Możecie się wypowiedzieć

Edytowano przez Rychu2115
  • Lubię! 1
Link do komentarza
Share on other sites

@Rychu2115 witam na forum 🙂 Dwie kosmetyczne uwagi. Pierwsza: nie wiem czy to kwestia formatowania na forum (raczej nie), ale nie trzeba zostawiać pustej linii po każdej linijce programu. Czasami takie dodatkowe przerwy są potrzebne, ale czasami przesadnie rozciągają program. Druga uwaga kosmetyczna dotyczy komentarzy. Warto je robić w taki sposób, aby opisywały co robi dany kawałek programu, ale od strony praktycznej, a nie programistycznej. Przykładowo:

W_P1 = W_Pot - 50; //Zmienne +- 50
W_P2 = W_Pot + 50;

Powyższy komentarz z Twojego programu nie mówi wiele, bo bez niego też widać, że zmieniasz wartość zmiennych o 50. Wygodniej byłoby to opisać np. takLub:

// Stworzenie zakresu szczesliwej liczby +/- względem potencjometru
W_P1 = W_Pot - 50;
W_P2 = W_Pot + 50;

Lub coś podobnego, chodzi mi tylko o rozróżnienie tego co opisuje komentarz. 

  • Lubię! 1
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.