ソフトウエア制御による8LEDの点滅
ハードウエアのPWMでは、タイマ0のAとB、タイマ1のAとBの4個のPWMを使えると思うのですが(検証していません)PORTBに接続した8個のLEDを蛍のように次第に明るく次第に暗く点滅し、かつ8個の位相が少しずつずれたものを考えました。
このプログラムは以前に考えたもので、今見直してもすぐには理解できないほど忘れ去っています。作ったときのままリストを挙げておきます。
回路は単純にポートBに電流制限抵抗を付けたLEDを接続しているだけです。
/**********************************************************************************
spwm1.c ソフトウエアによるPWMコントロール 050811 im
ATtiny2313の8つのポートをソフトウエアでpwm制御する。クロックは内蔵RC8MHz。
タイマで約0.03ミリ秒毎に割込をかける(TCNT0=252の時)。
割込が発生したらフラグを立てメインルーチンに伝える。これは割込ルーチンで処理を続ける
には多くのグローバル変数が必要だから、メインで処理することにしたため。
この割込により変数cntで100回の割込処理を繰り返す。この100回で1クールの発光をする。
デューティ1%の時は1回発光し残りの99回は発光を止める。デューティ90%なら90回発光10回消灯となる。
1クールの時間は 0.03ms*100回=3ms(333Hz)である。(TCNT0=252の時)
ポートBに8個のLEDをつなぎ、Hで発光させる。
8個のポートに対応した変数を準備し、この変数を割込100回につき1ずつ増加している。この変数に
でポイントされる配列変数の値がカウンタが等しくなったときにデューティの終わりで消灯する。
配列変数は1〜99〜1・・・と変化するから次第に明るくなり最大の明るさからは徐々に暗くなる。
8個のポートにはオフセットがかかっているので明るい部分が流れるように見える。
*********************************************************************************** */
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t f=0;
void wait(unsigned int time){ /* 8MHzで100μsのウエイトルーチン */
register unsigned char lpcnt;
__asm__ __volatile__("\n"
"a00%=:\n\t" //"CPU_wait_entry:\n\t"
"ldi %0,200\n"
"CPU_wait_lp%=:\n\t"
"nop\n\t"
"dec %0\n\t"
"brne CPU_wait_lp%=\n\t"
"sbiw %1,1\n\t"
"brne a00%=\n\t" //"brne CPU_wait_entry\n\t"
:"=&a"(lpcnt)
:"w"(time)
);
return;
}
ISR(TIMER0_OVF_vect){
TCNT0=240; /* タイマカウンタ再設定 255に近づけると周期が短くなる */
f=1; /* 割込ルーチンではフラグを立てているだけ */
}
/* メインルーチン */
int main (void) {
uint8_t cnt=0,cnt2=0,a0=0,a1=5,a2=10,a3=15,a4=20,a5=25,a6=30,a7=35,a8=40;
uint8_t d[49]={1,1,1,2,3,3,4,4,5,6,7,9,11,13,15,18,22,27,32,38,46,55,66,79,95,
79,66,55,46,38,32,27,22,18,15,13,11,9,7,6,5,4,4,3,3,2,1,1,1};
DDRD=0xff; // PORTD出力モード
DDRB=0xff; // PORTB出力モード
TIMSK=_BV(TOIE0); //タイマー割込許可
TCCR0B=3; //分周比1/64
TCNT0=206; //タイマカウンタ初期値 一瞬だから何でもよい
sei(); /* 割り込みを有効にする */
for(;;) {
// wait(10);
if(f){
f=0; /* フラグをリセット */
if(PORTD&_BV(6)){PORTD&=~_BV(6);}else{PORTD|=_BV(6);} /* 割込時間測定用端子 割込毎に反転 */
cnt++;
if(cnt==100){ /* 割込100回で1クール */
cnt=0;
PORTB=0xff; /* 全LEDを点灯して */
cnt2++; if(cnt2==3){cnt2=0;} /* 2を3,4・・・と増加すると点滅の周期が長くなる */
if(cnt2==0){ /* しかし、ちらつきが目立つようになる */
a8++;
a0++;if(a0==49){a0=0;}
a1++;if(a1==49){a1=0;}
a2++;if(a2==49){a2=0;}
a3++;if(a3==49){a3=0;}
a4++;if(a4==49){a4=0;}
a5++;if(a5==49){a5=0;}
a6++;if(a6==49){a6=0;}
a7++;if(a7==49){a7=0;}
}
}
if(cnt==d[a0]){PORTB&=0b11111110;} /* デューティに応じて消灯 */
if(cnt==d[a1]){PORTB&=0b11111101;} /* */
if(cnt==d[a2]){PORTB&=0b11111011;} /* */
if(cnt==d[a3]){PORTB&=0b11110111;} /* */
if(cnt==d[a4]){PORTB&=0b11101111;} /* */
if(cnt==d[a5]){PORTB&=0b11011111;} /* */
if(cnt==d[a6]){PORTB&=0b10111111;} /* */
if(cnt==d[a7]){PORTB&=0b01111111;} /* */
}
}/* forの終わり */
}
/* メインルーチン終わり */