GR-SAKURA
GR-KURUMI
GR-COTTON
GR-CITRUS
GR-PEACH
GR-KAEDE
GR-ADZUKI
GR-LYCHEE
GR-ROSE
GR-MANGO(*)
SNShield
Web Compiler
IDE for GR
TOPPERS関連
女子美コラボ
その他
※プロデューサミーティング中
作り方使い方資料
イベント関連
作品記事
体験記事
ライブラリ
ツール
その他・過去ファイル
1msecごとに呼ばれる自前の関数を追加する方法です。
timer_regist_userfunc( )を使えば簡単に実現できます。
timer_regist_userfunc( )を2回呼ぶと後から呼んだものが有効となります。
ですから、2種類の関数は同時に定義できません。
下記のプログラムは gCountFunc1msec のグローバル変数を1msecごとにカウントアップします。
カウントした値をメインループ内でシリアル出力する、単純なものです。
digitalWrite( 7, 1 ); と digitalWrite( 7, 0 ); で端子7の波形を観測して、シリアル出力にかかる時間
を計ってみました。約12usecでした。
しかし、時間が結構かかるので1msecの関数内では処理させないほうがよいでしょう。
/*GR-SAKURA Sketch Template Version: V1.01*/
#include <rxduino.h>
#define D_INTERVAL 100
#define D_SERIALPORT SCI_USB0 // USB仮想com
// 追加する関数
void timerFunc1();
int gCount;
int gCountFunc1msec;
void setup()
{
// LED設定
pinMode( PIN_LED0, OUTPUT );
pinMode( PIN_LED1, OUTPUT );
pinMode( PIN_LED2, OUTPUT );
pinMode( PIN_LED3, OUTPUT );
pinMode( 7, OUTPUT );
digitalWrite( 7, 0 );
// デバッグシリアルの初期化
Serial.begin( 38400, D_SERIALPORT );
Serial.println( " " );
gCountFunc1msec = 0;
timer_regist_userfunc( timerFunc1 );
}
void loop()
digitalWrite( 7, 1 );
// カウンタの表示
Serial.print( "count = " );
Serial.print( gCountFunc1msec );
// LED0を点滅表示
if ( (gCount & 0x8) == 0 )
digitalWrite( PIN_LED0, 0 );
else
digitalWrite( PIN_LED0, 1 );
gCount++;
delay( D_INTERVAL );
// この関数内は必ず1msec以下で終了する処理を書く
// Serial.printなどデバッグ用出力は避けた方がよい
void timerFunc1()
gCountFunc1msec++;
1.001msecごとに呼ばれる自前の関数を追加する方法です、というか任意の周期ごとに呼ばれる自前の関数を追加する方法です。
TMR0とTMR1を連結して16bitモードで使用しています。
以前はtimer_regist_userfunc( )を使用して、CMT0.CMCORを操作したりしていたのですが、CMT0はシステムのタイマとして1msec周期以外にも使用しているとのことで、どうもよろしくなさげな感じなので、他の方法を試してみました。
/*GR-SAKURA Sketch Template Version: V1.01*/ #include <rxduino.h> #include <iodefine_gcc63n.h> #define D_INTERVAL 100 #define D_SERIALPORT SCI_USB0 // USB仮想com // 追加する関数 void timerFunc1(); extern "C" void Excep_TMR0_CMIA0(void) __INTTERUPT_FUNC; int gCount; volatile int gCountFunc1msec; volatile int gCountFunc1001usec; void setup() { // LED設定 pinMode( PIN_LED0, OUTPUT ); pinMode( PIN_LED1, OUTPUT ); pinMode( PIN_LED2, OUTPUT ); pinMode( PIN_LED3, OUTPUT ); pinMode( 7, OUTPUT ); digitalWrite( 7, 0 ); // デバッグシリアルの初期化 Serial.begin( 38400, D_SERIALPORT ); Serial.println( " " ); gCountFunc1msec = 0; gCountFunc1001usec = 0; timer_regist_userfunc( timerFunc1 ); const int PCLK = 48000000; const int TMR01usec = 1001; MSTP(TMR0) = 0; // TMR01 有効化 TMR1.TCCR.BYTE = 0; // TMR1 クロック入力を禁止 TMR0.TCCR.BIT.CSS = 0b11; // TMR0 TMR1.TCNTのオーバフロー信号でカウント TMR01.TCNT = 0; // タイマカウンタを0に初期化 TMR0.TCR.BIT.CCLR = 0b01; // コンペアマッチAによりクリア TMR0.TCR.BIT.CMIEA = 1; // コンペアマッチAによる割り込み要求(CMIAn)を許可 IEN(TMR0, CMIA0) = 1; // CMIA0を許可 IPR(TMR0, CMIA0) = 1; // 割り込みレベル1 TMR01.TCORA = TMR01usec * (PCLK / 8 / 1000000) - 1; TMR1.TCCR.BYTE = 0b01010; // TMR1 分周クロックPCLK/8 } void loop() { digitalWrite( 7, 1 ); // カウンタの表示 Serial.print( "count = " ); Serial.print( gCountFunc1msec ); Serial.print( ", " ); Serial.print( gCountFunc1001usec ); Serial.println( " " ); digitalWrite( 7, 0 ); // LED0を点滅表示 if ( (gCount & 0x8) == 0 ) { digitalWrite( PIN_LED0, 0 ); } else { digitalWrite( PIN_LED0, 1 ); } gCount++; delay( D_INTERVAL ); } // この関数内は必ず1msec以下で終了する処理を書く // Serial.printなどデバッグ用出力は避けた方がよい void timerFunc1() { gCountFunc1msec++; } // この関数内は必ず1.001msec以下で終了する処理を書く // Serial.printなどデバッグ用出力は避けた方がよい void Excep_TMR0_CMIA0(void) { gCountFunc1001usec++; }
ビルドの際には、gr_common/intvect.c の中の1500行辺りにある
void Excep_TMR0_CMIA0(void){ }
の行をコメントアウトか削除してください。
以上の投稿は、タイマ割込みを利用したいのですが上手くいきませんのスレッドを参考にしております。tursさん、Ryuji Naitou(なひたふ)さん、鈴木康之さんに感謝致します。
あるタイミングで呼ばれて、呼ばれた関数内の処理時間は不定で、その関数が終了するときに、次に自分を呼び出すタイミングをセットして終了するような処理を書きたいときは、どのように書けばいいのでしょうか?
例えば、
setup()で、
をセットして、
timer_init();
~ 1ms以上の処理処理 ~
このように書いても、処理中にハングアップしてしまうようです。
よろしくお願いします。
この方法はどうでしょうか。かなり近い事ができると思うのですが。
hamayan.blog.so-net.ne.jp/2012-12-27
試しに書いてみました。
取り敢えずのところは動いているようなのですが、delayMicroseconds()を呼び出すと止まる謎の現象が確認されています。まあ参考程度ということでお願いします。
/*GR-SAKURA Sketch Template Version: V1.02*/ #include <rxduino.h> #include <iodefine_gcc63n.h> static const int PCLK = 48000000; // 周辺モジュールクロック // 追加する関数 extern "C" void Excep_TMR0_CMIA0(void) __INTTERUPT_FUNC; // 割り込み間隔(1000~9000μ秒)を返す static int getInterval() { static double theta = 0.0; int interval = 5000 + int(4000.0 * sin(theta)); theta = fmod(theta + M_TWOPI / 100.0, M_TWOPI); return interval; } // delayMicroseconds()の代替(中身はテキトー) static void myDelayMicroseconds(unsigned long w) { w <<= 4; while (w--) { __asm__ volatile ("nop\n\tnop\n\tnop\n"); } } void setup() { // 初回の割り込みタイミング int interval = getInterval(); // LED設定 pinMode(PIN_LED0, OUTPUT); pinMode(PIN_LED3, OUTPUT); // TMR01設定 MSTP(TMR0) = 0; // TMR01 有効化 TMR1.TCCR.BYTE = 0; // TMR1 クロック入力を禁止 TMR0.TCCR.BIT.CSS = 0b11; // TMR0 TMR1.TCNTのオーバフロー信号でカウント TMR01.TCNT = 0; // タイマカウンタを0に初期化 TMR0.TCR.BIT.CCLR = 0b01; // コンペアマッチAによりクリア TMR0.TCR.BIT.CMIEA = 1; // コンペアマッチAによる割り込み要求(CMIAn)を許可 IEN(TMR0, CMIA0) = 1; // CMIA0を許可 IPR(TMR0, CMIA0) = 1; // 割り込みレベル1 TMR01.TCORA // タイムコンスタントレジスタA = (unsigned short)(interval * PCLK / 8 / 1000000) - 1; TMR1.TCCR.BYTE = 0b01010; // TMR1 分周クロックPCLK/8 } void loop() { } // 割り込み処理 void Excep_TMR0_CMIA0(void) { // TMR01停止 TMR1.TCCR.BYTE = 0; // TMR1 クロック入力を禁止 // 次回の割り込みタイミング(1000~9000μ秒) int interval = getInterval(); // なんかの処理(およそ9000~1000μ秒) int jobTime = 10000 - interval; digitalWrite(PIN_LED0, HIGH); digitalWrite(PIN_LED3, LOW); myDelayMicroseconds(jobTime); // delayMicroseconds()ではうまくいかんかった digitalWrite(PIN_LED0, LOW); digitalWrite(PIN_LED3, HIGH); // 次回の割り込みタイミングを設定 TMR01.TCNT = 0; // タイマカウンタを0に初期化 TMR01.TCORA // タイムコンスタントレジスタA = (unsigned short)(interval * PCLK / 8 / 1000000) - 1; TMR1.TCCR.BYTE = 0b01010; // TMR1 分周クロックPCLK/8 }
@chobichan様、
紹介、ありがとうございます。
内容が私には高度そうなので、先ず、良く理解したいと思います。
fujita nozomu様、
サンプルありがとうございます。
私も同様なサンプルを試していました。割り込み関数内で、テスト的にディレイを入れようと思って、delay()やdelayMicroseconds()を入れていたのですが、そこでハングアップしてしまうので、根本的に間違っているのかなと思っていました。
割り込み先で、カウンタを止めて、処理が終わるときに再度割り込みをセットするという考え方はあっているのですね。
本当にやりたいことは、BlueTooth処理を一定のインターバルで呼び出したいのです。
もう少し、頑張ってみます。
GR-SAKURAのライブラリv2では、タイマー系は、対応どうなってるんでしょうか?
V2 では MsTimer2 が使える筈です。
fujita nozomu さん、有難うございます。
使い方が、どこかに載ってますか?
SAKURAスケッチリファレンスに載ってないみたいなので、Arduino.cc のここですかね。
www.musashinodenpa.com/.../index.php;pos=2021
有難うございます。グローバル関数として、よび出すのですね。試してみます。
下記で、動きました。
#include <MsTimer2.h>
MsTimer2::set( (1000 * 60), cyclicFunc );
MsTimer2::start();
有難うございました。
Template V2.04でも動作しました。これは、使い勝手いいですね。
Kurumiでも、使えるのでしょうかね?
/* GR-SAKURA Sketch Template V2.04 */
#include <Arduino.h>
void cyclicFunc() {
static boolean output = 1;
digitalWrite(PIN_LED0, output);
output = !output;
pinMode(PIN_LED0,OUTPUT);
MsTimer2::set( 500, cyclicFunc );
KURUMIでは別の1ms interval timerを用意していたので実装してないですが、ソースは共有できた方がいいですからね。次の機会に検討いたします。
> Kurumiでも、使えるのでしょうかね?
GR-KURUMI 用に簡単な実装をしてみました。
http://japan.renesasrulz.com/gr_user_forum_japanese/f/110/p/2534/13687.aspx#13687