PIC12F683でウォッチドッグタイマ(WDT)の使い方

2023/07/02

PIC

t f B! P L

PIC12F683でウォッチドックタイマ(WDT)を使う方法をまとめました。

そもそもWDTって?何のためにあるのか

ウォッチドックタイマ(WDT)は、一定時間経過したら、リセット処理をする動作をします。

マイコンが通常に動作しているときには、WDTによって勝手にリセットされては困るので、WDTがタイムアウトするより前に、WDTが時間を計時しているカウンタをクリアして、WDTによるリセットがかからないようにします。

カウンタがクリアされても、WDTはまた計時のためにカウントを開始するので、WDTがタイムアウトするより前に、再びカウンタをクリアする必要があります。そして、これを延々と繰り返すことになります。

こんな面倒なことを、なぜするのか?というと、マイコンがどっかの処理にハマり込んだりして、抜けられなくなったようなとき(つまり異常時)に、自動でリセット(再起動)するためです。

マイコンが、何かの処理に異常に時間がかかったり、無限ループにはまり込んだりした場合、WDTのカウンタをクリアすることが出来ず、WDTによるリセットがかかります。この場合、マイコンは初期状態からやり直すことができます。

正直、こんなことが起こるのはマズイので、それで良しとするのか?という問題もありますが、フリーズして全く反応なし。みたいな状態よりはマシ。という発想のものです。

WDTを使うための3ステップ

PIC12F683でWDTを使うためには、以下のように設定していきます。

WDTを使うための3ステップ
  1. WDTを有効にする
  2. タイムアウトになるまでの時間を設定する
  3. 定期的に(タイムアウトになる前に)クリア処理をする

Step1:WDTを有効にする

WDTを有効にする方法は2つあります。

  • コンフィグレーションでWDTをONにする
  • 「WDTCON」レジスタのSWDTEN(0bit目)を"1"(ON)にする

両者の違いは、コンフィグレーションでWDTを有効とした場合は、プログラムから途中でWDTを無効とすることはできません。しかし、「WDTCON」のSWTDENでWDTを有効にした場合は、SWTDENに"0"を書き込むことで、プログラムからWDTを無効にすることができます。

Step2:タイムアウトになるまでの時間を設定する

タイムアウトになるまでの時間は、「WDTCON」レジスタと「OPTION_REG」によって設定します。

WDTは、31kHzの内蔵クロックで動作して、勝手にカウントアップしていきます。そのため、31kHzの逆数である32.258usごとにカウンタをカウントアップしていきます。

このカウントを、WDT用のプリスケーラに入力していき、溢れたらリセットがかかります。そのため、プリスケーラの大きさが、タイムアウトになるまでの時間の長さになります。

WDTプリスケーラ設定

WDT用プリスケーラの設定は、「WDTCON」レジスタのWDTPS<3:0>で設定します。

WDTCONのWDTPSでプリスケーラ設定

WDT用プリスケーラの最大値は65536で、その時のWDTのタイムアウト時間は2.114秒です。この値でも足りないときは、「OPTION_REG」で更にプリスケーラを追加することができます。

ただし、この追加のプリスケーラは、タイマー0と共用のものなので、このプリスケーラをWDTに割り当てた場合、タイマー0ではプリスケーラを使用することはできなくなります。

WDTプリスケーラ2段

2段目のプリスケーラの設定は、「OPTION_REG」のPSAとPS<2:0>で設定します。

OPTION_REG設定

PSAを"1"にすると、共用プリスケーラはWDTに割り当てられます。プリスケーラの大きさは、PS<2:0>で選択します。

Step3:定期的に(タイムアウトになる前に)クリア処理をする

WDTがタイムアウトしてリセットがかかる前に、WDTカウンタをクリア処理をします。クリア処理は、xc.hに「CLRWDT()」というマクロが用意されています。

CLRWDT()をメインループ内において、メインループが一周するたびにWDTカウンタのクリアを実行するのが常套手段です。

WDT設定の例(タイムアウト時間:2.11s)

#include <xc.h>

#pragma config WDTE = ON	//WDT有効

WDTCON = 0x17;     // 0001_0111  プリスケーラ65536, WDT:2.11sくらい
OPTION_REG = 0xF7; // 1111_0111 プリスケーラはTMR0に使う(1:256)

while(1){	//メインループ
 /* 他の処理 */
    CLRWDT();	//WDTクリア  
}
 
当ブログはアフィリエイト広告を利用しています。

このブログを検索

最新記事

ブログ運営者:そのへんの誰か


このブログのURL

QooQ