« ROWAの互換バッテリー購入 | トップページ | 300kHzのセラミック発振子:Tele Auto FX-1 修理 »

2020年1月28日 (火)

Arduinoから「タイマー0」を取り上げる(ユーザーが使う)

Arduino(UNO)でユーザーが自由に使えるタイマー(ATmega328の)は2つ。
タイマー0をArduinoのシステムが使っているから。
残るタイマー1とタイマー2は自由に使ってokという構成。

で、このタイマー0が何に使われているかというと、この3つ。
 unsigned long millis()・・・経過時間をミリ秒値で得る
 unsigned long micros()・・・経過時間をマイクロ秒値で得る
 void delay(unsigned long ms)・・・ミリ秒値で時間待ち

タイマー0のオーバーフロー割り込みでもって計時しています。
割り込み周期は、16MHzを1/64して256カウントですので、
1.024ms = 976.5625Hz。
  ※なお、「void delayMicroseconds(unsigned int us)」
   は純粋にソフトでの時間待ちですのでこのタイマー0
   には依存しません。

『millis()やmicros()、delay()は使わんぞ』というプログラムなら、
タイマー0もユーザーが使えます。
その検証をちょいと。

・タイマー0のオーバーフロー割り込みをやめる。
   「TIMER0_OVF_vect」の処理ルーチンは残ってしまうけど、
    無視します。

・タイマー0のコンペアマッチA割り込み使って、自由なタイマー
 割り込みを得る。
 例えばジャスト「1ミリ秒=1kHz」と使いやすく。

・そのために、タイマー0のレジスタを直接操作。
・TIMER0_COMPA_vectの処理を書く。

簡単なテストプログラムを紹介しておきます。
  (表示の関係で全角スペースにしてます)

//////////////////////////////////////////////////////////////
// I/O MACRO
#define PB0_H  (PORTB |= (1 << PB0))   // (!!!)PB0 H/L
#define PB0_L  (PORTB &= ~(1 << PB0))
#define PB1_H  (PORTB |= (1 << PB1))   // (!!!)PB1 H/L
#define PB1_L  (PORTB &= ~(1 << PB1))

/***** タイマー0コンペアマッチA割込み    *****/
// 割り込みでパルス出力(1kHz周期)
ISR(TIMER0_COMPA_vect)
{
  PB0_H;             // (!!!)PB0 H
  PB0_L;             // (!!!)PB0 L
}
/*****  セットアップ    *****/
//  ATmega328Pのレジスタを直接制御
void setup()
{
  cli();         // 割込禁止
// I/Oイニシャル
  PORTB = 0b00000000;   // data/pull up
  DDRB = 0b00111111;   // port指定
  //     |||||+---- PB0 IO8  out TEST 割り込みでパルス
  //     ||||+----- PB1 IO9  out TEST メインでパルス
  //     |||+------ PB2 IO10  out
  //     ||+------- PB3 IO11  out
  //     |+-------- PB4 IO12  out
  //     +--------- PB5 IO13  out (LED)
  PORTD = 0b00000000;   // data/pull up
  DDRD = 0b11111100;   // port指定
  //    |||||||+---- PD0 IO0  RXD
  //    ||||||+----- PD1 IO1  TXD
  //    |||||+------ PD2 IO2  out
  //    ||||+------- PD3 IO3  out
  //    |||+-------- PD4 IO4  out
  //    ||+--------- PD5 IO5  out
  //    |+---------- PD6 IO6  out OC0Aトグル出力
  //    +----------- PD7 IO7  out
// タイマー0
  TCCR0B = 0x00;     // タイマー0いったん停止
  TCCR0A = 0b01000010;  // あらためてモード設定
  //     |||| ++--- WGM: CTCモード
  //     ||++------- COM0B
  //     ++--------- COM0A PD6トグル出力
  TCCR0B = 0b00000011;
  //       |+++--- CS:1/64 : 250kHz
  //       +------ WGM02
  OCR0A = 250 - 1;    // 250カウントで1kHzを
  TIMSK0 = 0b00000010;
  //        +----- OCIE0A コンペアマッチA割り込み有効
  //               オーバーフロー割込は無しに
  sei();         // 割込許可
}

/***** LOOP    *****/
// PB1にパルス出力
void loop()
{
  PB1_H;             // (!!!)PB1 H
  PB1_L;             // (!!!)PB1 L
}
//////////////////////////////////////////////////////////////

PB0、PB1そしてPD6をオシロで見たのがこの波形。

Tm01

タイマー割り込み処理を行っている間、メインで出している
PB1のパルスが止まります。
PD6がトグル(ここで割り込み要求が発生している)してPB0が
オン(割り込み内の処理)するまでの間、時間がかかっている
のは割り込みのスタック処理です。
レジスタを待避するなどあれこれ見えない処理が走ります。

Arduinoでの初期設定は「wiring.c」に記されています。
この中で設定されている「TIMER0_OVF_vect」の処理は取り除けません。
しかし、タイマー0オーバーフロー割り込み許可ビット:TOIE0を0に
することでこの処理は走りません。
そして、オーバーフローは無視してコンペアA割り込みを走らせる
のです。

タイマー0のクロック分周設定や割込時間も自由。
   「OCR0A= 25 - 1;」としたら10kHzで割り込み。
   まぁ、1msあたりが使いやすいかと。
計時だけでなく、いろんな処理を入れ込めますので、3つしかない
タイマーが生かせます。

ただ・・・millis()やmicros()、delay()をシステムで(ユーザー
から見えない何かの処理)使っていたら、その処理は止まってしま
います。
シリアルや液晶表示は大丈夫そうでしたが、「ダメ」なのを探し切れて
いません。

※関連
割り込みで処理させるwordデータの扱い
Arduinoのタイマー処理 タイマー0のオーバーフロー割り込みの実行時間
ラジオペンチ Arduinoのmillis()関数が返す値は不連続な場合がある
魔法の言葉「volatile」
AVRマイコンのCコンパイラ 具体的に


※追記
なぜタイマー0を使いたいのか・・・
JIS C8708による充放電サイクル試験回路 これの「2019」対応プログラムを
Arduinoに移植したいから。
現在はアセンブラで書いてます。
「C」に直すならArduinoでと考えました。
現状、
  タイマー0:1mS割り込み
  タイマー1:充放電電流設定用PWM出力
  タイマー2:ブザー報知(4kHz)出力
となっていて、これを踏襲したいからなんです。



|

« ROWAの互換バッテリー購入 | トップページ | 300kHzのセラミック発振子:Tele Auto FX-1 修理 »

Arduino」カテゴリの記事

コメント

コメントを書く



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




« ROWAの互換バッテリー購入 | トップページ | 300kHzのセラミック発振子:Tele Auto FX-1 修理 »