Skocz do zawartości

Sterowanie diod za pomocą pilota


digitalread

Pomocna odpowiedź

Witam chciałbym zbudować sześcian z diod LED, którymi będę sterował za pomocą pilota. Problem tkwi w tym, że jestem początkującym programistą i nie wiem jak napisać kod aby wciśniecie przycisku na pilocie oznaczało logiczne 1 i żeby program zapamiętywał ten stan. Chodzi o to żeby nie trzymać ciągle wciśniętego przycisku tylko żeby raz go wcisnąć. Również chce zrobić tak, żeby za pomocą guzików(przycisków) w pilocie przełączać różne tryby świecenia diod.  Napisałem wstępnie 3 testowe funkcje które mają być jednymi z trybów świecenia diodami. Funkcja na pętli for działa teoretycznie prawidłowo, ale nie wiem jak ją zatrzymać tak aby przełączyć guzikiem z pilota na inny tryb. Funkcja dioda1 działa poprawnie tylko, że trzeba ciągle trzymać przycisk na pilocie. Wygląd kodu: 

#define TSOP_PIN 7
#define diodyLED 11
#include <RC5.h>
RC5 rc5(TSOP_PIN); //Informacja o podłączeniu odbiornika TSOP
 int wypelnienie=0;
//Zmienne dla RC5
byte address; 
byte command;
byte toggle;


void setup() {                
   pinMode(TSOP_PIN ,INPUT); //odbiornik podczerwieni
  pinMode(diodyLED, OUTPUT); //diody LED
  digitalWrite(diodyLED, LOW);
}
 
void loop() {
  //Jeśli odebrano komendę
  if (rc5.read(&toggle, &address, &command))
  {
 switch(command){
  case 2:
  dioda(255,50,0,999); //wlacz funkcje dioda i potworz ją 999 razy
  break;
  case 3:
  dioda1(0,255,5,50);
  break;
  case 1:
  zamigajLED(250);
  break;
 }
  }
}

void zamigajLED(int czas) {
 analogWrite(diodyLED, HIGH);
  delay(czas);
  analogWrite(diodyLED, LOW);
  delay(czas); 

}

void dioda(int ile, int czas,int ile2,int ile3){ //funkcja z pętlą nieskonczoną
  if(digitalRead(2)==LOW){
  for (int j=0; j<=ile3; j++){
  for (int i=0; i<=ile; i++){
    analogWrite(diodyLED, i);
    delay(czas);
  }
  for (int i =ile; i>=ile2; i--){
    analogWrite(diodyLED, i);
    delay(czas);
  }
}
  }
}
void dioda1(int wyplelnienie, int ilewypelnienie, int zmiana, int czas){
if(wypelnienie<ilewypelnienie){
        analogWrite(diodyLED, wypelnienie);
        wypelnienie+= zmiana;
      }
      if(wypelnienie==ilewypelnienie){
        while(wypelnienie!=0){
        analogWrite(diodyLED, wypelnienie);
        wypelnienie=wypelnienie-zmiana;
        delay(czas);
      }
      }
      delay(czas);
     }

Próbowałem napisać kod, który będzie zapamiętywał stan przycisku, ale nie wiem jak go połączyć z funkcją dioda1.

 

boolean stan = false; // aktualny stan zaświecenia diody
int  TSOP_PIN = 10; //pin do odczytu stanu przycisku
int diodyLED = 11;   //pin do obsługi diody

void setup() {

pinMode(diodyLED OUTPUT); //Dioda jako wyjście
pinMode(TSOP_PIN, INPUT_PULLUP); //Przycisk jako wejście
digitalWrite(diodyLED, HIGH); //Wyłączenie diody
}

void loop() {

  if (digitalRead(TSOP_PIN) == LOW) { //jak odwołać się do guzika na pilocie?
     delay(20); //20ms na obsługę drgań styków
     stan = !stan; //ustawienie przeciwnego stanu diody
     if (stan == true){
       digitalWrite(diodyLED, stan);
     }  else {
       digitalWrite(diodyLED, stan);
     }
     while (digitalRead(TSOP_PIN) == LOW); //czekamy tak długo, jak długo wciśnięty jest przycisk
     delay(20); //20ms na obsługę drgań styków
     }
}

Nie mam pojęcia jak mam odnieść się w instrukcji warunkowej do dowolnego przycisku(guzika) na pilocie lub czy ewentualnie da się zatrzymać funkcje dioda na pętli for która powtarza się 999razy czy trzeba czekać aż się ona 'skończy'. Mógłby ktoś pomoc z napisaniem kodu? 

