電音の工場ブログ

趣味の電子工作を中心としたブログです.音モノの工作が多いです.

avr-gcc で工作(その6)

avr-gcc で工作(その6)

もののついでにさらに色気を出して、LEDがジワっと点灯、ジワっと消灯を繰り返すプログラムを書いてみました。今回ターゲットとしている工作にはおそらく採用しない*1のですが、先日 (id:Chuck:20040910#p1) 買ったフルカラーLEDに適用してみようかなと。

PWMでやっているわけですが、timer2 でジワっと明るさ定数 _pwm の更新を行い、timer0 でその値を PWMでポートに出力しています。timer0 は クロック8MHz を prescale 1 で、256カウントでオーバーフローして割り込みに飛んできます*2。それを64を1周期として出力しています*3

ジワっと明るさ定数 _pwm の更新はもっとずっとゆっくりです。8MHzを1024でprescaleして256カウントでオーバーフローして割り込みに飛んでは来るものの、さらに cnt (初期値 _COUNT) を数えないと値更新にたどり着きません。この値は当初直線的に変化させていたのですが、今回繋いだLEDで今ひとつに見えた*4ので、2次関数的に変化させるようにしてみました。が、もうひとこえ欲しいところです。

いかん、寄り道していないで、本題に戻らねば…

以下ソースコード

/*
  PORTA LED fade in/out
*/
#include 
#include 
#include 
#include 

#define _COUNTER 2

enum { UP, DOWN };

volatile uint8_t cnt = _COUNTER;
volatile uint8_t _direction = UP;
volatile uint16_t _pwm = 0;
volatile uint8_t _pwm_work = 0;
volatile uint8_t _pwm_cnt = 0;

/* timer0 for PWM, timer2 for fade in/out */

SIGNAL(SIG_OVERFLOW0)
{
  if (++_pwm_cnt > 64)
    _pwm_cnt = 0;
  if (_pwm_cnt < (uint8_t)(_pwm>>5))
    sbi(PORTA, PA0);
  else
    cbi(PORTA, PA0);
}

INTERRUPT(SIG_OVERFLOW2)
{
  if (!(--cnt)) {
    cnt = _COUNTER;
    switch (_direction) {
    case UP:
      _pwm += _pwm_work++;
      if (_pwm_work > 64)
        _direction = DOWN;
      break;
    case DOWN:
      _pwm -= --_pwm_work;
      if (!(_pwm_work))
        _direction = UP;
      break;
    }
  }
}

void ioinit (void)
{
  /* tmr0 is prescaled by 1, tmr2 by 1024 */
  TCCR0 = _BV (CS00);
  TCCR2 = _BV (CS22) | _BV (CS21) | _BV (CS20);
  /* enable PA0 as output */
  DDRA = _BV (PA0);
  timer_enable_int (_BV (TOIE0) | _BV (TOIE2));
  /* enable interrupts */
  sei ();
}

int main(void)
{
  ioinit();
  for (;;) ;
  return 0;
}

*1:いや、オープニングで 7セグメントLEDがジワっとフェードインだ、とか無い話ではなさそうな…

*2:Q1: 周波数はいくつでしょう?

*3:Q2: 周波数はいくつでしょう?

*4:使用するLEDによって見え方は違うはず。