Pes s modrými očami

Zápisník experimentátora

Dostal som plyšového psíka. Čakal ho osud plyšového zvieratka, ktoré skončí v odpadkovom koši. V tomto článku sa mu pokúsime vdýchnuť nový život pomocou Arduina. Alebo aby som bol presnejší, v tomto článku iba napíšeme algoritmus diabolského blikania očí a až v tom nasledovnom článku mu ich vymeníme.

Algoritmus

Diabolské blikanie očami pozná každý človek. Predstavíte si, ako sa v tme objavia obrovské blikajúce oči. V pravidelných intervaloch svietia alebo zhasnú. Pretože máme k dispozícii PWM, môžeme efekt vylepšiť postupným rozsvietením a zhasnutím LED. A teraz skúsme dodať blikaniu trochu realizmu. Ak nebudú oči blikať úplne synchrónne, bude to pôsobiť vierohodnejšie. Ako živé zviera, ktoré jedno oko privrie trošku skôr.

Program

Základom programu je Timer2. Ten je nastavený na frekvenciu 200 Hz. Na vytvorenie programu som použil AVR Timer CTC Interrupts Calculator. Obsluha prerušenia nastavuje PWM na dvoch LED. V programe som použil deličku frekvencie, ale ak bola nastavená na vyššie číslo, blikanie bolo príliš pomalé a tak som nakoniec nastavil hodnotu jedna.

Popísaný algoritmus realizuje trieda pwmLed. Má tri parametre v konštruktore. Číslo pinu, na ktorom je LED. Počiatočná hodnota PWM a smer animácie. Ak je hodnota PWM rovná 255, otočí sa smer a LED postupne zhasne. To isté sa udeje, ak hodnota PWM bude rovná 0. Otočí sa smer a LED sa postupne rozsvieti. Počiatočná hodnota PWM je fázový posun animácie. Ak chceme obe oči trochu rozladiť, nastavíme hodnotu 0 a 50. To zabezpečí, že LED budú fázovo posunuté približne 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 sa nachádza na serveri GitHub.

 


09.08.2021


Menu