フォト
2025年3月
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
無料ブログはココログ

« 秋月電子の「お楽しみ袋」を買ってみた | トップページ | Arduino Uno で006P(9V)電池を使って電源を確保する »

2014年11月24日 (月)

ATtiny13Aでウォッチドッグタイマを使ったタイマー割り込み

ATtiny13Aでウォッチドッグタイマを使った簡易的なタイマー割り込みを試してみました。
本来、ウォッチドッグタイマはハングアップを監視して復旧するために使うのですが、
一般的なタイマーとしても利用できます。

ATtiny13Aは通常のタイマー/カウンタが1つしか無く、かつ
arduino環境で使うとシステム用に使われて利用出来ません。
タイマー割り込み、PWM出力、tone()なんかは使えません。

強引に使うことも可能ですが、その場合、一部の機能が使えなくなります。
delay()、micros()などのシステム稼働時間を使っている関数は機能しなくなります。

そこでウォッチドッグタイマを使って簡易的なタイマー割り込みを実現します。
テストとして、0.5秒周期でカウントをして10回目で割り込みを停止するプログラムを
作成してみました。取りあえず動作するようです。

ダウンロード test_tinyTimer.zip (1.4K)
#define BAUD_RATE 38400
#include <BasicSerial3.h>
#include <avr/interrupt.h>

//WDT利用のための定義
#define WDT_reset() __asm__ __volatile__ ("wdr")
#define sleep()     __asm__ __volatile__ ("sleep")
#define WDT_16MS    B000000
#define WDT_32MS    B000001
#define WDT_64MS    B000010
#define WDT_125MS   B000011
#define WDT_250MS   B000100
#define WDT_500MS   B000101
#define WDT_1S      B000110
#define WDT_2S      B000111
#define WDT_4S      B100000
#define WDT_8S      B100001

// WDTタイマー開始
void WDT_start(uint8_t t) {
  cli();                             // 全割り込み禁止
  WDT_reset();                       // ウォッチドッグタイマーリセット
  WDTCR |= _BV(WDCE)|_BV(WDTIE);     // WDCE:ウォッチドッグ変更許可、WDTIE:動作種別=割り込み
  WDTCR |= t;                        // 割り込み間隔設定  
  sei();                             // 全割り込み許可
}

// WDTタイマー停止
void WDT_stop() {
  cli();                             // 全割り込み停止
  WDT_reset();                       // ウォッチドッグタイマリセット
  MCUSR &= ~_BV(WDRF);               // ウォッチドッグリセットフラグ解除
  WDTCR |= _BV(WDCE)|_BV(WDE);       // WDCEとEDEに1をセット
  WDTCR =  0;                        // ウォッチドッグ禁止
  sei();                             // 全割り込み許可
}

uint16_t count =0;

// タイマー割り込みで呼び出される関数
// 1〜10までカウントしたら停止する
ISR(WDT_vect) {
  count++;
  serOutHex(count);
  serOut("\n\r");
  if (count == 10) {
    WDT_stop();
    serOut("STOP\n\r");
  }
}

// シリアル出力整数を16進数で出力
void serOutHex(uint16_t h) {
  uint8_t c;
  for (int8_t i=12; i>=0; i-=4) {
    c = h>>i & 0xf; 
    c = c >9 ? c+'A'-10: c+'0';
    TxByte ((uint8_t)c);
  }
}

// シリアル出力 文字列出力
void serOut(const char* str) {
   while (*str) TxByte (*str++);
}

void setup() {
  WDT_stop();           // 起動直後に念のためにWDTを停止
  serOut("START\n\r");
  WDT_start(WDT_500MS);    // ウォッチドッグタイマ 0.5秒間隔で割り込み実行
}

void loop(){
  sleep();  
}

2014/11/30 追記
Arduino UNOの場合、WDTCRはWDTCSR、WDTIEはWDIEに変更する必要があります。

実行すると、こんな感じになります。

01

