mbed触りだしてみました
使いやすいですmbed。オンラインIDEで使いたいボードなりチップを選ぶとピン配置図が出て配線が簡単に確実にできます。とても賢い人達が作っているのがわかります。某マイコンボード陣営が内部分裂でグダグダやってる内に嫌気が差してmbedに移るユーザもいるのではないでしょうか。
触ってるのはこれ
www.switch-science.com
BTつきのモノとかいくつか買ってみたのですが、いま私が主に触ってるのはLPC1114FN28です。プログラムをアップロードした後は石だけ取り出して電源を与えるだけでも動き出すという素敵な構成で、石単体なら200円ちょっとで手に入ります。すごい。
PocketGeiger Type5をつないでみる
mbedに慣れる目的で、PocketGeiger Type5をLPC1114FN28につないで放射線センサデータを取れるかどうか試してみました。といっても、arduino用のコードがすでにRadiation-Watch.orgから入手できるので、移植は私程度のクズでも簡単にできるはずです。
オンラインIDEでLPC1114FN28を選んでPinoutを見てみると、dp25とdp26が空いているのでこれらをデジタル入力として使うことに決めました。PocketGeiger Type5からは信号線として放射線検出信号とノイズ信号の二本がデジタル出力として出ており、これらを取り扱う必要があります。
arduinoのソースはほぼプログラミング言語Cそのものですが、以下の三点がarduino独自の方言です。
- ピン設定
- シリアル通信
- タイマー
この方言をmbed用のCに翻訳するだけで移植は完了します。
1. ピン設定(と読み取り)
これは簡単です。
arduinoの
//設定
//信号検出ピンの設定
pinMode(signPin,INPUT);
digitalWrite(signPin,HIGH);
//ノイズ検出ピンの設定
pinMode(noisePin,INPUT);
digitalWrite(noisePin,HIGH);
//読み取り
// 信号のローデータ 通常:High 検出時:Low
int sign = digitalRead(signPin);
// ノイズのローデータ 通常:Low 検出時:High
int noise = digitalRead(noisePin);
をmbedでは
//設定
DigitalIn signPin(dp25);
DigitalIn noisePin(dp26);
signPin.mode(PullUp);
noisePin.mode(PullUp);
//読み取り
// Raw data of Radiation Pulse: Not-detected -> High, Detected -> Low
int sign = signPin;
// Raw data of Noise Pulse: Not-detected -> Low, Detected -> High
int noise = noisePin;
と書きます。mbedは関数すら呼ばずにピンの状態を変数に直接代入しているようにみせてます。すごい。
2. シリアル通信
これも簡単です。
arduinoでは
Serial.begin(9600);
//シリアルで送信
Serial.println(msg);
などとしますが、mbedでは
Serial pc(USBTX, USBRX); // tx, rx
pc.puts(msg);
pc.puts("\r\n");
などとします。\rを付けずに\nだけ付加しているmbedプログラムをよく見かけますが、多くの環境(というかシリアル通信端末プログラム)で\rがないと改行後に左端にカーソルが移動せずに出力が乱れてしまいます。
3. タイマー
これも簡単。
arduinoでは
//現在の時刻を取得
currTime = millis();
ですが、mbedでは
Timer t;
t.start();
currTime = t.read_ms();
とすれば一対一対応します。
動かしてみたが、止まる。
移植はすぐ終わったのですが、いざ動かしてみると短時間で動作を停止してしまうことがわかりました。どうやらノイズピンに信号があると動作停止するようです。移植元のarduinoのソースコードを真面目に読んでみたところ、怪しげな部分を見つけました。
//10000回ループを回ったら、計測値を計算して、シリアルで出力する
if(index==10000) //Arduino Nano(ATmega328)で160-170ms程度
{
//省略
//ノイズが10000回のループの中でまったく検出されないとき
//ノイズが検出されたときは、処理をしない
if(noiseCount == 0)
{
//省略
//シリアルで送信
Serial.println(msg);
index=0; // <-えっ???ここで?
}
// 省略
}
index++;
つまり、ノイズがない時だけ、indexが正常に0に初期化されるロジックになっているので、ノイズがあるとindexが初期化されずに増加しすぎておかしな挙動につながる、と思われます。よって
if(noiseCount == 0)
{
//省略
//シリアルで送信
Serial.println(msg);
//index=0; // <-ここをやめて
}
index=0; // <- ここにする
としました。これでmbedでも正常に動作し続けることを確認できました。
なぜarduinoでは問題が起こらないのか?
起きてるような気もしますが、とりあえずわかりません。intのサイズの違いかなあ。
追記(2015/05/05)
Radiation-watch.orgの問い合わせフォームから、上記のコード部分について質問してみたところ、やはりバグであることが判明しました。現在ダウンロードできるarduinoコードは修正済みのものなので、もし現在古いコードを使っている方は新しいもので置き換えることをお勧めします。ノイズピンに信号があった場合の計測値の精度が若干向上します。
arduinoで問題が起こらなかった理由も、Radiation-watch.orgのご担当の方の説明で判明しました。arduinoのintが2バイトであるため、index変数の初期化に失敗しても短時間でオーバーフローして、ある意味で勝手に再初期化が行われるために明確なバグとして発覚していなかったというのが真相です。mbedはintが4バイトなので、オーバーフローまでarduinoの65535倍の時間がかかるために、動作が止まったことがハッキリと認識できたわけです。私がもし賢かったら、移植の際にintのサイズを合わせるためにmbedではshort intを使っていたはずで、その場合はバグが発覚することもなかったでしょう。バカで良かった。
コード
改変部分をあえてコメントとして残してある部分もあります。
まとめ
mbedすげー。