プロが教える店舗&オフィスのセキュリティ対策術

ATtiny2313で割り込み端子入力2つを使用してINT0が入力されたら赤LEDを点灯させて、INT1端子が入力されたら黄LEDを点灯させて、どちらの入力もなかったらパワーダウンモードでマイコンの消費電流を最小限まで落とすというプログラムを作って動作させています。

だいたい割り込みのプログラムはできたのですが、INT0とINT1端子がどちらとも入力されていた場合INT0を優先して、割り込み1ベクタルーチンに飛ぶようにしたいのですが、今のプログラムは先に入った方の入力が優先されるようで、後から入ってきた割り込み端子入力は全く無視するようなプログラムになっているようです。

ATtiny2313のデータシートでINT0端子に優先的な割り込み許可を与えるレジスタ設定などがあるのかなと探しているのですが、よくわからない状態です。

現在のプログラムの動きを試験しているテスト基板の画像をyoutubeで動画にして投稿しました。

どなたかご存知のかたいらっしゃいましたらご教授よろしくお願い致します。

A 回答 (6件)

C/C++の質問ではないような気がするのですが…。



AVRは確か割り込みベクタの若い方から優先順位が高かった筈です。
和訳されたデータシートもありますので参考にしてみてください。
(参考URLの27ページにベクタテーブルの記述があります)

参考URL:http://reef.path.ne.jp/~hero/pdf/tiny2313.pdf
    • good
    • 0

えぇと、読み直したら質問の回答になっていないようで…;



まず、割り込みの条件は何でしょう。
目的からすると論理変化ですよね?

プログラムの内容としては…

・メイン
 スリープ無限ループ

・INT0処理
 INT0=Loなら赤ON
 INT0=Hiなら赤OFF

・INT1処理
 INT1=Loなら黄ON
 INT1=Hiなら黄OFF

というプログラムであれば、変化時にLEDが変わると思うんですが。

ちなみに、割り込み処理中に割り込みが発生しても割り込みは保留されるので、割り込み処理から抜けていなければ他の割り込みの処理は出来ません。
    • good
    • 0
この回答へのお礼

回答いただきありがとうございます。

> ちなみに、割り込み処理中に割り込みが発生しても割り込みは保留
> されるので、割り込み処理から抜けていなければ他の割り込みの
> 処理は出来ません。

この、”割り込み処理から抜けなければ他の割り込み処理ができない”というのはATtiny2313の39ページ目の”外部割り込み要求フラグ レジスタ (External Interrupt Flag Register) EIFR”

この部分に相当するものでしょうか。

EIFRレジスタの
bit7 --- INTF1 : 外部割り込み1要求フラグ
bit6 --- INTF0 : 外部割り込み0要求フラク
bit5 --- PCIF : ピン変化割り込み要求フラク

たとえば赤LEDを点灯させる時はINT0入力にLOWを入れるとINTF0ビットがセットされ、INT0割り込みルーチンに飛び、その時にbit7のINTF0が
クリアされ、割り込みルーチンを抜けて、まだINT0がLOWだったら再度セットされてまたINT0割り込みルーチンに行く・・・・

みたいな考えでよいでしょうか。


プログラムの全体的な作りはyamaj_bizがおっしゃった通りで、

main関数内にステートマシンを作り

case MODESW_LED_FLASH01:
case MODESW_LED_FLASH02:
case MODESW_LOWPOWER:
default

INT0,INT1がどちらもHIGHなら
”MODESW_LOWPOWER”内のsleepモードでパワーダウンモードに突入します。

INT0,INT1の割り込みで
MODESWStateという変数にステートが設定され、赤か黄のLEDが点灯するという感じにしています。

私のブログに現在の動画のマイコンプログラムを掲載してみました。
http://d.hatena.ne.jp/blackzoro/20090811


私の考えでは、もしINT0,INT1を両方LOWにした場合、INT0の優先度が高いのであれば、INT0の割り込みルーチンに飛び、その時にフラグはクリアされるので、割り込みルーチンを抜けた後は再度INT0,INT1がLOW状態ならばINT0ルーチンに飛ぶと考えています。ただ、INT0をHIGHにした場合、INT1がLOWなので、INT1の割り込みルーチンに行くと思っていたのですが、動画ではそうならず、ずっとINT0の割り込みルーチンに行っている状態になってしまいます。このようにしたい場合、どのようにプログラミングしたらよいのかご存知でしょうか。

