#norelated
* LEDサンプル [#d2eb2c43]

やっぱり最初はこれよね。~
LEDをPD0〜PD7に接続。~

#ref(LEDTest.png,left,nowrap,LEDサンプル)

本当は抵抗が必要なはずだが、まぁいい。~
とりあえずは光ればいい。~

#u2b(fc-vW6RD1Co,w=480,h=385)

以下、ソースコード。~

 #include <avr/io.h>
 #include <util/delay.h>
 
 void delay_ms( int time )
 {
 	// 指定ms分ループ
 	while( time-- ){
 		_delay_ms( 1 );
 	}
 }
 
 int main( void )
 {
 	DDRD	= 0b11111111;	// ポートDの方向レジスタを、全て出力に
 	PORTD	= 0b00000000;	// ポートDの出力レジスタを、全てLowに
 
 	char count	= 0;	// 0〜7まで
 	char binc	= 1;	// インクリメントモードかデクリメントモードか
 
 	while( 1 ){
 		PORTD = ( 1 << count );	// ポートDのカウント数位置の出力レジスタのみをHighに
 		if( binc ){	// インクリメントモード
 			count++;
 			if( 7 <= count ){	// 端までいったのでデクリメントモードへ
 				binc = 0;
 			}
 		} else {	// デクリメントモード
 			count--;
 			if( 0 >= count ){	// 最初まで戻ったのでインクリメントモードへ
 				binc = 1;
 			}
 		}
 		delay_ms( 50 );	// 50ms待ち
 	}
 
 	return 0;
 }

ATmega168Pは、内蔵RC発信器が8MHzとなっていたので、普通にCPUのFrequencyも8MHzだろうと思いこむ。~
AVRStudioのProject Optionで、Frequencyを8000000Hzに設定して、F_CPUのdefineを設定したんだけど、実際やってみると、delay_msの待ちが余りに遅い。~
具体的に言うと、8倍くらい。~
データシートを読み返してみると、ヒューズビットにCKDIV8とかいうのがあって、こいつが0だと、実際には8で割った数がシステムクロックとなるらしい。~
(システムクロック前置分周器:目的としては、消費電力節約用?)~
ってんで、Frequencyを1000000Hzに設定しなおして、事なきを得る。~

デバイスの最高周波数より高い周波数のクロックを入力する場合、前置分周器で押さえてやったりするみたいね。~

というわけで、ヒューズビットのCKDIV8を立てて、Frequencyを8000000Hzにしてもちゃんと動きました。~
この辺は、電源とかの兼ね合いで変えるべきかね。~

[[AVRWikiにあるように、:http://avrwiki.jpn.ph/wiki.cgi?page=AVR%A4%E8%A4%AF%A4%A2%A4%EB%BC%C1%CC%E4(FAQ)#p17]]_delay_ms関数は、システムクロック数によって、待てる時間が異なり、しかもその時間は結構短い。~
なので、1ms指定で指定ms分ループをしている。~

本当は、1ms指定じゃなくもっと大きい数で少ない回数回す方が、誤差は少ないはず。~
そのシステムクロックで回せる最大数以上だったら最大数、未満だったらその値を指定するのが一番いいような気はする。~
しかし、未満で変数を渡す場合は、以下の問題がある。~

_delay_ms関数は結局、周波数の定数F_CPUを参照して、それをもとにループ回数を決め、ループを回しているだけらしい。~
このため、定数を_delay_msに渡す場合は、コンパイラが最適化し、ループ回数が決定している。~
けど、変数を渡すようなコードを書くと、doubleに変換した引数とF_CPUの計算ルーチンが入るため、コードが膨らむ。~
手軽に使えるけど、色々考えなければいけないようだ。~

タイマーを使ってみようかとも思ったけど、分周比との兼ね合いを考えると、あらかじめ待つ時間がわかってるような場合じゃないと、使いにくい。~
結局、今のやり方が、とりあえずは一番お手頃な感じ。~

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS