C-Styleで割り込み(その3)
次のような無条件ループでプログラムする場合、ループ内で時間のかかる処理があると、センサ値を読むタイミングによっては、センサ値の変化に気づかない場合がある。
内部で50ミリ秒の時間がかかる処理があるとセンサ値を読むタイミングは50ミリ秒ごとになる。
センサ値を読んだ後の10~30ミリ秒でセンサ値が変化終了すると、次のセンサ値を見たときには変化が読み取れない。
そこで、時間のかかる処理とは別に、割り込み内でセンサ値の変化をチェックすることで読み飛ばしを防ぐ。
センサ値が大きくなる変化を読み取る場合は、次のような感じでセンサ値の最大値(グラフでは点線)を保存しておけば読み飛ばしを防げる。
- メインプログラム側でセンサ保存値をリセット
- 割り込み内でセンサ値をチェックし、センサ保存値より値が大きければ、センサ保存値を更新
- メインプログラム側でセンサ保存値を使って処理
- (以下繰り返し)
自走するロボットが秒速1mで進む場合、50ミリ秒で5cm進む。
- 秒速1mとは
- 1秒で1m (1000ミリ秒で1000mm)
- 0.1秒で10cm (100ミリ秒で100mm)
- 0.01秒で1cm (10ミリ秒で10mm)
処理に時間のかかる超音波センサなどを使う場合、その処理中にセンサ値の変化が終わり、変化を読み飛ばすことは十分考えられる。
C-Styleで割り込み(その2)
割り込みをもう少しテストしてみる。
超音波センサ(PING)は超音波を使い距離を測る。
超音波も音なので、音速を超えた処理はできず、一般的に超音波センサは遅い。
ja.wikipedia.org
センサから出た超音波が1m先の何かに反射して戻ってくる場合、往復で2m。
音速を340m/sとしたとき、2mの往復にかかる時間は約0.0059秒=5.9ミリ秒。
ja.wikipedia.org
C-StyleでPINGを使う場合にかかる時間と割り込み処理について、次のプログラムで確認する。
メインプログラムでは以下を行う。
- 変数A、Bの初期化
- タイマー1を使い、1秒間のループ
- ループ内で
- PING計測し変数Cに代入、
- 計測回数を変数Bでカウント
- 1秒のループ後に、変数A、B、Cを表示
- 変数Cは1秒間のループ中の最後に計測したPINGの値となる
割り込みで処理されるサププログラムでは
- サブプログラム実行回数を変数Aでカウント
結果は次の通り。今回PINGは未接続だったため、変数Cは0となった。
PING処理は割り込みに比べると相当遅い事がわかる。
C-Styleで割り込み
C-Styleで割り込みができるようになった。
ja.wikipedia.org
使い方は新しいマニュアル「C-Style 操作編」に追記されている。
割り込み処理中に実行できないこととして「モータ、PING、サーボモータ、I2C 等の制御」が挙げられているが、割り込みタイミング等の記載はないので調べてみる。
サンプルプログラムは次の通り。
メインプログラムでは以下を行う。
- 変数Aの初期化
- 無条件ループ内での赤1LEDの点滅
- タイマー1を使った1秒の待機
- 変数Aの表示(C-Codeブロックで「printf("%ld\r\n", gV[VAR_A]);」)
割り込みで処理されるサププログラムでは
- 赤3LEDの点灯
- 変数Aの加算。サブプログラム実行ごとに1づつ増える。
- タイマー1を使い、0.5秒ごとに赤2LEDの点滅
このプログラムで以下が確認できる。
- 赤LED3がONになるタイミングが、割り込み処理の初回実行タイミング
- 割り込み処理とメインプログラムで変数、タイマーがが共有できるか
- 変数Aを表示することで、1秒間に実行される割り込み処理の回数
変数Aを確認するにはセンサーモニタを使う。
手順は次の通り。
センサモニターのタイトル付近「センサモニタ & 出力チェック」をダブルクリック。
センサモニターのウィンドウが拡大したら、モニタ開始。
モニタ開始すると、各CNの値が表示されるので、TJ3BをSTARTさせる。
変数Aが表示され始める。
ロボット作りには欠かせない機能だと思う。
アナログジャイロセンサーについて(その7)
モニタ表示があれば、センサーの値を使ったプログラムのデバッグが容易になる。
I2C接続のモニタだと結線も容易にできる。
動画で使っているOLEDはこちら。ドライバICがSSD1306のもので、AdafruitのArduino用SSD1306ライブラリを使うことで簡単に利用できる。
- I2C シリアルOLED液晶ディスプレイモジュール 128x32
- GitHub - adafruit/Adafruit_SSD1306: Arduino library for SSD1306 monochrome 128x64 and 128x32 OLEDs
- 基板サイズは秋月D型
- Arduino ProMicro(互換品)
- MPU-6050
- OLEDの下にDAC(MCP4726)
loop()内では、毎周ではなく、適当な周回(動画では50周ごと)で画面を更新し、三角関数を使い図形を作成している。
int x1_, y1_, x2_, y2_, x3_, y3_; float x1, y1, x2, y2, x3, y3; float sn, cs; sn = sin(- 3.14 * mydeg / 180); cs = cos(- 3.14 * mydeg / 180); x1 = 0; y1 = 15; x2 = -4; y2 = -15; x3 = 4; y3 = -15; x1_ = (int)(x1 * cs - y1 * sn) + 16; y1_ = (int)(x1 * sn + y1 * cs) + 16; x2_ = (int)(x2 * cs - y2 * sn) + 16; y2_ = (int)(x2 * sn + y2 * cs) + 16; x3_ = (int)(x3 * cs - y3 * sn) + 16; y3_ = (int)(x3 * sn + y3 * cs) + 16; display.drawLine(x1_, y1_, x2_, y2_, WHITE); display.drawLine(x2_, y2_, x3_, y3_, WHITE); display.drawLine(x3_, y3_, x1_, y1_, WHITE);
三角関数が理解できれば、プログラムの幅も広がるので、良くわからない方には以下をオススメ。
- 作者: 結城浩
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2014/04/24
- メディア: 単行本
- この商品を含むブログ (12件) を見る
一連のブレッドボードのイメージはFritzingで作成した。
Fritzingでは独自のパーツも作成できる。
(ProMicroのMicroUSBコネクタがもげたので、おわり)