お礼日時:2009/08/11 17:31

ん~。


割り込み条件00の動作が良く理解出来てないので完全な回答は難しそうです。

手っ取り早く思い通りに動かすプログラム方法としては、ステートマシンになっているので、割り込み条件を論理変化にしてみてはどうでしょう。
単純に修正すると後優先動作をすると思いますので、後は条件分岐でなんとか…。

ところで、MovieではLEDが点滅していないように思うのですが、映り具合によるものなのでしょうか。
プログラムでは1秒点灯後の消灯を行っているようですが。
    • good
    • 0
この回答へのお礼

回答いただきありがとうございます。

割り込み条件ではなく、割り込み後にINT0,INT1入力のレベルがHIGHかLOWかを調べてそれに応じてどのLEDを点灯させるかを決めるかのステートに行くようにして、その結果でLEDを点灯させるという方法も良いですね。

回路的に割り込み端子を使うことを前提にして考えていたので、INT0、INT1に応じて割り込みルーチンでの処理を考えていたのですが、INT0、INT1はパワーダウンモードからの復帰のための機能としての入力端子として使用するというのも方法ですね。

> ところで、MovieではLEDが点滅していないように思うのですが、
> 映り具合によるものなのでしょうか。
> プログラムでは1秒点灯後の消灯を行っているようですが。

そうですね。確かに消灯はさせているのですが、そのあとにwait時間をはさんでいないので全く点滅の気配がありませんね。私も点滅させようと思っているので、後で修正して、再度そのプログラムを掲載し直します。

お礼日時:2009/08/12 10:28

調べましたが質問者さんの言われているように「INT0端子に優先的な割り込み許可」はないようですね。

INT0とINT1がほぼ同時に割り込みがあった場合はINT0処理が優先され,INT0処理が終わったあとにINT1処理が続けて実行されるはずです。
あと,ソース読んで気になったところがありましたのでコメントします。参考までに・・・
1.INT0がLowで始まり,INT1がLowでINT0をHighにしても赤いLEDが発光したままとは,不思議な動きですね。
  とりあえずウォッチドックまわりの処理をはずして一度動作確認してみては?
  割り込み処理内で次の処理が使えるのかわからない為です。
    wdt_enable(WDTO_8S);
    wdt_reset();
  これでも何も変わらないのであればsleep関連の処理もはずしてみれば問題の切り分けが出来ると考えます。

2.意図して処理されているのであれば問題ありませんが,MODESWStateを割り込み処理で書き換えると割り込みが無視されるケースがありますので,ロジック見直しが必要と思われます。
  例)INT0/1がHighの状態でINT0をLowにした場合
   1.MODESWStateがMODESW_LOWPOWERでsleep中にINT0が割り込みが入ります。
   2.sleepから復帰して,割り込み処理「SIGNAL(SIG_INTERRUPT0)」がコールされMODESWState に MODESW_LED_FLASH01が代入されます。
   3.sleep_mode()の次の行から再開され,ループの先頭に戻りswitch()されcase MODESW_LED_FLASH01ルートへ
   4.LED01点灯開始,sdelay(1)で1秒間NOPで点灯時間を稼ぎ,消灯します。
   5.INT0の割り込みは連続して発行されているはずなので,手順4のsdelay(1)で何回かMODESWStateが書き換わっています。※
   6.このCaseの処理の最後にMODESWStateにMODESW_LOWPOWER代入される為,次はMODESW_LOWPOWERの処理に移ります。
   7.case MODESW_LOWPOWERの処理でsleepします。
   結果的にINT0割り込みは何度も発行される為,意図通りの動きとなるようですが,ステートとINTの状態は分けて管理すべき
   と考えます。割り込み発生時にフラグをONにしてsleepから復帰した時にそのフラグのON/OFFでLEDを制御するとか・・・
   ※もちろん割り込み処理なのでsdelay(1)前後でもMODESWStateが書き換わる可能性があります。
#動画のおかげで現状の動作がよくわかりました!
    • good
    • 0
この回答へのお礼

回答いただきありがとうございます。

私の勉強不足なのが原因だと思うのですが、割り込み動作が私の意図しない動きをしているような気がしていろいろと意見をもらいたく動画を作成してみたというのが今回の質問の動機です。

INT0、INT1の割り込みルーチンにパワーダウンモードからウェイクアップして飛ぶときに最初に
//cli();//全割り込み禁止

