logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Arduino: Zliczanie impulsów enkodera i sterowanie przekaźnikiem

tomek122 25 Sty 2024 19:43 1764 19
  • #1 20928635
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    Witam.

    Z góry zaznaczę, że w arduino to właściwie mój pierwszy program. Próbuję sklecić sobie program który liczy impulsy z enkodera inkrementalnego (500 impulsów na obrót), i co zadaną ilość impulsów (która będzie czasami zmieniana), włączy przekaźnik na określony czas (na początek 500ms a później jak ma też być ten czas regulowany w pewnych widełkach). Mam kod który obsługuje enkoder, oraz wyświetlacz 2x16, do tego 5 przycisków. Ale na razie przyciski są nieobsługiwane, będą potrzebne w przyszłości. Impulsy się liczą i są wyświetlane na lcd. Kręcąc pomału, w miarę wszystko działa. Problem jest jak zaczynam kręcić szybciej, tzn kiedy licznik naliczy 500 impulsów ale przekaźnik jeszcze jest włączony. W tedy punkt jakby ucieka na enkoderze. Problem jest również kiedy zaczynam kręcić enkoderem do tyłu, to przekaźnik jest jakby cały czas załączony. Proszę kogoś mądrego aby ogarnął mi prawidłowe zliczanie i złączanie przekaźnika.

    Oto kod:
    #include <LiquidCrystal.h>
    #include <Bounce2.h>
    
    const byte LcdRS = 4;
    const byte LcdEN = 5;
    const byte LcdD4 = 6;
    const byte LcdD5 = 7;
    const byte LcdD6 = 8;
    const byte LcdD7 = 9;
    const byte LcdKolumny = 16;
    const byte LcdWiersze = 2;
    
    const byte Gora = A0;      //Przycisk Góra  A0
    const byte Dol = A1;       //Przycisk Dół   A1
    const byte Lewo = A2;      //Przycisk Lewo  A2
    const byte Prawo = A3;     //Przycisk Prawo A3
    const byte Ok = A4;        //Przycisk Ok    A4
    
    const byte Przekaznik = 13;
    
    volatile unsigned int temp, counter = 0; //Ta zmienna będzie się zwiększać lub zmniejszać w zależności od obrotów enkodera
    
    
        LiquidCrystal lcd(LcdRS, LcdEN, LcdD4, LcdD5, LcdD6, LcdD7); //Konfiguracja LCD
    
        Bounce debouncer = Bounce(); // Inicjalizacja obiektu Bounce
    
    void setup() {
                       Serial.begin (9600);
    
                    // Po konfiguracji przycisku, ustawienie działania funkcji Bounce :
                       debouncer.attach(Gora);
                       debouncer.attach(Dol);
                       debouncer.attach(Lewo);
                       debouncer.attach(Prawo);
                       debouncer.attach(Ok);
                       debouncer.interval(50); // interwał w ms
      
                    // Konfiguracja przycisków  
                       pinMode(Gora, INPUT_PULLUP);
                       pinMode(Dol, INPUT_PULLUP);
                       pinMode(Lewo, INPUT_PULLUP);
                       pinMode(Prawo, INPUT_PULLUP);
                       pinMode(Ok, INPUT_PULLUP);
                    
                    // Konfiguracja wyjścia przekaznika
                       pinMode(Przekaznik, OUTPUT);
                    
                    //Konfiguracja pinów wejściowych enkodera A i B
                       pinMode(2, INPUT_PULLUP); // Wewnętrzny rezystor podciągający pin wejściowy 2
                       pinMode(3, INPUT_PULLUP); // Wewnętrzny rezystor podciągający pin wejściowy 3
    
                    //Konfiguracja przerwania
                    //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
                      attachInterrupt(0, ai0, RISING);
       
                    //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
                      attachInterrupt(1, ai1, RISING);
    
      
      
      
      
                     lcd.clear();            // Wyczyść ekran
                     lcd.setCursor(2, 0);
                     lcd.print("Licznik 1.0");
    
      
                     delay(2000);            // Poczekaj 2 sekundy
      
      
                     lcd.clear();            // Wyczyść ekran
                     lcd.setCursor(0, 0);
                     lcd.print("Impulsy:");  
      
                  }
       
      void loop() {
    
      // Aktualizacja funkcji Bounce :
          debouncer.update();
      
      // Wyślij wartość licznika
          if( counter != temp ){
                                lcd.setCursor(8, 0);
                                lcd.print("     ");
                                lcd.setCursor(8, 0);
                                lcd.print(counter);
                                Serial.println (counter);
                                temp = counter;
                               }
                             if (counter >= 500) {
                              digitalWrite(Przekaznik, HIGH); // Załącz przekaznik
                              counter = 0; // Zresetuj licznik
                              delay(800);
                              digitalWrite(Przekaznik, LOW); // Wyłącz przekaznik  
                                                      }
                 }
                      
      void ai0() {
                  // ai0 zostaje aktywowane, jeżeli stan pinu cyfrowego nr 2 zmienia się z NISKI na WYSOKI
                  // Sprawdź pin 3, aby określić kierunek
                  if(digitalRead(3)==LOW) {
                  counter++;
                  }else{
                        counter--;
                       }
                 }
       
      void ai1() {
                  // ai0 zostaje aktywowane, jeżeli stan pinu cyfrowego nr 3 zmienia się z NISKI na WYSOKI
                  // Sprawdź z pin2, aby określić kierunek
                  if(digitalRead(2)==LOW) {
                  counter--;
                  }else{
                        counter++;
                       }
                }


    Przypuszczam, że ten fragment kodu jest zły. Ale jak to zrobić inaczej, nie mam pojęcia:
    if (counter >= 500) {
                              digitalWrite(Przekaznik, HIGH); // Załącz przekaznik
                              counter = 0; // Zresetuj licznik
                              delay(800);
                              digitalWrite(Przekaznik, LOW); // Wyłącz przekaznik
  • #2 20928855
    jarekgol
    Poziom 40  
    Posty: 5172
    Pomógł: 644
    Ocena: 1145
    Spróbuj zdefiniować zmienną licznika jako ze znakiem.
  • #3 20928879
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    Jeszcze wpadlem na inną rzecz ktora rozwiarze problem naliczenia wiecej impulsow nim uplynie te zadane 800ms. Zamiast ustawiania czasu, chce zrobic aby przekaźnik zzałączał sie na co 500 impulsów i był załączony przez np 20 impulsów. Teraz noezależnie od szybkosci krecenia enkodera przekaźnik bedzie załaczał się prawidłowo (ze zmiennym czasem trwania ale ze stałą liczbą impulsów). Zostaje tylko kwestia liczenia tych impulsow do tyłu...
  • #4 20928951
    gps79
    Poziom 37  
    Posty: 2209
    Pomógł: 495
    Ocena: 796
    Zliczanie impulsów enkodera to kilka linijek kodu. Wydaje mi się, że próbujesz odkryć koło od nowa.
    Wypada zapoznać się z częścią teoretyczną kodowania kwadraturowego.

    Dekoder najlepiej zrobić na przerwaniu mikrokontrolera. Wtedy masz pewność, że nie ominiesz żadnego impulsu.
    Zobacz program w tym wątku.
    https://www.elektroda.pl/rtvforum/topic4025136.html
  • #5 20928993
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    No ale mam na przerwaniu. Zliczanie działa jak trzeba. Monitor portu pokazuje wszyskie liczby od 0 o 65535.
  • #6 20929007
    jarekgol
    Poziom 40  
    Posty: 5172
    Pomógł: 644
    Ocena: 1145
    No, a jak pójdziesz od zera do tyłu to wskakuje 65k i tu możesz mieć problem. Zmień na "signed". Tam oczywiście będzie problem przy przejściu +/- 32k ale sam sobie odpowiedz co jest bardziej prawdopodobne.
  • #7 20929458
    gps79
    Poziom 37  
    Posty: 2209
    Pomógł: 495
    Ocena: 796
    Wg priorytetów:
    1. Policz/zmierz, czy czas obsługi przerwania jest wystarczający przy prędkości obrotowej enkodera.
    2. Dostęp do zmiennej counter wykonuj w sekcji krytycznej.
    3. Zastosuj typ signed, jak sugeruje @jarekgol .
    4. Zamiast zerować zmienną counter, to zmniejsz jej wartość o 500.
    5. Ja bym zrobił jedną procedurę obsługi przerwania na zmianę, ale to moja estetyka i precyzja.

    Prościej byłoby zapytać o poradę, w stylu "mam enkoder, chcę włączyć przekaźnik w takich a takich warunkach, jak to zrobić efektywnie?".
    Teraz widzimy, że coś próbujesz delay'em, albo dwudziestoma impulsami. O co chodzi?
  • #8 20929585
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    Ok, jeszcze raz. Zapomnijmy teraz o delay, Chce odliczać 500 impulsow i po odliczeniu je wyzerowac (w późniejszym czasie chce te 500 impulsow zrobic zadawane z sekcji menu, powiedzmy od 0 do 5000). Na razie te 500 impulsow ma być stałe. Po zresetowaniu licznika (gdy impulsy sa od 0 do np 50) ma być załączony przekaznik a po tym ma on sie wyłaczyc. Licznik ma dalej liczyc do 500. Ilosc impulsow na razie tez udtawiona na sztywno a w późniejszym czasie tez zrobiona aby ją ustawiać w menu.

    Nie potrzebuje wysylac monitorze danych
    Sa na razie do podgladu.
  • #9 20929630
    gps79
    Poziom 37  
    Posty: 2209
    Pomógł: 495
    Ocena: 796
    Człowiek ma tendencję do ignorowania tego, czego nie rozumie, albo zapamiętać pierwsze i/lub ostatnie zdanie z całego tekstu.
    Widzę, że w odpowiedzi na #7 pominąłeś najważniejszą jej część, czyli punkty 1-4. Warto się na nich skupić, abyś mógł skutecznie rozwiązać problem.
  • #10 20929668
    jarekgol
    Poziom 40  
    Posty: 5172
    Pomógł: 644
    Ocena: 1145
    Czy Ty w ogóle przewidujesz obroty w 2 strony? Bo może mógłbyś badać tylko jeden kanał :)
    Najprostsza wersja jednokierunkowa, to w przerwaniu po osiągnięciu 500 ustawić flagę i przekaźnik i w przerwaniu jeśli flaga i więcej jak 50 wyłączyć przekaźnik, skasować flagę.
    W sumie to można nawet testować stan przekaźnika zamiast flagi, ale dostęp do portu przez arduinowe funkcje jest trochę wydłużony.
  • #11 20929747
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    Wybacz, że nie rozumiem wielu rzeczy. To pierwsze w sumie spotkanie z arduino.

    Tak, potrzebuje dwa kierunki, bo walek do ktorego będzie przylorzony enkoder potrafi (na postoju) minimalnie sie cofnac i jesli nie zmniejsze tego licznika w tedy, to po ruszeniu do przodu, przekaznik bedzie w innym "miejscu" się załaczać.
    Co do wałka do ktorego bedzie przyłożony enkoder, podczas pracy może troche przyspieszać i zwalniać.

    Sprubuje cos potworzyc jak wrócę z pracy i będe prosil o ewentualne dalsze porady.

    Sprawa w praktyce wyglada tak:
    Pod enkoderem przesuwa sie materiał. Nad nim jest silownik z pisakiem, ktory to ma rysowac na tym materiale kreske co powiedzmy 25cm. Kreska o dlugosci 2cm. (O delay juz zapominam bo zdalem sobie sprawe że w twdy przy zmianie predkosci przesuwu, by miala różną długość). Teraz licząc tylko impulsy, gdy materiał przyspieszy, to i tak kreska bedzie co 25cm (500 impulsów) i o długosci 2cm (40 impulsów).
    Kierunek jest ważny i liczenie w dól, gdyż materiał przy zatrzymaniu potrafi lekko się cofnąć a czasami (w granicach +-2mm drgać).

    Dodano po 4 [godziny] 8 [minuty]:

    Wrzucam szkielet programu, właśnie zauważyłem w monitorze portu, że gubi impulsy. Czy to wina programu? Czy samego enkodera? Enkoder to Omron EB2-CWZ6C (500 imp). Robie onkoderem jakieś 2 obroty na sekunde
    Szkieket licznika:
    #include <LiquidCrystal.h>
    
    
    const byte LcdRS = 4;
    const byte LcdEN = 5;
    const byte LcdD4 = 6;
    const byte LcdD5 = 7;
    const byte LcdD6 = 8;
    const byte LcdD7 = 9;
    const byte LcdKolumny = 16;
    const byte LcdWiersze = 2;
    
    
    const byte Przekaznik = 13;
    
    volatile unsigned int temp, licznik = 0; //Ta zmienna będzie się zwiększać lub zmniejszać w zależności od obrotów enkodera
    //word ilosc_impulsow = 1000;
     
    
        LiquidCrystal lcd(LcdRS, LcdEN, LcdD4, LcdD5, LcdD6, LcdD7); //Konfiguracja LCD
    
        
    void setup() {
                        Serial.begin (115200);
                                      
                                    
                        // Konfiguracja wyjścia przekaznika
                       pinMode(Przekaznik, OUTPUT);
                    
                    
                        //Konfiguracja pinów wejściowych enkodera A i B
                       pinMode(2, INPUT_PULLUP); // Wewnętrzny rezystor podciągający pin wejściowy 2
                       pinMode(3, INPUT_PULLUP); // Wewnętrzny rezystor podciągający pin wejściowy 3
    
                        //Konfiguracja przerwania
                        // Zbocze narastające kanału A z enkodera aktywuje ai0(). Przerwanie 0 w arduino nano jest na pinie 2.
                      attachInterrupt(0, ai0, RISING);
       
                        // Zbocze narastające kanału B z enkodera aktywuje ai1(). Przerwanie 1 w arduino nano jest na pinie 3.
                      attachInterrupt(1, ai1, RISING);
    
        
                     lcd.clear();            // Wyczyść ekran
                     lcd.setCursor(2, 0);
                     lcd.print("Licznik 1.0");
                     
                     delay(2000);            // Poczekaj 2 sekundy
                       
                     lcd.clear();            // Wyczyść ekran
                     lcd.setCursor(0, 0);
                     lcd.print("Impulsy:0");  
      
                  }
       
      void loop() {
    
        
       //Wyślij wartość licznika
          if( licznik != temp ){
                                lcd.setCursor(8, 0);
                                lcd.print("     ");
                                lcd.setCursor(8, 0);
                                lcd.print(licznik);
                                Serial.println (licznik);
                                temp = licznik;
                               }
                             
                             
                  }             
                      
      void ai0() {
                  
                    // ai0 zostaje aktywowane, jeżeli stan pinu cyfrowego nr 2 zmienia się z NISKI na WYSOKI
                    // Sprawdź pin 3, aby określić kierunek
                  if(digitalRead(3)==LOW) {
                  licznik++;
                  }else{
                        licznik--;
                       }
                 }
       
      void ai1() {
                     // ai0 zostaje aktywowane, jeżeli stan pinu cyfrowego nr 3 zmienia się z NISKI na WYSOKI
                    // Sprawdź z pin2, aby określić kierunek
                  if(digitalRead(2)==LOW) {
                  licznik--;
                  }else{
                        licznik++;
                       }
                }


    Dodano po 1 [godziny] 18 [minuty]:

    W miare działa tak jak bym chciał. Zadaje liczbe impulsów po którym ma być reset licznika oraz liczbe impulsów przez ile jest włączony przekaznik. Jednak gubią się impulsy. Poproszę rzucić okiem i sprawdzić dlaczego one mogą uciekać.
    Kod:
    #include <LiquidCrystal.h>
    
    
    const byte LcdRS = 4;
    const byte LcdEN = 5;
    const byte LcdD4 = 6;  
    const byte LcdD5 = 7;
    const byte LcdD6 = 8;
    const byte LcdD7 = 9;
    const byte LcdKolumny = 16;
    const byte LcdWiersze = 2;
    
    const byte Przekaznik = 13;
    
    volatile unsigned int temp, licznik = 0; //Ta zmienna będzie się zwiększać lub zmniejszać w zależności od obrotów enkodera
    //volatile int temp, licznik = 0; //Ta zmienna będzie się zwiększać lub zmniejszać w zależności od obrotów enkodera
    word ilosc_impulsow = 1000;
    byte dl_przekaznika = 200;
    
        LiquidCrystal lcd(LcdRS, LcdEN, LcdD4, LcdD5, LcdD6, LcdD7); //Konfiguracja LCD
    
        
    void setup() {
                        Serial.begin (115200);
                                      
                                    
                        // Konfiguracja wyjścia przekaznika
                       pinMode(Przekaznik, OUTPUT);
                    
                    
                        //Konfiguracja pinów wejściowych enkodera A i B
                       pinMode(2, INPUT_PULLUP); // Wewnętrzny rezystor podciągający pin wejściowy 2
                       pinMode(3, INPUT_PULLUP); // Wewnętrzny rezystor podciągający pin wejściowy 3
    
                        //Konfiguracja przerwania
                        // Zbocze narastające kanału A z enkodera aktywuje ai0(). Przerwanie 0 w arduino nano jest na pinie 2.
                      attachInterrupt(0, ai0, RISING);
       
                        // Zbocze narastające kanału B z enkodera aktywuje ai1(). Przerwanie 1 w arduino nano jest na pinie 3.
                      attachInterrupt(1, ai1, RISING);
    
        
                     lcd.clear();            // Wyczyść ekran
                     lcd.setCursor(2, 0);
                     lcd.print("Licznik 1.0");
                     
                     delay(2000);            // Poczekaj 2 sekundy
                       
                     lcd.clear();            // Wyczyść ekran
                     lcd.setCursor(0, 0);
                     lcd.print("Impulsy:0");  
      
                  }
       
      void loop() {
    
        
       //Wyślij wartość licznika
          if( licznik != temp ){
                                lcd.setCursor(8, 0);
                                lcd.print("     ");
                                lcd.setCursor(8, 0);
                                lcd.print(licznik);
                                Serial.println (licznik);
                                temp = licznik;
                               }
                               if (licznik >= ilosc_impulsow) {
                                licznik = 1;
                               }
                             if (licznik <= 0) {
                              licznik = ilosc_impulsow - 1;
                             }
                             if (licznik >= 0 && licznik <= dl_przekaznika) {
                              digitalWrite(Przekaznik, HIGH);
                             } else {
                              digitalWrite(Przekaznik, LOW);
                             }
                             
                             
                  }             
                      
      void ai0() {
                  
                    // ai0 zostaje aktywowane, jeżeli stan pinu cyfrowego nr 2 zmienia się z NISKI na WYSOKI
                    // Sprawdź pin 3, aby określić kierunek
                  if(digitalRead(3)==LOW) {
                  licznik++;
                  }else{
                        licznik--;
                       }
                 }
       
      void ai1() {
                     // ai0 zostaje aktywowane, jeżeli stan pinu cyfrowego nr 3 zmienia się z NISKI na WYSOKI
                    // Sprawdź z pin2, aby określić kierunek
                  if(digitalRead(2)==LOW) {
                  licznik--;
                  }else{
                        licznik++;
                       }
                }
  • #12 20930436
    tmf
    VIP Zasłużony dla elektroda
    Posty: 14318
    Pomógł: 2090
    Ocena: 2205
    Źle obsługujesz enkoder. Poczytaj o enkoderze kwadraturowym - enkodery nie działają tak jak założyłeś, że na jednym pinie masz impulsy jak kręcisz w jedną stronę, a na drugim, jeśli kręcisz w przeciwną. Używają najczęściej kodu Gray’a - więc zacznij od poprawnej obsługi enkodera.
    Druga sprawa - wewnętrzne podciąganie zapewnione na portach ma zbyt dużą wartość, raczej warto dodać zewnętrzne rezystory rzędu 4k7 max.
    Kolejny błąd wynika ze sposobu dostępu do zmiennych temp i licznik. Zapis:
    if( licznik != temp )
    jest zupełnie błędny - ponieważ zmienne te są modyfikowane asynchronicznie w przerwaniach, więc musisz zapewnić do nich atomowy dostęp - najprościej ująć to w sekcje krytyczne. Podobnie zapisy:
    if (licznik >= 0 && licznik <= dl_przekaznika)
    są błędne, z tych samych powodów. Zastanów się, co się stanie, jeśli przerwanie wystąpi w trakcie wykonywania takiego bloku instrukcji...
  • #13 20930592
    jarekgol
    Poziom 40  
    Posty: 5172
    Pomógł: 644
    Ocena: 1145
    Kod: Arduino
    Zaloguj się, aby zobaczyć kod

    Zmień tu na signed lub wyrzuć unsigned. Czy wiesz co się dzieje (w pamięci procesora) jak od 0 odejmiesz 1 ?

    Dla uproszczenia możesz wyłączyć jedno przerwanie. Żeby sprawdzić obsługę enkodera należy sobie gdzieś postawić punkty na oście i obudowie pokręcić pare pełnych obrotów, w różne strony i zobaczyć czy wartości się zgadzają.
    500 imp / obr * 2 obr /s to jest coś z czym AVR sobie radzi bez problemu.

    Wyjaśniając częściowo co kolega pisał wyżej, zmienna int jest 16 bitowa, a AVR 8-bitowy, porównanie 2 liczb 16bit musi robić po kawałku, powiedzmy jako 4 bajty, jak porówna górna a zmienią się w tym czasie dolne lub na odwrót, to robi się problem. Zresztą nawet przy porównaniu 2 bajtów, gdzie któryś jest modyfikowany w przerwaniu może wystąpić taki kłopot.

    Wyświetlania (czy na lcd czy na serial) też nie musisz na razie oszczędzać (wywal ten temp!=licznik). Wystarczy obsługe przekaźnika dopisać w przerwaniu, żeby nie był zależny od czasu "reakcji" lcd czy seriala.
    A skoro wykrywasz zmiany w przerwaniu to można tam ustawić flagę (zmienną bool) i wtedy wyświetlać w głównej pętli i ją kasować.
  • #14 20930699
    tmf
    VIP Zasłużony dla elektroda
    Posty: 14318
    Pomógł: 2090
    Ocena: 2205
    jarekgol napisał:
    skoro wykrywasz zmiany w przerwaniu to można tam ustawić flagę (zmienną bool) i wtedy wyświetlać w głównej pętli i ją kasować.

    Prawdę mówiąc obsługa enkodera w przerwaniu od pinu też nie jest najlepszym pomysłem - chyba, że to enkoder optyczny. Lepiej użyć przerwania timera.
  • #15 20930758
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    Jest to taki enkoder, od 5 dob24V
    omron e6b2-cwz6c 500
    Załączniki:
    • q085_e6b2-c_incremental_rotary_encoder_40_mm_datasheet_en-2.pdf (722.51 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #16 20930807
    tmf
    VIP Zasłużony dla elektroda
    Posty: 14318
    Pomógł: 2090
    Ocena: 2205
    @tomek122 Czyli masz wyjścia typu OC - podciągnij je rezystorej do Vcc. Jak pisałem te wbudowane, przy szybszym kręceniu niekoniecznie wystarczą. No i mają wyjście w kodzie Gray'a, więc twoje dekodowanie nie działa poprawnie. Także zaczniej od poprawnego dekodowania impulsów z enkodera.
  • #17 20930840
    jarekgol
    Poziom 40  
    Posty: 5172
    Pomógł: 644
    Ocena: 1145
    tmf napisał:
    Lepiej użyć przerwania timera.

    W sensie próbkowania na przerwaniu od timera aby pozbyć się drgania styków, czy podłaczyć do sprzętowego licznika (co raczej w AVR Arduino nie pyknie)?
  • #18 20930917
    tmf
    VIP Zasłużony dla elektroda
    Posty: 14318
    Pomógł: 2090
    Ocena: 2205
    jarekgol napisał:
    W sensie próbkowania na przerwaniu od timera aby pozbyć się drgania styków, czy podłaczyć do sprzętowego licznika (co raczej w AVR Arduino nie pyknie)?

    To pierwsze. Aczkolwiek w tym przypadku nie mamy drgań, więc jest ok. Sprzętowy licznik byłby ok, o ile ma enkoder kwadraturowy. W XMEGA to jest, więc tam można zrobić całość sprzętowo.
  • #19 20931322
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    Panowie, na szybko zapytałme chatGPT, o kod do obslugi enkodera i zapalenie diody na 1 sekunde ale żeby nie gubic liczenia impulsow. Czy taki kod jest prawidlowy:

    // Deklaracje zmiennych
    volatile int impulsy = 0;  // Licznik impulsów
    const int enkoderPinA = 2; // Pin A enkodera podłączony do pinu 2 na Arduino Nano
    const int enkoderPinB = 3; // Pin B enkodera podłączony do pinu 3 na Arduino Nano
    const int diodaPin = 13;   // Pin diody LED
    
    void setup() {
      Serial.begin(9600);     // Inicjalizacja komunikacji szeregowej
      pinMode(enkoderPinA, INPUT_PULLUP);
      pinMode(enkoderPinB, INPUT_PULLUP);
      pinMode(diodaPin, OUTPUT);  // Ustawienie pinu diody jako wyjście
    
      // Konfiguracja przerwań timera
      cli();           // Wyłączenie przerwań
      TCCR1A = 0;      // Wyzerowanie rejestrów
      TCCR1B = 0;
    
      TCNT1 = 0;       // Zerowanie licznika timera
      TCCR1B |= (1 << CS11) | (1 << CS10); // Ustawienie preskalera na 64
      TIMSK1 |= (1 << TOIE1);  // Włączenie przerwania overflow timera
      sei();           // Włączenie przerwań
    }
    
    void loop() {
      // Zapalenie diody przez 1 sekundę
      digitalWrite(diodaPin, HIGH);
      delay(1000);
      digitalWrite(diodaPin, LOW);
    
      // Kod obsługujący enkoder w pętli głównej
      // (dodatkowe zadania, które mogą być wykonywane bez utraty impulsów)
      // ...
    
      // Wypisanie aktualnej liczby impulsów na monitorze portu szeregowego
      Serial.println(impulsy);
    }
    
    // Obsługa przerwania od timera - liczenie impulsów enkodera
    ISR(TIMER1_OVF_vect) {
      int stanA = digitalRead(enkoderPinA);
      int stanB = digitalRead(enkoderPinB);
    
      if (stanA == LOW && stanB == HIGH) {
        impulsy++;
      } else if (stanA == HIGH && stanB == LOW) {
        impulsy--;
      }
    }
    
  • #20 20946275
    tomek122
    Poziom 22  
    Posty: 912
    Pomógł: 33
    Ocena: 234
    Okazalo sie, że nie gubi impulsów. Wydawalo mi sie, że gubi, bo patrzyłem na to co wypluwa monitor portu. W koncu zaznaczyłem na kole enkodera kreske i zrobiłem do tego wskaznik z drutu. Okazalo sie że pracuje hak trzeba.

    Teraz zacząłem "bawic" sie "drugą wersją" używając biblioteko enkoder.h Dziala jak należy, mam 2000 impulsow na obrót ale to wynika z kodu greya

    Teraz chcialbym stworzyć proste menu w ktorym bedę mógł zmienić obwód koła oraz ilośc impulsów z enkodera. Ale chcialbym to zrobić nie na przyciskach ale na enkoderze z adruino (taki obrotowy z przyciskiem). Może ktos podpowiedziec jak się teraz do tego zabrac? W koncu to by były teraz 2 enkodery. Ale w tym od menu nie potrzebuje miec idealnie wszystkie impulsy.

Podsumowanie tematu

✨ Użytkownik stara się stworzyć program na Arduino do zliczania impulsów z enkodera inkrementalnego oraz sterowania przekaźnikiem. Problemy pojawiają się przy szybkich obrotach enkodera, gdzie przekaźnik nie wyłącza się prawidłowo, a także przy obrotach w przeciwną stronę. Uczestnicy dyskusji sugerują użycie zmiennych ze znakiem, poprawne dekodowanie impulsów z enkodera kwadraturowego oraz zastosowanie przerwań mikrokontrolera dla dokładniejszego zliczania. Użytkownik testuje różne podejścia, w tym użycie biblioteki enkoder.h, i planuje stworzenie menu do zmiany parametrów pracy enkodera.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA