マルチタスクArduin:痛みのないタイマー

すべてのarduinoドライバーが、セットアップの開始コードとループの無限ループに加えて、厳密に所定の時間にメインループを停止し、タスクを実行してから制御を慎重に転送するコードをロボットファームウェアに追加できることを知っているわけではありませんメインプログラムを使用して、何にも気付かないようにします。 この機能は、タイマー割り込みメカニズム(すべてのマイクロコントローラーに共通)によって提供され、その助けにより、リアルタイムおよびマルチタスク要素をファームウェアに追加できます。



この機会を実際に使用することはあまりありません。なぜなら、 あまりリッチではない標準のArduino APIでは提供されていません。 そして、マイクロコントローラーの内部機能のすべての豊富な機能へのアクセスは、1つまたは2つのシステムヘッダーファイルを接続することにより無制限にありますが、誰もがかなり特殊な設定コードの画面をきちんとした小さなスケッチに追加したいわけではありません異なるボード)。 少数(特にArduinoの聴衆)が決定し、それを理解することができます。



今日は苦しみからあなたを解放します。



そして、正確に3行のコードを追加することにより、arduinoロボットのファームウェアで実際のマルチタスクとリアルタイムを取得する方法を説明します(ヘッダーの#includeを含む)。 初めてBlinkを始めたばかりでも、成功することをお約束します。



コードからすぐに始めましょう



arduino-timer-api /例/ timer-api / timer-api.ino



timer-api.hライブラリーを接続しますtimes



#include "timer-api.h"
      
      





timer_init_ISR_XYHzを使用して目的の周波数でタイマーを開始します 。ここではXYHz = 1Hz-1ヘルツ-1秒あたり1つの割り込み呼び出し( 2



 void setup() { Serial.begin(9600); // =1, =1 timer_init_ISR_1Hz(TIMER_DEFAULT); pinMode(13, OUTPUT); }
      
      





ISR-割り込みサービスルーチン、割り込みハンドラプロシージャ



ループのメインループにブロッキングまたはノンブロッキングのナンセンスを追加します 。メッセージを出力し、5秒間待機します( ここではすべてが通常どおりなので、カウントしません



 void loop() { Serial.println("Hello from loop!"); delay(5000); //   :    }
      
      





指定された期間でタイマーイベントを中断することによって呼び出されるプロシージャは、 timer_handle_interruptsという名前の関数の実装です。メッセージを出力し、ライトを点滅させます( 3



 void timer_handle_interrupts(int timer) { Serial.println("goodbye from timer"); //   digitalWrite(13, !digitalRead(13)); }
      
      





同じことです。わかりやすくデバッグするために、2つの呼び出しの間に時間測定を追加します。



 void timer_handle_interrupts(int timer) { static unsigned long prev_time = 0; unsigned long _time = micros(); unsigned long _period = _time - prev_time; prev_time = _time; Serial.print("goodbye from timer: "); Serial.println(_period, DEC); //   digitalWrite(13, !digitalRead(13)); }
      
      





ボードを縫い、 Tools> Port Monitorを開き、結果を確認します。



画像



ご覧のとおり、 timer_handle_interruptsハンドラーは1,000,000(100万)マイクロ秒ごとにメッセージを出力します。 正確に1秒に1回。 そして、(ああ奇跡!)、メインループで5秒の遅延(5000)の一定のブロッキング遅延は、この方法でそれを妨害しません。



ここでは、3行の1つのスケッチでリアルタイムとマルチタスクを実行できると約束しました。



timer_init_ISR_XYHzの周波数オプション



  //timer_init_ISR_500KHz(TIMER_DEFAULT); //timer_init_ISR_200KHz(TIMER_DEFAULT); //timer_init_ISR_100KHz(TIMER_DEFAULT); //timer_init_ISR_50KHz(TIMER_DEFAULT); //timer_init_ISR_20KHz(TIMER_DEFAULT); //timer_init_ISR_10KHz(TIMER_DEFAULT); //timer_init_ISR_5KHz(TIMER_DEFAULT); //timer_init_ISR_2KHz(TIMER_DEFAULT); //timer_init_ISR_1KHz(TIMER_DEFAULT); //timer_init_ISR_500Hz(TIMER_DEFAULT); //timer_init_ISR_200Hz(TIMER_DEFAULT); //timer_init_ISR_100Hz(TIMER_DEFAULT); //timer_init_ISR_50Hz(TIMER_DEFAULT); //timer_init_ISR_20Hz(TIMER_DEFAULT); //timer_init_ISR_10Hz(TIMER_DEFAULT); //timer_init_ISR_5Hz(TIMER_DEFAULT); //timer_init_ISR_2Hz(TIMER_DEFAULT); //timer_init_ISR_1Hz(TIMER_DEFAULT);
      
      





timer_init_ISR_1MHz呼び出しもありますが、どのテストコントローラーでも動作する結果は得られません



割り込みコードは、明らかに、次の割り込み呼び出しの前に完了することができるのに十分な速度で実行する必要があり、できれば、メインループを完了するために少しのプロセッサ時間を確保してください。



タイマーの周波数が高くなるほど、割り込み呼び出し周期が短くなるほど、ハンドラーコードの実行が速くなることを説明する必要はないと思います。 ロックブロッキング遅延呼び出し、事前に不明な回数のループ、その他の予測が不十分なランタイムSerial.printを含む)を呼び出すことはお勧めしません。



加算期間(周波数分割)



提案されたものからの標準周波数があなたに合わない場合には、割り込みコードに追加のカウンターを入力できます。これは、一定数の不在着信後にのみ有用なコードを実行します。 ターゲット期間は、スキップされたベース期間の合計に等しくなります。 または、一般的に可変にすることもできます。



arduino-timer-api /例/ timer-api-counter / timer-api-counter.ino



 #include"timer-api.h" void setup() { Serial.begin(9600); while(!Serial); // =10, =100 timer_init_ISR_10Hz(TIMER_DEFAULT); pinMode(13, OUTPUT); } void loop() { Serial.println("Hello from loop!"); delay(6000); //   :    } void timer_handle_interrupts(int timer) { static unsigned long prev_time = 0; //    static int count = 11; //     12  : //    10    100, //      100*12=1200 // (5   6 ) if(count == 0) { unsigned long _time = micros(); unsigned long _period = _time - prev_time; prev_time = _time; Serial.print("goodbye from timer: "); Serial.println(_period, DEC); //   digitalWrite(13, !digitalRead(13)); //   count = 11; } else { count--; } }
      
      





画像



任意の周波数



パラメーターでtimer_init_ISR(タイマー、プリスケーラー、調整)を呼び出すことにより、タイマーの周波数のほぼ任意の(特定の制限内で)値を設定する別のオプションがあります-プロセッサプリ スケーラーのシステムクロック分周器と、タイマーカウンターをレジスタに配置する任意の調整



投稿が過負荷にならないように詳細に進むことなく、詳細なコメント付きの例へのリンクを示します。

arduino-timer-api /例/ timer-api-custom-clock / timer-api-custom-clock.ino



そして、このアプローチを使用すると、異なるクロック速度のコントローラー間でコードの移植性が失われる可能性があることに注意してください。 タイマーの目標周波数を取得するためのパラメーターは、チップ上のシステム信号発生器の周波数、タイマーのビット深度、およびプリスケーラーシステム分周器で利用可能なオプションに正比例して選択されます。



ダイナミクスでタイマーを開始および停止する



タイマーを停止するには、 timer_stop_ISR呼び出しを使用し、タイマーを再起動するには、以前のようにtimer_init_ISR_XYHzの任意のバージョンを使用します。



arduino-timer-api /例/ timer-api-start-stop / timer-api-start-stop.ino



 #include"timer-api.h" int _timer = TIMER_DEFAULT; void setup() { Serial.begin(9600); while(!Serial); pinMode(13, OUTPUT); } void loop() { Serial.println("Start timer"); timer_init_ISR_1Hz(_timer); delay(5000); Serial.println("Stop timer"); timer_stop_ISR(_timer); delay(5000); } void timer_handle_interrupts(int timer) { static unsigned long prev_time = 0; unsigned long _time = micros(); unsigned long _period = _time - prev_time; prev_time = _time; Serial.print("goodbye from timer: "); Serial.println(_period, DEC); //   digitalWrite(13, !digitalRead(13)); }
      
      





画像



ライブラリのインストール



リポジトリをライブラリディレクトリに直接クローンします



 cd ~/Arduino/libraries/ git clone https://github.com/sadr0b0t/arduino-timer-api.git
      
      





Arduino環境を再起動します。



または、 arduino-timer-apiプロジェクトページで、 クローンのスナップショットをダウンロードするか、ダウンロード> ZIPリポジトリまたはリリースのいずれかをアーカイブとしてダウンロードし、Arduino環境のライブラリセットアップメニューからarduino-timer-api-master.zipアーカイブをインストールします( Sketch> Connect library > .ZIPライブラリを追加... )。



サンプルはメニュー>ファイル>例> arduino-timer-apiに表示されます



サポートされているチップとプラットフォーム



-ArduinoでのAtmega / AVR 16ビット16 MHz

-Arduino DueのSAM / ARM 32ビット84MHz

-PICKITMXファミリのPIC32MX / MIPS 32ビット80 MHz(PIC32MZ / MIPS 200 MHz-一部、動作中)



そして最後に、



step-dirインターフェイスを介したステッピングモーターによる回転:

-タイマーによるバックグラウンドで、STEPレッグのHIGH-> LOWエッジに沿ったステップに対して一定の矩形信号を生成します

-メインサイクルでは、シリアルポートを通じて回転方向を選択するコマンド(DIRピン)またはモーターを停止するコマンド(ENピン)をユーザーから受け取ります。



arduino-timer-api /例/ timer-api-stepper / timer-api-stepper.ino



 #include"timer-api.h" //       // Pinout for CNC-shield // http://blog.protoneer.co.nz/arduino-cnc-shield/ // X #define STEP_PIN 2 #define DIR_PIN 5 #define EN_PIN 8 // Y //#define STEP_PIN 3 //#define DIR_PIN 6 //#define EN_PIN 8 // Z //#define STEP_PIN 4 //#define DIR_PIN 7 //#define EN_PIN 8 void setup() { Serial.begin(9600); // step-dir motor driver pins //    step-dir pinMode(STEP_PIN, OUTPUT); pinMode(DIR_PIN, OUTPUT); pinMode(EN_PIN, OUTPUT); //      , //       //    . //      //   : // https://github.com/sadr0b0t/stepper_h // 1/1: 1500  // 1/2: 650  // 1/4: 330  // 1/8: 180  // 1/16: 80  // 1/32: 40  //   1/1 // =500, =2 //timer_init_ISR_500Hz(TIMER_DEFAULT); //  timer_init_ISR_200Hz(TIMER_DEFAULT); //   1/2 // =1, =1 //timer_init_ISR_1KHz(TIMER_DEFAULT); //  //timer_init_ISR_500Hz(TIMER_DEFAULT); //   1/4 // =2, =500 //timer_init_ISR_2KHz(TIMER_DEFAULT); //  //timer_init_ISR_1KHz(TIMER_DEFAULT); //   1/8 // =5, =200 //timer_init_ISR_5KHz(TIMER_DEFAULT); //  //timer_init_ISR_2KHz(TIMER_DEFAULT); //   1/16 // =10, =100 //timer_init_ISR_10KHz(TIMER_DEFAULT); //  //timer_init_ISR_5KHz(TIMER_DEFAULT); //   1/32 // =20, =50 //timer_init_ISR_20KHz(TIMER_DEFAULT); //  //timer_init_ISR_10KHz(TIMER_DEFAULT); ///////// //     // EN=HIGH to disable digitalWrite(EN_PIN, HIGH); //      Serial.println("Choose direction: '<' '>', space or 's' to stop"); } void loop() { if(Serial.available() > 0) { //     : int inByte = Serial.read(); if(inByte == '<' || inByte == ',') { Serial.println("go back"); //  digitalWrite(DIR_PIN, HIGH); // EN=LOW to enable digitalWrite(EN_PIN, LOW); } else if(inByte == '>' || inByte == '.') { Serial.println("go forth"); //  digitalWrite(DIR_PIN, LOW); // EN=LOW to enable digitalWrite(EN_PIN, LOW); } else if(inByte == ' ' || inByte == 's') { Serial.println("stop"); //  // EN=HIGH to disable digitalWrite(EN_PIN, HIGH); } else { Serial.println("press '<' or '>' to choose direction, space or 's' to stop,"); } } delay(100); } void timer_handle_interrupts(int timer) { //    HIGH->LOW digitalWrite(STEP_PIN, HIGH); delayMicroseconds(1); digitalWrite(STEP_PIN, LOW); }
      
      








All Articles