Skocz do zawartości

Problem z zakresem obrotu enkodera w Trinket 5V i generowanie PWM.


MC2Systems

Pomocna odpowiedź

Jako że Trinket jest mały i w miarę w rozsądnej cenie, chciałem wykonać sterowanie jasnością taśmy LED, czy PowerLEDa.
W tym celu zmontowałem układ jak na rysunku:

1010252069_Zrzutekranu2021-08-11o22_29_03.thumb.png.bcb90a51c45de9a3d6b285b7cab4fb4d.png
Natomiast pojawił się problem z programem. W założeniu obroty w lewo enkodera mają ściemniać, a w prawo rozjaśniać.  Do tego chciałem zaimplementować liniowość zmiany jasności LED, bo jak wiadomo zmiana widocznej jasności nie idzie w parze z wielkością wypełnienia PWM.
Jako że inni już przede mną temat rozkminiali, to na bazie ich osiągnięć próbuję napisać program.
Źródła to: 
Implementacja liniowej zmiany jasności LED<=> PWM  https://gist.github.com/netmaniac/8be83f2e66ae25e949f1
Tu trochę bardziej rozpisana: https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/

Oraz projekt na Trinketa - sterowanie głośnością muzyki w PC za pomocą enkodera i portu USB. 
https://learn.adafruit.com/trinket-usb-volume-knob

Z uwagi na to że nie interesuje mnie sterowanie przez port USB to zmodyfikowałem w/w kod z uwzględnieniem liniowości jasności LED:
https://pastebin.com/BHe8FKth

#include <avr/power.h>
#include <avr/pgmspace.h>

#define PIN_ENCODER_A 0
#define PIN_ENCODER_B 2
#define TRINKET_PINx  PINB
#define PWM_PIN 1
#define krok 9

#define CIELPWM(a) (pgm_read_word_near(CIEL8+a))
const uint8_t CIEL8[] PROGMEM ={ 0,1,2,3,4,5,7,9,12,15,18,22,27,32,38,44,
                                51,58,67,76,86,96,108,120,134,148,163,180,
                                197,216,235,255};

static uint8_t enc_prev_pos = 0;
static uint8_t enc_flags    = 0;
short int stan_pwm =0;

void stepCorrectedPWM(int b) {
  analogWrite(PWM_PIN,CIELPWM(b));
}

void setup()
{
 if(F_CPU == 16000000)
   clock_prescale_set(clock_div_1);
  // set pins as input with internal pull-up resistors enabled
  pinMode(PIN_ENCODER_A, INPUT);
  pinMode(PIN_ENCODER_B, INPUT);
  pinMode(PWM_PIN, OUTPUT);
  digitalWrite(PIN_ENCODER_A, HIGH);
  digitalWrite(PIN_ENCODER_B, HIGH);
  analogWrite(PWM_PIN,0);

  // get an initial reading on the encoder pins
  if (digitalRead(PIN_ENCODER_A) == LOW) {
    enc_prev_pos |= (1 << 0);
  }
  if (digitalRead(PIN_ENCODER_B) == LOW) {
    enc_prev_pos |= (1 << 1);
  }
}

