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をオシロで見たのがこの波形。
タイマー割り込み処理を行っている間、メインで出している
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)出力
となっていて、これを踏襲したいからなんです。
| 固定リンク
「Arduino」カテゴリの記事
- 1/nカウント方式とDDS方式の2相パルス発生回路(2024.10.13)
- おっと。map関数の計算桁に注意(2024.10.06)
- DDS方式の2相パルス発生回路、周波数スキャン機能を付ける(2024.10.05)
- 1クロックでも速くしたい 割込を「ISR_NAKED」で(2024.09.30)
- 1クロックでも速くしたい DDS方式の2相パルス発生器(2024.09.27)
「割り込み処理」カテゴリの記事
- 1クロックでも速くしたい 割込を「ISR_NAKED」で(2024.09.30)
- 1クロックでも速くしたい DDS方式の2相パルス発生器(2024.09.27)
- 最適化処理のせいで悩んだぞ 呪文volatile再び(2024.06.06)
- I2C液晶のアクセス、割り込みで処理しないようにすると(2024.04.12)
- I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの(2024.04.07)
コメント
「delayMicroseconds」の最大値に注意を!
↓ 知らなかったよぉ
http://igarage.cocolog-nifty.com/blog/2021/07/post-c8a883.html
・2021年7月1日:Arduino-UNOでのdelayMicrosecondsの設定は16383までだ!
投稿: 居酒屋ガレージ店主(JH3DBO) | 2021年7月 2日 (金) 09時10分
delayMicroseconds(50000)をオシロで確認
http://igarage.cocolog-nifty.com/blog/2024/02/post-08c9b1.html
投稿: 居酒屋ガレージ店主(JH3DBO) | 2024年2月10日 (土) 10時30分