Timer割込(Arduino-Pico環境)

最終更新日:2022/4/4

Timer割込はArduino-Pico環境でも実現出来ました。
使用するライブラリはKhoi Hoang氏が作成したモノで、
https://www.arduinolibraries.info/libraries/rpi_pico_timer-interrupt
からライブラリをダウンロードしてインクルードしてください。
#include "RPi_Pico_TimerInterrupt.h"


/*
 * 2022年4月1日 T.Wanibe
 * RP2040でタイマ割込するサンプルスケッチを見つけたので動作確認します。
 ****************************************************************************************************************************
 * TimerInterruptTest.ino
 * RPi_Pico_ISR_Timer-Impl.h
 * RASPBERRY_PI_PICO、ADAFRUIT_FEATHER_RP2040、GENERIC_RP2040などのRP2040ベースのボードの場合。
 * Written by Khoi Hoang
 * Built by Khoi Hoang https://github.com/khoih-prog/RPI_PICO_TimerInterrupt
 * Licensed under MIT license
 * 
 * RPI_PICOシステムタイマーペリフェラルは、システムにグローバルマイクロ秒のタイムベースを提供し、このタイムベースに基づいて割り込みを生成します。
 * 次の機能をサポートします。    
 * ?マイクロ秒ごとに1回インクリメントする単一の64ビットカウンター
 * ?このカウンタは、32ビットバスを介したレースフリー読み取りのために、ラッチレジスタのペアから読み取ることができます。
 * ?4つのアラーム:カウンターの下位32ビットで一致、一致でIRQ:TIMER_IRQ_0-TIMER_IRQ_3 
 * 
 * これで、これらの新しい16個のISRベースのタイマーをすべて使用しても、最大間隔は実質的に無制限(符号なしの長いミリ秒によってのみ制限されます)、RPI_PICOタイマーを1つだけ消費し、他のコアのタスクとの競合を回避できます。
 * ソフトウェアタイマーと比較して、精度はほぼ完璧です。 最も重要な機能は、それらがISRベースのタイマーであるということです。したがって、それらの実行は、動作の悪い関数/タスクによってブロックされません。
 * この重要な機能は、ミッションクリティカルなタスクに絶対に必要です。 
 ******************************************************************************************************************************
 *
 * ノート:
 * 割り込みコードとプログラムの残りの部分の間でデータを共有するには、特別な設計が必要です。
 * 変数は通常、「揮発性」タイプである必要があります。 Volatileは、変数が自発的に変更できないと想定する最適化を回避するようにコンパイラーに指示します。
 * プログラムが変数を使用している間、関数は変数を変更する可能性があるため、コンパイラーはこのヒントを必要とします。 しかし、揮発性だけでは十分でないことがよくあります。
 * 共有変数にアクセスするときは、通常、割り込みを無効にする必要があります。
 * 揮発性の場合でも、割り込みが一連の命令間でマルチバイト変数を変更すると、誤って読み取られる可能性があります。
 * データが配列やカウントなどの複数の変数である場合、通常、割り込みを無効にするか、データにアクセスするコードのシーケンス全体を無効にする必要があります。
 * 
 * 最大2093056バイトのフラッシュメモリのうち、スケッチが55820バイト(2%)を使っています。
 * 最大262144バイトのRAMのうち、グローバル変数が7552バイト(2%)を使っていて、ローカル変数で254592バイト使うことができます。
 */
// これらの定義は、前に最初に配置する必要があります #include "TimerInterrupt_Generic.h"
// _TIMERINTERRUPT_LOGLEVEL_ from 0 to 4
// 定義しないでください _TIMERINTERRUPT_LOGLEVEL_ > 0. 特別なISRデバッグのみ. システムを吊るすことができます.
#define TIMER_INTERRUPT_DEBUG         1
#define _TIMERINTERRUPT_LOGLEVEL_     4
// `複数の定義`リンカーエラーなしで、必要な回数だけ含めることができます
#include "RPi_Pico_TimerInterrupt.h"
#ifndef LED_BUILTIN
        #define LED_BUILTIN     25      // ピンD2はESP32のピンGPIO2/ADC12にマッピングされ、オンボードLEDを制御します