Dodam jeszcze, że w kursie budowy robotów napisana funkcja wywołana w instrukcji warunkowej switch-case za pomocą przycisku w pilocie działa po jednym wciśnięciu i nie trzeba trzymać przycisku aby silnik się kręcił. Wygląd kodu:

void leftMotor(int V) {
  if (V > 0) { //Jesli predkosc jest wieksza od 0 (dodatnia)
    V = map(V, 0, 100, 0, PWM_MAX);
    digitalWrite(L_DIR, 0); //Kierunek: do przodu
    analogWrite(L_PWM, V); //Ustawienie predkosci 
  } else {
    V = abs(V); //Funkcja abs() zwroci wartosc V  bez znaku
    V = map(V, 0, 100, 0, PWM_MAX);
    digitalWrite(L_DIR, 1); //Kierunek: do tyłu
    analogWrite(L_PWM, V); //Ustawienie predkosci    
  }
}

Proszę o pomoc. 

Link do komentarza
Share on other sites

Może coś w tym stylu:

int tryb;	// aktualny tryb

void loop() {
  
  if(rc5.read(&toggle, &address, &command)) {
    switch(command) {
        // tutaj zależnie od tego co dostaniesz zmieniasz (bądz nie) zmienną tryb
    }
  }
  
  switch(tryb) {
      // tutaj zależnie od zmiennej tryb dajesz funkcje odpowiedzialne za dane tryby, dioda(), dioda1() itp, ale bez powtórzeń
  }
}

Jeśli nie odebrano komendy, zmienna tryb się nie zmienia i program w następnym switchu będzie kontynuował ten tryb który jest ustawiony. Nie masz powtórzeń wewnątrz funkcji, rolę powtórzeń pełni loop(), więc w trakcie możesz zmienić tryb.

Nie wiem czy o to ci chodziło, jak nie spróbuj opisać trochę bardziej szczegółowo co to ma robić, w sensie jaki efekt ma być (fizycznie, nie program).

Link do komentarza
Share on other sites

To ma być sześcian ozdobny z diod LED 4 warstwowy. Każdą warstwę chcę oddzielnie podłączyć do pinów atmegi. Korzystając z biblioteki rc5 na instrukcji warunkowej switch case chce aby po wciśnięciu odpowiedniego przycisku na pilocie diody w określony sposób się zapalały.Oczywiście jeszcze do atmegi zastanie podłączony odbiornik podczerwieni  TSOP2236. Problem tkwi tylko w tym, żeby dany tryb świecenia diod działał gdy raz wcisnę odpowiedni przycisk na pilocie. Napisałem funkcje 'void dioda1' i działa ona tylko wtedy gdy trzymam wciśnięty przycisk na pilocie. Napisałem funkcje kolejną funkcje która robi dokładnie to samo tylko z użyciem pętli for. Funkcja 'void dioda' wykona sie załóżmy 20 razy. Po wybraniu odpowiedniego przycisku na pilocie dla tej funkcji diody będą świeciły według napisanej funkcji i nie będę musiał wtedy trzymać przycisku na pilocie aby diody świeciły. Problem tkwi w tym, że np. po 10 powtórzeniach chciałbym zmienić tryb świecenia, ale muszę poczekać aż diody zaświecą się te 20razy. Przy tej funkcji nie wiem w jaki sposób ją zatrzymać, bo ogółnie funkcja działa tak jak chciałem czyli nie musze trzymać przycisku na pilocie aby diody świeciły, ale nie wiem jak zatrzymać tą funkcję żeby przełączyć na kolejny tryb świecenia diod.. Myślałem żeby użyć przerwania, ale za bardzo nie wiem jak. Myślę, że najłatwiej jest zmodyfikować funkcję 'void dioda1' tak aby po wciśnięciu i puszczeniu przycisku na pilocie diody świeciły według napisanej funkcji. Myślałem, żeby do tej funkcji dodać może funkcje boolean i do tego zmienną 'stan' ale nie wiem jak to razem ze sobą połączyć.

Link do komentarza
Share on other sites

Trochę się wczytałem w te podczerwienie i wygląda na to że faktycznie będzie trochę kombinowania. Kod który ci podałem nie będzie działał z twoimi funkcjami. Czyli źle ci podałem 😀.

