SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|

2005-06-21(Tue) PICのTimer0を理解する

  今日は、残業でキーボードをバコバコと叩きまくっていて帰りが遅くなってしまった……のだが、別に家に帰ったトコロでキーボードをバコバコと叩きまくっているオイラなのであった。もし手元からPCが無くなったりしたら、窒息死するに違いない。これは、保障つきで間違いない。

  で、おもむろに昨日のタイマ割り込みの間隔が短すぎる問題の解消を図りだすのである。実はオイラ、タイマ割り込みを利用するのは初めてではないのだが、やっぱりちゃんと勉強しなおしておいた方がよいだろうというコトで、PICのデータシートの一部を翻訳してみるコトにした。ちゅーワケで、PIC12F629/675のデータシート、4章Timer0モジュールの訳をどうぞ。

  あ、そうそう、例によって各文末の句点などにマウスの乗せると原文がポップアップするようにしてある。このヘッポコ訳ッ!! と思ったら、原文を確認すれッ!!

  4.0 TIMER0モジュール_

Timer0タイマ/カウンタモジュールには、以下の特徴があります:

・8ビットのタイマ/カウンタ_

・読み書き可能_

・ソフトウェアで選択可能な8ビットのプリスケーラ(分周器)_

・内部/外部クロックを選択可能_

・オーバフロー(FFh→00h)発生時に割り込みを発生可能_

・外部クロックのエッジ(立ち上がり/立ち下がり)を選択可能_

図4-1はTimer0モジュールとプリスケーラ(WDTと共用)の模式図です

  画像の説明

  4.1 Timer0の操作方法_

タイマモードは、T0CSビット(OPTION_REG<5>)のクリアにより選択されますこのモードでは、インストラクションサイクル毎(1命令実行毎)にTimer0がカウントアップされます(プリスケーラ非使用の場合)TMR0に書き込みがなされた場合、続く2インストラクションサイクルの間、TMR0はカウントアップされませんユーザはこれを考慮の上、TMR0レジスタに値をセットすることで、意図する動きを実現可能です

カウンタモードは、T0CSビット(OPTION_REG<5>)のセットにより選択されますこのモードでは、ピンGP2/T0CKIの変化のエッジ(立ち上がり/立ち下がり)でTimer0がカウントアップされますカウントアップするエッジの方向は、ソースエッジ(T0SE)の選択ビット(OPTION_REG<4>)で指定可能で、T0SEビットがクリアに設定してあれば、立ち上がりでカウントアップされます

  4.2 Timer0割り込み_

TMR0タイマ/カウンタレジスタがオーバフロー(FFh→00h)すると、Timer0割り込みが発生しますこのオーバフローによりT0IFビットがセットされますT0IEビット(INTCON<5>)をクリアすることで、この割り込みを禁止することもできます次の割り込みを有効にするためには、Timer0割り込みルーチンの中でT0IFビット(INTCON<2>)をソフトウェア的にクリアする必要がありますタイマがSLEEP中にカウントアップすることはないので、Timer0の割り込みにより、CPUをSLEEPから復帰させることはできません

  4.3 Timer0を外部クロックで使用する_

プリスケーラを利用しない場合、外部クロック入力はプリスケーラの出力と同じになります内部クロックとT0CKIの同期は、内部クロックのQ2とQ4サイクルにプリスケーラ出力をサンプリングすることによって、実行されますよって、T0CKIをHIGHと認識するには最低2TOSC(+20nsのRC遅れ)、LOWと認識するには最低2TOSC(+20nsのRC遅れ)が必要です外部装置の電気的特性を確認してください

注意:入出力ピンをデジタル入力モードに設定したい場合、ANSEL(9Fh)およびCMCON(19h)レジスタを初期化する必要がありますアナログ入力モードに設定されていると、常に'0'が返りますなお、ANSELレジスタはPIC12F675用です

  4.4 プリスケーラ(分周器)_