シリアル出力用ライブラリは「ATtiny13Aでシリアル通信(UART)を行う」で試した
basicserial3を使っています。スケッチのサイズは636バイトでした。

割り込みの停止、割り込みの再開、カウントにリセットも出来ました。十分使えます。

ウォッチドッグタイマを使うにあたっての問題点等
 ・ウォッチドッグタイマの利用はヒューズビットの設定が必要です。
 ただし、arduino IDEのブートローダ書込み時に設定されるのでこの作業は不要です。

 ・最新のAVRマイコンの一部では、問題が発生するようです。
  ブート直後の16ms後にウォッチドッグタイマによるリセットがかかる場合があり
   ブート直後に明示的にタイマーを停止させる必要があるようです。

   電子牛乳さん「AVR がウォッチドッグタイマ発動後に再起動を繰り返す問題」
  記事で分かりやすく解説されています。
   使った感じでは、ATtiny13Aでは発生しないみたいです(たぶん)。
   該当デバイスにATtiny13はありますがATtiny13Aは無いですね。
   他のデバイスでは注意が必要です。


   

« 秋月電子の「お楽しみ袋」を買ってみた | トップページ | Arduino Uno で006P(9V)電池を使って電源を確保する »

arduino」カテゴリの記事

AVR」カテゴリの記事

ATtiny13A」カテゴリの記事

コメント

はじめまして。

ATtiny13Aを使って同じようなリモコン受信器を製作しているのですがうまくいかず、
ネットで調べていたところ、こちらのブログにたどり着きました。
同じスケッチをArduinoで実行すると正常に動作するのですが、ATtiny13Aだとうま
くいきません。恐らくmicros( )関数が正しく機能していないではと推測しています。
Tinyマイコンでmicros( )関数を使う秘訣のようなものがありましたらご教授願えな
いでしょうか。

ちなみにFuseビットは、「9.6MHz 分周なし」に設定しています。


以上、よろしくお願いいたします。

マコさん、はじめまして
私もATtiny13Aを使い込んでいるレベルではないのですが、分かる範囲で回答いたします。

>micros( )関数を使う秘訣
「TIMER0 を使わない」しか思いつかないです。
私はArduino IDE上でATtiny13Aを利用するための環境としてkosakalabさんのホームページ
「Arduino IDEでATtiny他の開発(Arduino-ISP編)」http://make.kosakalab.com/make/electronic-work/arduino-ide-arduinoisp/を利用しています。
この環境ではTIMER0を利用してdelay(),micros()を実装しています。
したがって、PWMやタイマー割り込み等でTIMER0を使うとdelay(),micros()が使えなくなります。


>同じスケッチをArduinoで実行すると正常に動作するのですが、ATtiny13Aだとうまくいきません。
私もArduino Unoで実装、テストしてATtiny13Aに移植しています。
この時、うまく動作しない場合があります。この時引っかかったのは次の場合です。
 1)Fuseビットの設定を忘れた、クロックの設定が正しくない
=> delay(1000)で1秒が正確な時間かをチェック
2)ピンアサインが間違ている
ATtiny13AとArduino Unoでは利用できるピンが当然異なりますが、
私の場合、プログラムサイズを抑えるために直接レジスタを指定しています(PORTB)等。
ATtinyのPB4(D4ピン)は、Arduino Uno(ATmega328)ではD12(12ピン)となります。

たま吉さん

早々のご返事ありがとうございます。
アドバイスを参考にもう少し調べてみます。

おやすみなさい。

たま吉さん

やっと原因がわかりました。
micros( )関数内のインラインアセンブラで、割込み禁止/許可
の命令が漏れていました...お騒がせしました。

マコさん

ご報告ありがとうございます。
micros( )関数は自作なされたのですね。

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: ATtiny13Aでウォッチドッグタイマを使ったタイマー割り込み:

« 秋月電子の「お楽しみ袋」を買ってみた | トップページ | Arduino Uno で006P(9V)電池を使って電源を確保する »