これで割り込みを禁止して、再度sleep_mode機能でパワーダウンしてからでないと割り込みがかからないようにしたつもりでした。理由は、もしINT0,INT1が両方ともLOWだったならば、INT0割り込みルーチンに飛んでもらいたかったからです。ただこのcli();をコメントアウトしても結果が同じというのがどうも納得がいかないです。
こうなったらアセンブラの書かれたlssファイルを見てみようかとも考えております(難しそう)。

パワーダウンモードを使用したプログラムのサンプルをインターネット上で調べてもあまり掲載されておらずどのように皆さんが使っているのかと気になっているのですが、

http://avrwiki.jpn.ph/wiki.cgi?page=Getting+Star …

ここの方のパワーダウンモードの使い方はmain関数内の永久ループ内にsleep_mode();とだけ書いて、後は割り込みルーチンごとの処理りを記載してルーチンを抜けたらsleep_mode();に入るという単純な仕掛けにしていることが多いようです。
やはりmain関数内でのステートマシンとINT割り込みルーチンをリンクするようなやり方よりもこのようにしたほうがコンパイラにとってはいいのかなと考えております。

お礼日時:2009/08/12 14:53

>これで割り込みを禁止して、再度sleep_mode機能でパワーダウンしてからでないと割り込みがかからないようにしたつもりでした。

理由は、もしINT0,INT1が両方ともLOWだったならば、INT0割り込みルーチンに飛んでもらいたかったからです。ただこのcli();をコメントアウトしても結果が同じというのがどうも納得がいかないです。
>こうなったらアセンブラの書かれたlssファイルを見てみようかとも考えております(難しそう)。
→そうですねアセンブラで見るのが早いかもしれません。ライブラリでどんなコードを付加されているかわかりませんので・・・。
 一般的には割り込みが発生した場合は,割り込み禁止に自動的なります。Cソースでは意識出来ませんが割り込み処理終了時のRETIで割り込み許可を行っています。
 この為割り込み処理内でCLIを実行しても無効です。
 どうしても割り込み禁止にしたい場合は割り込みマスク(GIMSK)なら操作ができると思います。

>パワーダウンモードを使用したプログラムのサンプルをインターネット上で調べてもあまり掲載されておらずどのように皆さんが使っているのかと気になっているのですが、
>ここの方のパワーダウンモードの使い方はmain関数内の永久ループ内にsleep_mode();とだけ書いて、後は割り込みルーチンごとの処理りを記載してルーチンを抜けたらsleep_mode();に入るという単純な仕掛けにしていることが多いようです。
>やはりmain関数内でのステートマシンとINT割り込みルーチンをリンクするようなやり方よりもこのようにしたほうがコンパイラにとってはいいのかなと考えております。
→割り込み処理ですべて処理出来るのであれば,sleepだけのループがシンプルなのでしょうね。
 もちろん、ループ内に処理があっても何も問題はないはずですが。
    • good
    • 0
この回答へのお礼

回答いただきありがとうございました。

> この為割り込み処理内でCLIを実行しても無効です。
このことを知りませんでした。割り込みルーチンに飛んでいる最中にさらに割り込みがかかって、優先順位の高いものが割り込んできたら、現在の割り込みを中断してその割り込みルーチンに飛ぶと思っていました。今度から気をつけてプログラミングします。


現在youtubeに掲載している動画でINT0,INT1のスイッチを逆に字幕で表示しておりました。訂正完了しましたので報告いたします。大変申し訳ありません。


プログラミングでは大きく分けて2種類の方法を考えてみました。

1、main関数内の永久ループ内でステートマシンを組む場合。INT0,
INT1の入力割り込みで、ステートマシンのINT0、INT1のI/O入力を確認するステートへ移行するようにして割り込みルーチンを抜け、4種類の状態ごとのステートに飛び、最後にパワーダウンモードに入る。


2、main関数内の永久ループ内ではパワーダウンモードに入るだけ。INT0、INT1の割り込みが入力されたらそれぞれの割り込みルーチンでLED点灯させる。もしくは、I/O入力の確認するステートを作り、それにおおじた点灯方法のステートに分岐させ、最後はmain関数に戻り、パワーダウンモードに移行させる。