この8ビットのカウンタは、Timer0モジュールのためのプリスケーラとして、またはウォッチドッグタイマのためのポストスケーラとして利用可能です(……が、以下このカウンタを一概にプリスケーラと呼ぶことにします)プリスケーラの設定はソフトウェア的にコントロールビットPSA(OPTION_REG<3>)で行えますPSAビットをクリアに設定すると、プリスケーラはTimer0に割り当てられるますプリスケーラ値はPS2:PS0ビット(OPTION_REG<2:0>)により設定可能です

プリスケーラは読み書き不可能ですプリスケーラがTimer0に割り当てられている場合、TMR0レジスタへの書き込み命令(CLRF 1、MOVWF 1、BSF 1などなど)実行の都度、プリスケーラはクリアされますプリスケーラがWDTに割り当てられている場合、CLRWDT命令実行の際、ウォッチドッグタイマのクリアと同時にプリスケーラもクリアされます

  4.4.1 プリスケーラの設定切り替え_

プリスケーラの設定はすべてソフトウェア的に行います(つまり、プログラム実行中にホイッと変えられます)Timer0からWDTへプリスケーラの割り当てを変える場合、以下の命令順序(例 4-1)で実行すれば、意図しないデバイスリセットを避けられます

逆に、WDTからTimer0へプリスケーラの割り当てを変える場合、以下の命令順序(例 4-2)を使用します例えWDTが無効にしてあっても、この方法を利用すべきです

  ※ちょっと、後半は適当なので、またそのうち修正する予定。

  以上。PIC12F629/675のデータシート、4章Timer0モジュールの訳でした。例によって内容の正確さについては無保証なのでそのつもりで。

  でだ、訳すウチに気づいてしまったのだ。それは「次の割り込みを有効にするためには、Timer0割り込みルーチンの中でT0IFビット(INTCON<2>)をソフトウェア的にクリアする必要があります」というトコロ。今回、気づかないうちに、そのコードをコメントアウトしていたんだよね。

  通常、割り込みルーチンには、割り込み処理をそのまま記述するのでなく、起こった割り込みの種類をイベントフラグに記録する処理だけを記述する。そんでもって、割り込み処理自体はメインルーチンの中で行うようにするのが常套手段である。なぜなら、割り込み処理中に再び割り込みイベントが発生すると、二重に割り込みが発生することはないので、後者のイベントを取りこぼしてしまうからである。そーゆーコトではどーしよーもないので、極力取りこぼしたくないならば、極力割り込み処理自体を短時間で完了する必要があるのだ。ところが今回、割り込み処理のテストとして行ったLEDの点滅処理は非常に軽いので、割り込みルーチンの中に直接書いてしまったのが災いした。LEDの点滅処理を追加する際に、元から記述してあったT0IFビットをクリアする処理をコメントアウトしてしまったのである。これが昨日の失敗の理由だ。理解したので、サクッと修正する。

  コードは割り込みの都度、ポートのHIGH/LOWを反転処理するように書いているので、割り込みがかかる度に点灯、消灯を繰り返す動作になっている。内蔵オシレータは4MHzであるから、1インストラクションは1usで、1インストラクションごとにTMR0がカウントアップするから、256usで割り込みがかかる……トコロなのだが、そこに4倍に設定したプリスケーラを咬ませているから、256us x 4 = 1024us = 1ms。1ms単位で割り込みがかかるのだ。

  しかし、1ms間隔の点滅は目で確認することができないので、オシロで確認するのだ。ドキドキ……

  画像の説明

  ……よっしゃッ!! 多少の誤差はあるが、キチンと1ms間隔でHIGH/LOWが切り替わっているようだ。これにて割り込み設定処理の完成である。それにしても、T0IFビットのクリアを忘れると、連続的に割り込みがかかってしまう現象が発生するとは知らなかった。ちゅーコトで、明日はガスセンサのヒータとセンサに与える電源パルスを作り出す予定である。ちゃらっちゃっちゃっちゃらッ!!