#endif
#define PIN_D1                  16      // RPI_PICOのピンGPIO1にマップされたピンD1
#define TIMER0_INTERVAL_MS      1000
#define TIMER0_DURATION_MS      5000
#define TIMER1_INTERVAL_MS      3000
#define TIMER1_DURATION_MS      15000
//Init RPI_PICO_Timerは、0?15の疑似ハードウェアタイマーを使用できます。
RPI_PICO_Timer  ITimer0(0);
RPI_PICO_Timer  ITimer1(1);
//-------------------------
bool    TimerHandler0(struct repeating_timer *t){ 
        static bool toggle0 = false;
        static bool started = false;
        if (!started){
                started = true;
                pinMode(LED_BUILTIN, OUTPUT);
        }
#if (TIMER_INTERRUPT_DEBUG > 0)
        Serial.print(F("ITimer0 called, millis() = ")); Serial.println(millis());
#endif
        //タイマー割り込みはピンLED_BUILTINを切り替えます
        digitalWrite(LED_BUILTIN, toggle0);
        toggle0 = !toggle0;
        return true;
}
//-------------------------
bool    TimerHandler1(struct repeating_timer *t){ 
        static bool toggle1 = false;
        static bool started = false;
        if (!started){
                started = true;
                pinMode(PIN_D1, OUTPUT);
        }
#if (TIMER_INTERRUPT_DEBUG > 0)
        Serial.print(F("ITimer1 called, millis() = ")); Serial.println(millis());
#endif
        //timer interrupt toggles outputPin
        digitalWrite(PIN_D1, toggle1);
        toggle1 = !toggle1;
        return true;
}
//-------------------------
void setup(){
        Serial.begin(115200);
        while (!Serial);
        delay(100);
        Serial.print(F("\nStarting TimerInterruptTest on ")); Serial.println(BOARD_NAME);
        Serial.println(RPI_PICO_TIMER_INTERRUPT_VERSION);
        Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
        //マイクロ秒単位の間隔
        if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0)){
                Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
        }else{
                Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
        }
        //マイクロ秒単位の間隔
        if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1)){
                Serial.print(F("Starting ITimer1 OK, millis() = ")); Serial.println(millis());
        }else{
                Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
        }
        Serial.flush();  
}
//-------------------------
void loop(){
        static unsigned long    lastTimer0      = 0;
        static unsigned long    lastTimer1      = 0;
        static bool             timer0Stopped   = false;
        static bool             timer1Stopped   = false;
        if (millis() - lastTimer0 > TIMER0_DURATION_MS){
                lastTimer0 = millis();
                if (timer0Stopped){
                        Serial.print(F("Start ITimer0, millis() = ")); Serial.println(millis());
                        ITimer0.restartTimer();
                }else{
                        Serial.print(F("Stop ITimer0, millis() = ")); Serial.println(millis());
                        ITimer0.stopTimer();
                }
                timer0Stopped = !timer0Stopped;
        }
        if (millis() - lastTimer1 > TIMER1_DURATION_MS){
                lastTimer1 = millis();
                if (timer1Stopped){
                        Serial.print(F("Start ITimer1, millis() = ")); Serial.println(millis());
                        ITimer1.restartTimer();
                }else{
                        Serial.print(F("Stop ITimer1, millis() = ")); Serial.println(millis());
                        ITimer1.stopTimer();
                }
                timer1Stopped = !timer1Stopped;
        }
}



戯言(nonsense)に戻る


問い合わせ頁の表示


免責事項

本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。

本ソフトウエアの著作権はToolsBoxに帰属します。
本ソフトウエアをご利用の結果生じた損害について、ToolsBoxは一切責任を負いません。
ToolsBoxはコンテンツとして提供する全ての文章、画像等について、内容の合法性・正確性・安全性等、において最善の注意をし、作成していますが、保証するものではありません。
ToolsBoxはリンクをしている外部サイトについては、何ら保証しません。
ToolsBoxは事前の予告無く、本ソフトウエアの開発・提供を中止する可能性があります。

商標・登録商標

Microsoft、Windows、WindowsNTは米国Microsoft Corporationの米国およびその他の国における登録商標です。
Windows Vista、Windows XPは、米国Microsoft Corporation.の商品名称です。
LabVIEW、National Instruments、NI、ni.comはNational Instrumentsの登録商標です。
I2Cは、NXP Semiconductors社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。