初心者
電子工作歴もプログラム歴も同じく1か月弱のなにもかも超初心者なのですが質問です
(おかしな質問してたらごめんなさい)
TIMERのところの
while( !(( TIFR0 >> 1 ) & 1 ) ); //OCF0Aが1になるまでwhileで待機
TIFR0 = 0b00000010; //OCF0Aに1を書き込む(クリア)
上記の部分なのですが、
!((TIFR0 >> 1 ) & 1)
というのは
OCF0Aが1になった時にTIFR0が0b00000010になるから
>>1で0b00000001になり、
0b00000001&1は1だから、!で反転して0になりループを終了する、ということ合っていますか?
while(!TIFR0);や while(bit_is_clear(TIFR0,OCF0A)); では問題ありますか?
それと、ループを抜けた時点でOCF0Aが1になっているはずなのにすぐ下にTIFR0=0b00000010;があるのはなぜでしょうか
宜しくお願いします!
(おかしな質問してたらごめんなさい)
TIMERのところの
while( !(( TIFR0 >> 1 ) & 1 ) ); //OCF0Aが1になるまでwhileで待機
TIFR0 = 0b00000010; //OCF0Aに1を書き込む(クリア)
上記の部分なのですが、
!((TIFR0 >> 1 ) & 1)
というのは
OCF0Aが1になった時にTIFR0が0b00000010になるから
>>1で0b00000001になり、
0b00000001&1は1だから、!で反転して0になりループを終了する、ということ合っていますか?
while(!TIFR0);や while(bit_is_clear(TIFR0,OCF0A)); では問題ありますか?
それと、ループを抜けた時点でOCF0Aが1になっているはずなのにすぐ下にTIFR0=0b00000010;があるのはなぜでしょうか
宜しくお願いします!
kc - Re: 無題
2016/03/09 (Wed) 21:28:59
初心者様、初めまして。
管理人のkcです。
まさかこんな過疎サイトに書き込みがあるとは思わず、ずっと確認していませんでした、大変申し訳ございません<(_ _)>
ご質問有難うございます。
私のわかる範囲でお答えしていきたいと思います。
>>!((TIFR0 >> 1 ) & 1)
>>というのは
>>OCF0Aが1になった時にTIFR0が0b00000010になるから
>>>>1で0b00000001になり、
>>0b00000001&1は1だから、!で反転して0になりループを終了する、ということ合っていますか?
はい、まさしくその通りです!
私の個人的な好みもあるのでこのような書き方をしていますが、
「while(!( TIFR0 & 0b00000010 ))」や「while(!( TIFR0 & ( 1 << 1 )))」
といった書き方でも問題無いです。
>>while(!TIFR0);や while(bit_is_clear(TIFR0,OCF0A)); では問題ありますか?
「while(!TIFR0)」について。
TIMERのページで紹介している設定でしたら、while(!TIFR0)でも同様の動作になると思います。
しかしタイマの設定次第では、2bit目のOCF0B(タイマ/カウンタ0比較B割り込み要求フラグ)や、0bit目のTOV0(タイマ/カウンタ0溢れ割り込み要求フラグ)といった別のビットが立ち上がってしまう可能性があり、バグを出さないプログラムという観点からみると「while( !(( TIFR0 >> 1 ) & 1 ) )」のような、見たいビットのみで真or偽を判定するような書き方が宜しいかと思います。
「while(bit_is_clear(TIFR0,OCF0A))」について。
私自身このマクロを使ったことが無いので、調べた結果をお伝えしたいと思います、もしかしたら間違ってるかもしれません(笑)。
while(bit_is_clear(TIFR0,OCF0A)の場合ですと、
「TIFR0のOCF0Aのビットが0の時は1を返し、TIFR0のOCF0Aのビットが1の時に0を返す」という動作になるため、同様の動作になると思われます。
最下部に詳しい解説を載せておきましたので、宜しければ参考程度に見てみてください。
>>それと、ループを抜けた時点でOCF0Aが1になっているはずなのにすぐ下にTIFR0=0b00000010;があるのはなぜでしょうか
直下でTIFR0 = 0b00000010;としているのは、TIFR0の1bit目(OCF0A)をクリア(0)にするためです。
TIFR0の1bit目(OCF0A)を0にしないと、次にこの処理を通る時に while(!(( TIFR0 >> 1 ) & 1 ) )ですぐ抜けてしまいます。
今回のプログラムでは割り込みベクタを使用していないため、自動的にTIFR0の1bit目(OCF0A)を0にすることが出来ません。ですので、自身でOCF0Aを0にする処理を書く必要があります。
少々驚くかもしれませんが、1を書き込むことで0クリアされます。というのも、データシートに記載されています。
******************************************************************
■ ビット1 - OCF0A : タイマ/カウンタ0比較A割り込み要求フラグ (Timer/Conter0, Output Compare A Match Flag)
OCF0Aビットは比較一致がタイマ/カウンタ(TCNT0)と比較レジスタ(OCR0A)間で起こる時に設定(1)されます。対応する割り込み処理ベクタを実行すると、OCF0Aはハードウェアによって解除(0)されます。代わりにこのフラグへ論理1を書くことによってもOCF0Aは解除(0)されます。ステータス レジスタ(SREG)の全割り込み許可(I)ビット、タイマ/カウンタ0割り込みマスク レジスタ(TIMSK0)のタイマ/カウンタ0比較A一致割り込み許可(OCIE0A)ビット、OCF0Aが設定(1)されると、タイマ/カウンタ0比較A一致割り込みが実行されます。
www.avr.jp/user/DS/PDF/mega88P.pdf P.67より引用
******************************************************************
拙い説明で申し訳ありませんが、以上で質問の回答になったでしょうか?
また、わからないことがあればいつでもご質問して頂ければと思います。
余談ですが、電子工作もプログラムもまだ1ヵ月しか経っていないというのに、この質問の鋭さは素晴らしいと思います。これからも電子工作やプログラム等頑張って下さい。見てくださる方がいるのなら、私もHPの更新を頑張りたいと思います(笑)。
-----------------------------------------------------------------------
bit_is_clearについて
-----------------------------------------------------------------------
sfr_defs.hというヘッダ内にこのマクロがあり、その内容は、
#define bit_is_clear(sfr, bit) (!(_SFR_BYTE(sfr) & _BV(bit)))
のようになっていました。
また、上記のマクロ内で使われているマクロは、
#define _BV(bit) (1 << (bit))
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
となっています。
bit_is_clear(sfr, bit)では、_SFR_BYTE(sfr)と_BV(bit)の論理積をとり、その後、論理否定をとる形となっています。
_SFR_BYTE(sfr)では、指定されたメモリからそのアドレスを取得し、その後何故かまたそのアドレスから中身(メモリ)を取得し、1byte読み込むといった動作をしています(おそらく_SFR_BYTE(sfr)とsfrは等価です)。
_BV(bit)では、指定した数値の数だけビットシフトさせた値を返します。
また、例として挙げているもの以下のようになっています(今回はmega328pのプロジェクトで見たのでアドレス等は若干違う可能性があります)
#define OCF0A 1
#define TIFR0 _SFR_IO8(0x15)
また、上記で使われているマクロは以下のようになっています。
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
__SFR_OFFSETに関してはマイコン毎に値が変わります(0x00,0x20等)
…ここまで長々と各マクロを載せてしまいましたが、ここからは「(!(_SFR_BYTE(sfr) & _BV(bit)))」に実際の値を入れた場合の動作を考えてみます。
TIFR0のレジスタ値が0b00000010の時を考えますと、
_SFR_BYTE( TIFR0 )では、TIFR0の領域として使われているメモリの1byte分のデータが読み込まれます。つまり0b00000010が返されます。
また、_BV(OCF0A)では、0b00000001を1ビットシフトした値となるため、0b00000010となります。
ですので、(_SFR_BYTE(sfr) & _BV(bit))までのところでは、0b00000010 & 0b00000010 => 0b00000010となります。
そして、最後に論理否定「!」が入るので、0b00000010の否定となるため、0b00000000となります。
つまり、bit_is_clearは「指定したレジスタのビットが1の時は0が返される」となっているようです。
逆の言い方をしますと、「指定したレジスタのビットが0の時は1が返される」となっています。bit_is_clearの名前の由来はこちらでしょうね。
-------------------------------------------------------------------------
管理人のkcです。
まさかこんな過疎サイトに書き込みがあるとは思わず、ずっと確認していませんでした、大変申し訳ございません<(_ _)>
ご質問有難うございます。
私のわかる範囲でお答えしていきたいと思います。
>>!((TIFR0 >> 1 ) & 1)
>>というのは
>>OCF0Aが1になった時にTIFR0が0b00000010になるから
>>>>1で0b00000001になり、
>>0b00000001&1は1だから、!で反転して0になりループを終了する、ということ合っていますか?
はい、まさしくその通りです!
私の個人的な好みもあるのでこのような書き方をしていますが、
「while(!( TIFR0 & 0b00000010 ))」や「while(!( TIFR0 & ( 1 << 1 )))」
といった書き方でも問題無いです。
>>while(!TIFR0);や while(bit_is_clear(TIFR0,OCF0A)); では問題ありますか?
「while(!TIFR0)」について。
TIMERのページで紹介している設定でしたら、while(!TIFR0)でも同様の動作になると思います。
しかしタイマの設定次第では、2bit目のOCF0B(タイマ/カウンタ0比較B割り込み要求フラグ)や、0bit目のTOV0(タイマ/カウンタ0溢れ割り込み要求フラグ)といった別のビットが立ち上がってしまう可能性があり、バグを出さないプログラムという観点からみると「while( !(( TIFR0 >> 1 ) & 1 ) )」のような、見たいビットのみで真or偽を判定するような書き方が宜しいかと思います。
「while(bit_is_clear(TIFR0,OCF0A))」について。
私自身このマクロを使ったことが無いので、調べた結果をお伝えしたいと思います、もしかしたら間違ってるかもしれません(笑)。
while(bit_is_clear(TIFR0,OCF0A)の場合ですと、
「TIFR0のOCF0Aのビットが0の時は1を返し、TIFR0のOCF0Aのビットが1の時に0を返す」という動作になるため、同様の動作になると思われます。
最下部に詳しい解説を載せておきましたので、宜しければ参考程度に見てみてください。
>>それと、ループを抜けた時点でOCF0Aが1になっているはずなのにすぐ下にTIFR0=0b00000010;があるのはなぜでしょうか
直下でTIFR0 = 0b00000010;としているのは、TIFR0の1bit目(OCF0A)をクリア(0)にするためです。
TIFR0の1bit目(OCF0A)を0にしないと、次にこの処理を通る時に while(!(( TIFR0 >> 1 ) & 1 ) )ですぐ抜けてしまいます。
今回のプログラムでは割り込みベクタを使用していないため、自動的にTIFR0の1bit目(OCF0A)を0にすることが出来ません。ですので、自身でOCF0Aを0にする処理を書く必要があります。
少々驚くかもしれませんが、1を書き込むことで0クリアされます。というのも、データシートに記載されています。
******************************************************************
■ ビット1 - OCF0A : タイマ/カウンタ0比較A割り込み要求フラグ (Timer/Conter0, Output Compare A Match Flag)
OCF0Aビットは比較一致がタイマ/カウンタ(TCNT0)と比較レジスタ(OCR0A)間で起こる時に設定(1)されます。対応する割り込み処理ベクタを実行すると、OCF0Aはハードウェアによって解除(0)されます。代わりにこのフラグへ論理1を書くことによってもOCF0Aは解除(0)されます。ステータス レジスタ(SREG)の全割り込み許可(I)ビット、タイマ/カウンタ0割り込みマスク レジスタ(TIMSK0)のタイマ/カウンタ0比較A一致割り込み許可(OCIE0A)ビット、OCF0Aが設定(1)されると、タイマ/カウンタ0比較A一致割り込みが実行されます。
www.avr.jp/user/DS/PDF/mega88P.pdf P.67より引用
******************************************************************
拙い説明で申し訳ありませんが、以上で質問の回答になったでしょうか?
また、わからないことがあればいつでもご質問して頂ければと思います。
余談ですが、電子工作もプログラムもまだ1ヵ月しか経っていないというのに、この質問の鋭さは素晴らしいと思います。これからも電子工作やプログラム等頑張って下さい。見てくださる方がいるのなら、私もHPの更新を頑張りたいと思います(笑)。
-----------------------------------------------------------------------
bit_is_clearについて
-----------------------------------------------------------------------
sfr_defs.hというヘッダ内にこのマクロがあり、その内容は、
#define bit_is_clear(sfr, bit) (!(_SFR_BYTE(sfr) & _BV(bit)))
のようになっていました。
また、上記のマクロ内で使われているマクロは、
#define _BV(bit) (1 << (bit))
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
となっています。
bit_is_clear(sfr, bit)では、_SFR_BYTE(sfr)と_BV(bit)の論理積をとり、その後、論理否定をとる形となっています。
_SFR_BYTE(sfr)では、指定されたメモリからそのアドレスを取得し、その後何故かまたそのアドレスから中身(メモリ)を取得し、1byte読み込むといった動作をしています(おそらく_SFR_BYTE(sfr)とsfrは等価です)。
_BV(bit)では、指定した数値の数だけビットシフトさせた値を返します。
また、例として挙げているもの以下のようになっています(今回はmega328pのプロジェクトで見たのでアドレス等は若干違う可能性があります)
#define OCF0A 1
#define TIFR0 _SFR_IO8(0x15)
また、上記で使われているマクロは以下のようになっています。
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
__SFR_OFFSETに関してはマイコン毎に値が変わります(0x00,0x20等)
…ここまで長々と各マクロを載せてしまいましたが、ここからは「(!(_SFR_BYTE(sfr) & _BV(bit)))」に実際の値を入れた場合の動作を考えてみます。
TIFR0のレジスタ値が0b00000010の時を考えますと、
_SFR_BYTE( TIFR0 )では、TIFR0の領域として使われているメモリの1byte分のデータが読み込まれます。つまり0b00000010が返されます。
また、_BV(OCF0A)では、0b00000001を1ビットシフトした値となるため、0b00000010となります。
ですので、(_SFR_BYTE(sfr) & _BV(bit))までのところでは、0b00000010 & 0b00000010 => 0b00000010となります。
そして、最後に論理否定「!」が入るので、0b00000010の否定となるため、0b00000000となります。
つまり、bit_is_clearは「指定したレジスタのビットが1の時は0が返される」となっているようです。
逆の言い方をしますと、「指定したレジスタのビットが0の時は1が返される」となっています。bit_is_clearの名前の由来はこちらでしょうね。
-------------------------------------------------------------------------