現在2番目のプログラミングを行ってみたところ、INT0はINT1よりも割り込み優先度が高く、INT1の割り込み最中にINT0がかかるとINT0の割り込みがかかり、それが終了するとINT1の割り込みが実施させるようになることが分かりました。

現在、
http://sourceforge.jp/projects/midicv/svn/view/t …

このページから、現在のこのマイコンのプログラムを”Download GNU tarball”というリンクを押すことでダウンロードすることができます。もし見ていただけるのでしたらばぜひおねがいいたします。

お礼日時:2009/08/13 13:27

「教えて」の回答が必要か迷いましたがコメントします。


>>割り込み処理は割込禁止で処理が呼ばれること。(要約)
>このことを知りませんでした。割り込みルーチンに飛んでいる最中にさらに割り込みがかかって、優先順位の高いものが割り込んできたら、現在の割り込みを中断してその割り込みルーチンに飛ぶと思っていました。
→もし多重割り込みが希望であれば,割込処理中に割込み許可いれることで実現出来ます。ただ,割込処理全般の考慮をしなくてはいけなく非常に複雑ですので,必要になった時に実装すべきと考えます。

>現在2番目のプログラミングを行ってみたところ、INT0はINT1よりも割り込み優先度が高く、INT1の割り込み最中にINT0がかかるとINT0の割り込みがかかり、それが終了するとINT1の割り込みが実施させるようになることが分かりました。
→ソースから動作を予想すると,INT1割込処理が連続して実行されているが,INT0割込要因を有効にするとINT0割込処理が連続で実行されるようになる。INT0割込処理が終わったころにはINT0割込がまた発生しているのでINT1割込処理が動かないということでしょうか。

→ソースの確認はしました。ソースの目的がINT0/INT1の優先を確認するのであれば問題ないと思います。
 個人的には割込処理にウォッチドッグタイマの処理は不要な気がしますが,試験的であれば問題ないと考えます。
 あと,個人的に興味をもったのはLED_FLASHER\default\LED_FLASHER.lssの323行目にcliがありました。これは318行目のwdt_enable(WDTO_8S)処理の中に割込禁止が含まれていることです。つまりwdt_enable()を割込禁止外で使う場合は対に割込許可(SEI)をする必要があります。割込処理に関わるウォッチドッグ設定には割込禁止が必要ということでしょうか。

#1番目の構想に近い,割り込み処理では最小限の処理を行い,通常処理でLED制御を行うのが一般的だと思いますので,是非チャレンジして下さい。

この回答への補足

私が先ほど質問した

> ただ、ピン変化割り込みの許可を行ったはずがエミュレート
> デバッガで確認してもその割り込みルーチンに飛ばないので
> 困っています。
> 原因とか分かりませんでしょうか?

すみません。原因は私の勘違いで、PCINT0端子はINT0端子だと思ってました。データシートでDIPタイプのマイコンATtiny2313の端子を見たら、INT0(PD2:6番ピン)、PCINT0(PB0:12番ピン)と全然違いますね。PCINT0にスイッチでLOWを入力させたら、確かに割り込みがかかります。

大変申し訳ありません。

補足日時:2009/08/17 10:12
    • good
    • 0
この回答へのお礼

回答いただきありがとうございます。

> もし多重割り込みが希望であれば,割込処理中に割込み許可
> いれることで実現出来ます。

このようなこともできるのですね。今度試してみたいと思います。いろいろと動作させたい幅が広がりそうです。


> #1番目の構想に近い,割り込み処理では最小限の処理を行い,
> 通常処理でLED制御を行うのが一般的だと思いますので,
> 是非チャレンジして下さい。

今、この方法でのプログラミングを行ってみています。

パワーダウンモードからの復帰のINT0,INT1割り込みルーチンへ飛ばすということはやめてINT0,INT1端子のピン変化割り込みでそのルーチンへ行って、main関数内のINT0,INT1端子入力のレベルチェックを行いそれに応じたLED点灯ステートへ行って処理を行い、再度パワーダウンモードステートへ行くという感じにしようと思っています。

ただ、ピン変化割り込みの許可を行ったはずがエミュレートデバッガで確認してもその割り込みルーチンに飛ばないので困っています。
原因とか分かりませんでしょうか?

もし見ていただけましたら
http://sourceforge.jp/projects/midicv/svn/view/t …

ここでファイルが見れるようになってます。
”Download GNU tarball”でダウンロードできます。

お礼日時:2009/08/16 19:27

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!