Zamysł biblioteki RC5 jest chyba taki że wywołujesz rc5.read() jeden po drugim aż przyjdzie komenda.  Wtedy robisz co chcesz na chwile przerywając "czuwanie" i znów zaczynasz wywoływać rc5.read() w pętli. I to musi być wywoływane jeden po drugim bo on ciągle obserwuje ten pin od czujnika. Sygnał to ileś zmian tego pinu, które on musi "zauważyć". Więc kod co ci proponowałem nie będzie działał z twoimi funkcjami bo masz tam delay() co chwile, czyli atmega sobie czeka, pin sie zmienia, a biblioteka tego nie widzi.

Możesz spróbować zrobić tak na razie:

void loop() {
  
  rc5.read(&toggle, &address, &command)
    
  switch(command) {
	case 2:
      digitalWrite(diodyLED, HIGH);
      break;
      case 3:
      digitalWrite(diodyLED, LOW);
      break;
  }
}

Powinien włączać i wyłączać diody na 2 przyciski (z pamięcią). Jak będzie działać znaczy że tak krótki odstęp między rc5.read() mu nie przeszkadza, można wtedy kombinować jak to dalej robić.

Edytowano przez moderin
  • Lubię! 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

Twój kod działa tak jak chciałem, czyli muszę zrobić tak, że jednym przyciskiem włączam funkcje a innym przyciskiem ją wyłączam? Bo jak teraz wcisnąłem 2 na pilocie to dioda się świeci i nie muszę trzymać przycisku a po wciśnięciu przycisku 3 dioda gaśnie. Więc w analogiczny sposób powinno zadziałać wywoływanie funkcji jednym przyciskiem a drugim jej wyłączanie. 

Link do komentarza
Share on other sites

Gdybyś chciał zrobić ten program bardziej profesjonalnie powiedzmy, powinieneś mieć całą transmisję na przerwaniach. Czyli atmega większość czasu zajmuje się sterowaniem diodami, a gdy odbiornik IR zmieni stan na wyjściu (wejściu atmegi), twój mikro-kontroler na chwilę przerywa sterowanie diodami, liczy co trzeba i znów wraca do sterowania diodami. Gdybyś to zrobił w ten sposób, wszystko by działało idealnie. Twoje funkcje mogłyby mieć dalay() w środku. Generalnie kod wyglądałby tak:

volatile int tryb;

// [Kod przerwań]

void loop() {
  switch(tryb) {
    case 1:
      // [funkcja trybu 1]
      break;
    case 2:
      // [funkcja trybu 2]
      break;
      
      // itd.
  }
}

Kod wykonuje funkcje danego trybu. Jeśli wciśniesz przycisk na pilocie przerwana zmienią zmienną tryb i atmega zacznie wykonywać funkcje innego trybu.

Problem w tym że wtedy musiałbyś sam to liczyć w sensie biblioteki nie wykorzystasz. Robiąc to na bibliotece musisz zadbać żeby co chwila wywoływać rc5.read(), bo on nie ma przerwań tylko ciągle sprawdza czy pin zmienił stan. Na maksa nie efektywne. Ale za to proste. To co ci proponowałem w poprzednim poście (z zapalaniem i gaszeniem) to miał być test czy biblioteka nadal będzie działać jesli pomiędzy kolejnymi wywołaniami rc5.read() coś zrobisz - czyli minie pewien czas. Wygląda na to że pomiędzy nimi możesz coś zrobić - jeśli zajmie mało czasu. digitalWrite() to jest chwila, delay() to są wieki. Więc:

void loop() {
  
  rc5.read(&toggle, &address, &command)
    
  switch(command) {
    case 1:
      // tu możesz wstawić funkcje odpowiedzialną za tryb 1
    break;
    
	case 2:
      // tu możesz wstawić funkcje odpowiedzialną za tryb 2
      break;
    
     case 3:
      // tu możesz wstawić funkcje odpowiedzialną za tryb 3
      break;
  }
}

ALE: Te funkcje nie mogą zajmować dużo czasu. Jeśli zajmą go za dużo, pin odbiornika może zmienić stan, a atmega tego nie zauważy - bo wykonuje wciąż twoją funkcje a nie rc5.read(). I w ten sposób zdekoduje sygnał źle, bądz nie zdekoduje. Więc: żadnych delay-ów! Jeśli chcesz żeby funkcja na przykład ściemniała diody płynnie, nie rób pętli z delay(), tylko spraw by funkcja za każdym wykonaniem wywoływała analogWrite z miejszą wartością.

To nie jest specjalnie profesjonalne podejście - w sensie wstawianie czegoś między rc5.read(). Ale nie mam innego pomysłu jak to zrobić bez przerwań. Jeśli twoje funkcje będą dostatecznie szybkie, powinno działać.

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.