HOME > 技術談話 > PIC® microcontroller > タイマを使ったLED制御2
はじめに テーマ 回路図 部品の配置 フローチャート プログラム説明
前回はPICマイコン内蔵タイマを利用しポーリングでタイムアウトを検出するLED制御でしたが、今回はPICマイコンに内蔵されるタイマと割り込み利用してLEDを制御します。 前回の内蔵タイマをポーリングする方法ではLED制御を行う際に遅延の累積は発生しませんが、メイン処理の負荷状況によってはLED制御のタイミングがばらつきます。今回はメイン処理の負荷状況に関係なく、安定してLEDを制御するべく、時間をイベントとし、割り込み処理の中からLED制御を行います。 |
▲ |
(1)基本仕様 PICマイコンにLEDを3個接続し、250ミリ秒単位で順番に点灯します(LED0 > LED1 > LED2 > LED0 > LED1 > …) (2)ハードウェア PIC12F683(8pin)を3Vで動作させます。源発振は内蔵クロックを利用します(4MHz)。 (3)ファームウェア 250ミリ秒の基準は内蔵タイマを割り込み要求とし、割り込み内で算出します。LEDの点灯はスタティック制御です。 なお、厳密に言うと250ミリ秒の近似値249.856msで制御します。 |
▲ |
前回の回路図が利用されます(クリックすると新しいウィンドウが開きます)。 結果的な事ですが、ハードウェアが同じでもプログラムの作り方により動作の安定度は異なります。制御対象がLEDの場合。これは人の目が見て感じる対象なので数msの誤差は区別がつきませんが、対象が信号で相手がマイコンの場合は数msの誤差は致命的です。 制御の総てを割り込み処理で行う方法は非常に安定した出力を行いますが、その分メイン処理の動作が遅くなります。できることならば割り込み処理の守備範囲を小さくした方が良いと思われますが、ケースバイケースです。 |
▲ |
前回の配置が利用されます(クリックすると新しいウィンドウが開きます)。 |
▲ |
関数mainは自動生成されるスタートアップルーチンから呼び出されます。 基本的な流れは前回と同様ですが、タイマの割り込みを許可し、グローバルな割り込みを許可している箇所が異なります。 今回のサンプルプログラムではLED制御の箇所を総て割り込み処理内で行っており、メイン処理では何もしていませんが、一般的なプログラムでは割り込み処理以外の様々な処理を行っています。 |
新たに設けられた割り込み処理です。 タイマ0のオーバーフローをトリガに割り込み処理が実行されます。 関数の修飾子 interrupt により当該関数が割り込み処理であることを明示し、関数の入り口と出口でレジスタの退避と復帰が行われます。この退避、復帰作業に関わるアセンブラ命令はコンパイラが付与するのでユーザプログラムは意識しなくても大丈夫です。 サンプルプログラムでは前回の待機監視、LED制御をサブルーチンコールしています。が、できることならば割り込み処理内におけるサブルーチンコールのネストは浅くなるように設計することを勧めます(駄目では無い)。 |
この処理の構成は前回と同様です。 唯一の違いは…。 この待機監視では250msを検出します。タイマ割り込み要求が4096us周期で発生するので、61回分のタイマ割り込み要求を検出すると250ms経過と判断します。なお厳密には249.856msです。 割り込み処理から呼び出されることに注意してください。 PIC12F683では各割り込み要因に対して共通の割り込み処理を実行します。今回のサンプルプログラムでは割り込み要因はタイマ0の1つだけですが、複数種の割り込み要因を処理する場合は総ての割り込み要因を確認する必要があります。割り込み要因が残されたままで割り込み処理を終了すると再度割り込み処理が動作します。 今回のサンプルプログラムでは割り込み要因がタイマ0の1つだけですが、割り込み処理実行時に当該割り込みが発生しているか否かを確認する事を勧めます。 |
この処理は前回と同様です。 割り込み処理から呼び出されることに注意してください。 |
▲ |
(1)プログラム本体
サンプルプログラムを公開します … Test103_LED001.zip HI-TECH C v9.70 で作成されたプログラムを v9.81 以降のコンパイラで再コンパイルする際の注意点 → 開発環境による修正 2011/03/09 プログラムには特別な記述はありません。コメントを見るだけでも大まかに理解できると思いますが、気になりそうな箇所だけをピックアップして補足説明します。 |
(2)割り込み処理とプログラム容量
割り込みを利用することは劇薬を扱うことに等しいです。ですが、その動作を理解して使用することでプログラムがシンプルになるばかりか、事象に対する反応速度が安定します。反面、割り込みに頼りすぎるとプログラム容量が肥大する傾向があるので注意してください。 例えばプログラム容量を削減しようとメイン処理で呼び出す汎用関数を割り込み処理で利用したとします。PICマイコンの場合はスタック領域に確保するローカル変数という概念がないので、コンパイラが割り込み処理用の汎用関数を生成します。この時、割り込み処理用のローカル変数も生成することに注意が必要です。 できることならば基礎情報をメイン処理で作成し、その情報に基づいて割り込み処理が作業を行う構成を勧めます。 |
(3)割り込み処理と処理時間
以下の図では事象発生周期に対して割り込み処理時間(可変長と仮定)が伸びた場合を想定しています。このケースでは伸びても一瞬であり現在保留中の割り込み要求が直ちに処理されるならば事象認識のモレはありません。 なお、割り込み要求を解除する部位は直ちに。であり、処理を終了する部位で行うことは危険です。 |
以下の図では事象発生周期の2倍以上、処理時間を要した場合を想定しています。このケースでは事象の上書きが発生してしまい1回分の事象を見失っています。 なお、事象発生周期と称しましたが、間隔が一定の時間情報に限らず、時間がばらつく外部信号の変化を認識する場合なども含めて最短周期を考慮するようにプログラミングする必要があります。 |
前者の場合はかろうじて処理を行うことはできますが、避けたい状況です。そして後者は…完全にNGです。 理想を言えば、割り込み処理は事象発生周期の最短時間未満で処理を行う事が基本です。 |
(3)割り込み処理と変数の競合
今回のサンプルプログラムではポートのバックアップデータは総てLED制御になりますが、ポートの中に別の機能を行う情報が含まれていて、その情報の更新がメイン処理で行うような場合、メイン処理では当該情報を操作する期間を割り込み禁止にする必要があります。 割り込みが許可される前の初期設定等、明らかに排他的であると判断される場合を除きますが、メイン処理と割り込み処理で同時にアクセスする可能性のある変数はvolatile属性を付与して下さい(コンパイラの最適化により過去の情報を参照する可能性がある)。 |
(4)割り込み処理と割り込み禁止
割り込み禁止、許可は便利なのですが、割り込み禁止期間は短くなるよう考慮してください。割り込み禁止期間が長いと割り込み要求に対する応答性が悪くなります。 C言語で1行で記述されたとしても、割り込み禁止中に乗除算する様な…やらない方が無難です。 プログラム全体で見た場合に割り込み禁止命令 di() と割り込み許可命令 ei() は同じ数だけ存在するはずです。プログラミングの都合で数が異なる場合もありますが、数が合わない場合の理由を必ず見つけてください。逆に数が合った場合でも、その関係が正しいことを確認してください。結局は確認する必要があるのですが(汗。 割り込み禁止許可命令の後ろにコメントで印をつけてテキストエディタで検索するとわかりやすいです。 |
▲ |