void loop()
{
  int8_t enc_action = 0; // 1 or -1 if moved, sign is direction

  uint8_t enc_cur_pos = 0;
  // read in the encoder state first
  if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_A)) {
    enc_cur_pos |= (1 << 0);
  }
  if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_B)) {
    enc_cur_pos |= (1 << 1);
  }

  // if any rotation at all
  if (enc_cur_pos != enc_prev_pos)
  {
    if (enc_prev_pos == 0x00)
    {
      // this is the first edge
      if (enc_cur_pos == 0x01) {
        enc_flags |= (1 << 0);
      }
      else if (enc_cur_pos == 0x02) {
        enc_flags |= (1 << 1);
      }
    }

    if (enc_cur_pos == 0x03)
    {
      // this is when the encoder is in the middle of a "step"
      enc_flags |= (1 << 4);
    }
    else if (enc_cur_pos == 0x00)
    {
      // this is the final edge
      if (enc_prev_pos == 0x02) {
        enc_flags |= (1 << 2);
      }
      else if (enc_prev_pos == 0x01) {
        enc_flags |= (1 << 3);
      }

      // check the first and last edge
      // or maybe one edge is missing, if missing then require the middle state
      // this will reject bounces and false movements
      if (bit_is_set(enc_flags, 0) && (bit_is_set(enc_flags, 2) || bit_is_set(enc_flags, 4))) {
        enc_action = 1;
      }
      else if (bit_is_set(enc_flags, 2) && (bit_is_set(enc_flags, 0) || bit_is_set(enc_flags, 4))) {
        enc_action = 1;
      }
      else if (bit_is_set(enc_flags, 1) && (bit_is_set(enc_flags, 3) || bit_is_set(enc_flags, 4))) {
        enc_action = -1;
      }
      else if (bit_is_set(enc_flags, 3) && (bit_is_set(enc_flags, 1) || bit_is_set(enc_flags, 4))) {
        enc_action = -1;
      }

      enc_flags = 0; // reset for next time
    }
  }

  enc_prev_pos = enc_cur_pos;

  if (enc_action > 0) {
   // Jaśniej
    stan_pwm = stan_pwm + krok;
 
  }
  if (enc_action < 0) {
   //ciemniej
   stan_pwm = stan_pwm - krok;
 
  }
  if (stan_pwm >= 255)
           {
            stan_pwm=255;
           }
 if (stan_pwm <=1)
         {
            analogWrite(PWM_PIN,0);
         }
 else
         {        
          stepCorrectedPWM(abs(stan_pwm/8));
          }
}

I teraz problem. Kod działa w pewnym zakresie poprawnie. Tzn. gdy zwiększam jasność diody (enkoderem obrót w prawo) jasność wzrasta aż do maksymalnej i dalsze obracanie już jej nie zmienia, ale co ważne "odkręcanie" jasności (obrót w lewo) od razu reaguje zmianą wypełnienia PWM i spadkiem jasności. I ta część działa poprawnie.

Ściemniając diody dochodzimy do wygaszenia i... dalsze obracanie w lewo niby już nic nie robi, ale niestety zakres obrotu domyślam się że nie kończy się na wygaszeniu tylko dalej obracając niejako "nabija się licznik" kroków. Czyli np. wykonując po wygaśnięciu diody jeszcze np. 4 obroty enkodera w lewo, musimy wykonać tyle samo w prawo + troszkę by znów dioda zaczęła jaśnieć.

Moim założeniem jest to by przedział zmian jasności był 0-255 (tak jak w sygnale PWM), a nie jak obecnie również poniżej zera. Po prostu po wygaszeniu diody, niezależnie ile jeszcze obrotów w lewo wykonamy, jeden krok w prawo powinien już włączać diodę i zwiększać jej jasność. Problem niby trywialny, ale nie potrafię znaleźć gdzie tkwi błąd.
Jako mniej eleganckie rozwiązanie, zawsze zostaje reset układu (przycisk w enkoderze), no ale to ostateczność.

Coś doradzicie?

Link do komentarza
Share on other sites

Po odjęciu / dodaniu kroku

if (enc_action > 0) {
   // Jaśniej
    stan_pwm = stan_pwm + krok;
 
  }
  if (enc_action < 0) {
   //ciemniej
   stan_pwm = stan_pwm - krok;
 
  }

Nie limitujesz licznika w lewo.

 if (stan_pwm >= 255)
           {
            stan_pwm=255;
           }

To ogranicza licznik w prawą stronę.

Ale w lewo już nie masz ograniczenia

 if (stan_pwm <=1)
         {
            analogWrite(PWM_PIN,0);
         }

Tutaj tylko resetujesz pin, ale nie ograniczasz limitu

Zmień to ostatnie na:

 if (stan_pwm <=1)
         {
            stan_pwm = 1;
            analogWrite(PWM_PIN,0);
         }

I powinno być dobrze 😉 

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

To może obrazek poglądowy, wycinek schematu z mojego projektu

enc.thumb.JPG.ed60aa8bcd12f144750606b89f3532f6.JPG

Chodzi o r4 i r5 są po to aby kondensatory nie były zwierane bezpośrednio do masy, taki szczególik na pewno nie zaszkodzi

Link do komentarza
Share on other sites

(edytowany)

No i wszystko jasne. Każde dopracowanie projektu się przyda. Zważywszy, że potem płytka ma być u "majfrendów" zamówiona żeby było tak bardziej na poważnie 🙂
Dzięki

Edytowano przez MC2Systems
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.