Pes s modrýma očima

Zápisník experimentátora

Dostal jsem plyšového pejska. Čekal ho osud plyšového zvířátka, které skončí v odpadkovém koši. V tomto článku se mu pokusíme vdechnout nový život pomocí Arduina. Nebo abych byl přesnější, v tomto článku pouze napíšeme algoritmus ďábelského blikání očí a až v tom následujícím článku mu je vyměníme.

Algoritmus

Ďábelské blikání očima zná každý člověk. Představíte si, jak se ve tmě objeví obrovské blikající oči. V pravidelných intervalech svítí nebo zhasnou. Protože máme k dispozici PWM, můžeme efekt vylepšit postupným rozsvícením a zhasnutím LED. A teď zkusme dodat blikání trochu realismu. Pokud nebudou oči blikat zcela synchronně, bude to působit věrohodněji. Jako živé zvíře, které jedno oko přivře trošku dříve.

Program

Základem programu je Timer2. Ten je nastaven na frekvenci 200 Hz. K vytvoření programu jsem použil AVR Timer CTC Interrupts Calculator. Obsluha přerušení nastavuje PWM na dvou LED. V programu jsem použil děličku frekvence, ale pokud byla nastavena na vyšší číslo, blikání bylo příliš pomalé a tak jsem nakonec nastavil hodnotu jedna.

Popsaný algoritmus realizuje třída pwmLed. Má tři parametry v konstruktoru. Číslo pinu, na kterém je LED. Počáteční hodnota PWM a směr animace. Pokud je hodnota PWM rovná 255, otočí se směr a LED postupně zhasne. Totéž se stane, pokud hodnota PWM bude rovna 0. Otočí se směr a LED se postupně rozsvítí. Počáteční hodnota PWM je fázový posun animace. Pokud chceme obě oči trochu rozladit, nastavíme hodnotu 0 a 50. To zajistí, že LED budou fázově posunuté přibližně o 500 ms.

void setupTimer2() {
  noInterrupts();
  // Clear registers
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2 = 0;

  // 200.32051282051282 Hz (16000000/((77+1)*1024))
  OCR2A = 77;
  // CTC
  TCCR2A |= (1 << WGM21);
  // Prescaler 1024
  TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);
  // Output Compare Match A Interrupt Enable
  TIMSK2 |= (1 << OCIE2A);
  interrupts();
}

void setup() {
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  setupTimer2();
}

class pwmLed {
    int led;
    int pwm;
    int direction;

  public:
    pwmLed(int _led, int _pwm = 0, int _direction = 1)
      : led(_led), pwm(_pwm), direction(_direction)
    {}

    void Next() {
      pwm += direction;
      analogWrite(led, pwm);
      if (pwm == 255)
        direction = -1;
      if (pwm == 0)
        direction = 1;
    }
};

// eyes with phase shift
pwmLed pwm1(9, 0, 1);
pwmLed pwm2(10, 50, 1);

ISR(TIMER2_COMPA_vect) {
  static int divider = 0;
  if (divider == 0) {
    pwm1.Next();
    pwm2.Next();
  }
  divider++;
  divider %= 1;
}

void loop() {
}

Zdrojový kód

Zdrojový kód programu se nachází na serveru GitHub.

 



Video



10.08.2021


Menu