arduinoでハマりましたw

arduinoでハマったお話ですw
今回はarduinoを使用しない人にはあまり意味ないかもですw

ステップモーターのタイマー割り込みでハマりました~ww
色々書いていますがあまり面白くは無いので赤い文字の所だけ読めばオッケーですwww

今回NeoPixelっとステップモーターを共存させる上でステップモーターをタイマー割り込みで使用することにしました。
ステップモーターの可動自体はタイマー割り込みで意外とすんなり出来ました。
まっ、ここまでは良いのですが、正逆回転を繰り返すプログラムを入れて動かしてみるのですが1方向に回って終わってしまいます。

考えてみれば当たり前なのですが、以前在った待ち時間分がタイマー割り込みによってなくなったので実際にvector_upのコマンドはすぐ下のvector_dowのコマンドで消されちゃいますよねww
で、最終的に実際に動くのはvector_centerのコマンドのみになりますw

単発で動かす時は良いけど、連続して動かす時が問題になります。

そこで、連続可動時だけのモーターの動きが止まるまで待つための関数を作ってwhile()文を挿入してみました。

割り込み時に実行される関数はこちらです。

ステップの回数が終わったりリミットスイッチが押されるとタイマー内でstep_wait=1;が実行されwhile()分から抜け出しますよね!

ところがどっこい実行するとwhile()文が無視されちゃいますw
何故にこれで相当悩みましたが、以前マルチタスクの時に変数にvolatileを付けた事あったな~と思い出し

データー型をbyteからvolatile byteに変更してみました

するとこれで正常に機能するようになりました^^
while(step_wait==0){}がコンパイル時に要らない物との判断されていたようです^^;

実際、このwhile(step_wait==0){}の中にwhile(step_wait==0){engin_normal();}と待機中にNeoPixelの実行コマンドを入れるとvolatileを外しても正常に機能しましたw

さらにarduino特有のハマりもw

次にメインギアも可動で5秒のdelayが入っていますのでこれもタイマー割り込みにしないといけません。これはタイマーをカウントして5秒になったらモーターの電源供給が切れるようにすればいいので簡単。
ステップモーターの関係でタイマーは100μ秒毎に動いています5秒となると50000カウントしなければいけません。
という事で
int  mg_count
という変数を用意しました。これで動かしてみると一瞬の通電で終わりますww
どうも変なのでシリアルでmg_countの数字を確認してみるとなんかわけの分からないマイナスの数字になってるwwww

なんで??オバーフローしてる数字みたい???
intは4バイト最大値は2147483647、最小値は-2147483648だよね!!
で、相当ハマって色々調べるととんでもないことが発覚www
arduinoではintは2バイトで最大値は32767、最小値は-32768です!!
(32ビットであるESP32使用時は通常と同じ値です)

マジかよ初めて知ったww確かにそれなら50000は丁度超えてるねww

longに指定しなおすと正常に稼働するようになりましたw

まっ、そんなこんなが有りながらなんとかタイマー割り込みで全体の可動が確保できましたw

で、ネットをふらりと見ているとgyoさんもコメント欄で前回言っていたarduinoでの疑似マルチタスク用のライブラリーTimedActionやprotothreadsがあり、疑似的にタイマーを増やすMetro等色々とあるみたいですね~。ホントarduinoどこまで便利なんだよw

関連すると思われる記事:

8 comments

  1. おいしいネタが満載w
    volatileつけなあかんのはArduinoのコンパイラがいけてないっすね。グローバル変数でリードとライトがあるんだから。。。メインルーチンと割り込みルーチンを分割コンパイルしてるならいざ知らず、だけど。
    intとlongはお見事なり。正の値しか使わないならunsigned intという手もありまっせ。そこまでメモリをケチる必要はないだろうからlongがわかりやすくてよさそうですけど、メモリ容量に四苦八苦してプログラムしてた昔を思い出します(^^;

  2. なおさん こんばんは!
    はいはいwこんなマニアックなネタにコメント書く人は限られているからねww
    今回型式に結構悩まされましたよww
    いままでえさ、とりあえずintにしとけば大丈夫だろ~てなノリで考えた事少なかったですからねw
    volatileは以前ESP32のマルチタスクでやっていなければ絶対思いつかなかったw
    それに、arduinoではintの範囲がちがうなんて「聞いてないよ~~!」の世界ww
    そうだね~unsigned intもいけそうだけどそれでも6.5万辺りまでだからlongにしときましたw

  3. 結果だけ読んでると、なるほどねーって感じだけど、よく原因見つけましたね。
    自分だったらWhileのくだりはどこかで構文ミスしてるはずと思い込んで堂々巡りしそう。

    マニアックなコメントはなおさんとVividさんに任せたww

  4. こんばんは
    ちょっと複雑で、6jiroさんがやりたいプログラムの仕様がもう一つ理解できていません。(すみません)
    ステップモーターをタイマー割り込みでどの様に動作させたいのでしょうか、想像するに、
    ステップモーターを普通に駆動させておいて、たとえば5秒経過後、もしくはリミットSWが動作したら停止、もしくは反転させようという仕様でしょうか?
    それによっていろいろな対応が考えられます。差し支えなければご紹介ください。
    volatileの話は以前に聞いた記憶がありますが、いままで気にしてプログラミングしたことはありませんでした(笑)
    int型のバイト数はプラットフォームで変化しますから、落とし穴でしたね!

  5. gyoさん こんばんは!
    いぜんAtmelStudioの方で空のwhile文回したことあるのでどうにかたどり着けましたw
    もちろん何度も自分の構文おかしくないか確認もしましたwww
    最近は色々と経験積んできたので少しづつですが進歩してきてますよ(^_^)/

  6. Vividさん こんばんは!
    タイマー部分は100μ秒毎に次の関数を実行しています。
    void step_motor(){//
    t++;
    if( t==timer_speed){
    t=0;w^=1;
    if(w==1 && s==1){digitalWrite(vector_power,LOW);//LOWで動ける
    digitalWrite(vector_step,HIGH);}
    if(w!=1 && s==1) {digitalWrite(vector_step,LOW);}

    step_count++;

    }
    if (digitalRead(vector_limit)==0) {s=0;step_wait=1;step_count=0;
    digitalWrite(vector_power,HIGH);//電源供給ストップ
    }
    if(step_count>=timer_step*2){s=0;step_wait=1;step_count=0;
    digitalWrite(vector_power,HIGH);//電源供給ストップ
    }
    //————————————————–

    mg_count++;

    if(mg_count/10>=mg_time){digitalWrite(main_gear_up,LOW);
    digitalWrite(main_gear_down,LOW);
    }

    }
    これでステップモーターもDCモーターもNeopixelも同時に動かすことが出来るようになりました。
    ステップモーターはステップ数で、DCモーターを秒数で制御しています。
    ただ、タイマー割り込みになると連続でステップモーターを一杯迄動かして即反転させるためにはステップ数を完全に消化してもらわないといけないので、それを待つためのwhile文です。
    次のネタバレですが、こんな感じの動きです。
    https://youtu.be/wXKTMgLnts0

  7. (追記失礼します)
    volatile をどの様な時に使用すべきか調べてみました。
    gloval 変数を定義して、それを通常の関数や、timer 割り込み関数でも使用するばあいに、その変数の値が破棄されない様に volatile を付けて宣言する必要があるようです。(たぶん)

  8. Vividさん こんばんは!
    調べて頂いたようで感謝です<(_ _)>
    私もそんな感じの文章を以前読んだ気がしていたのと、やはり以前やったESP32のマルチタスクの際に使ったのを覚えていたので何とかいけましたw

Leave a Reply

メールアドレスが公開されることはありません。

wp-puzzle.com logo