google-site-verification: google3bd66dd162ef54c7.html

Raspberry Piでシリアルデータ受信

 久しぶりにうちのPaspberry Piを引っ張り出してきてシリアルのデータの読み取りをやってみました。

 私が好きな測定では、ハードに密着した部分はArduinoで処理した方がやり易いと思います。でも、人間とのインターフェイスはラズパイを使った方が断然有利になるはずです。うまくやればかっこいいグラフをWebサーバー経由で表示とかが簡単に出来ちゃうような気がします。

 ということで、ラズパイを使ったデーター加工の勉強を始めます。

 なお、以下の記事は、Chick Labさんの Raspberry Piでシリアル通信を参考、というかほとんどそのまま追試したものです。

 まずはUSBシリアル変換アダプタを使う方法。

 おなじみFDTIのUSBシリアル変換アダプタをRaspberry PiのUSBポートに接続してpythonで以下のプログラムを実行します。

import serial
import time

def main():
# USB:ttyUSB0
# GPIO:ttyAMA0
con=serial.Serial('/dev/ttyUSB0', 9600, timeout=10)
# con=serial.Serial('/dev/ttyAMA0', 19200, timeout=10)
print con.portstr
while 1:
str=con.readline()
print str
con.write(str)

if __name__ == '__main__':
main()

▼実行結果。プログラム名はusbSerialRead.pyです。
USBの仮想COMポートから受信
 このデーターは自作のグリッドタイインバーターが1秒間隔で吐き出しているもの。MPPTのレベルや電圧、電流などのデーターがだらだらと流れています。

 USBシリアルのアダプタが必要になりますが、コネクタを刺すだけで出来るのでお手軽な方法です。

 で次にやったのはGPIOコネクタのUART端子を使う方法。

 ラズパイの機能をちゃんと使うならこっちのやり方が王道なのでしょう。但し、この場合は配線する必要があります。Raspberry PiとArduinoでは信号のレベルが違うので抵抗でレベル変換も必要になります。

▼接続回路図(クリックで別窓に拡大)
raspberry pi でArduinokaranoシリアルを受信する回路
 こういう状態を説明するのには、回路図が一番だと思います。

▼Raspberry PiのGPIOコネクタ
Raspberry PiのGPIOコネクタへ配線
 熱収縮チューブの中にレベル変換回路の抵抗を入れています。

▼相手側
気圧高度計からシリアル出力
 これはこのあいだ作った高度計。

Pythonのプログラム

mport serial
import time

def main():
con=serial.Serial('/dev/ttyAMA0', 9600, timeout=10)
print con.portstr
while 1:
str=con.readline()
print str
con.write(str)

if __name__ == '__main__':
main()

▼実行結果 プログラム名は gpSerialRead.pyです
GPIOのURARTで受信
 気圧や標高などのデータが流れています。

 説明が後になりましたが、Raspberry PiはSSH経由のキャラクタベースで動かしています。また、シリアルポートはそのままではコンソールとして動作してしまうので修正が必要です。そのためにはこの記事に書いた以外にいろんな修正が必要になります。

 そのあたりは以下のWebを参考にさせていただきました。ありがとうございます。
Raspberry PiとArduinoでシリアル通信 (with Python)
Raspberry PiでUART、シリアル通信

LPS331を使った気圧高度計の製作、不具合解決

 形としては一応完成したものの、特定の気圧で針の位置が大きくばたつく現象が出ていましたが、ようやく解決することが出来ました。

▼アナログ表示の高度計
気圧高度計

 原因はセンサーの値をCPUで読む時に、一部のデータは1サイクル前の値を読んでいたようです。具体的には気圧は3バイトの値で表現されていますが、最上位の1バイトは1回前の値を読んでいたようです。

 センサーの値が変になるのは1008hPa付近。ここで下位16ビットが全部ゼロになって桁上がりが発生しますが、この時に値の取得がミスっていたので大きな誤差となって見えていたということのようです。ちなみにこの現象は16hPa間隔で発生するはずです。

 もちろんそういうことが起こらないように、センサーはワンショットモードで動作させ、センサーの状態表示ビットを見て変換完了を確認してから値の読み取りを行っています。更にBDU(ブロックデータ更新)ビットを立ててデータの不一致が発生しないように設定していたのですが、実際には問題が起きてしまいました。

 で、そういう問題を起こす引き金になったのがセンサーから値を読み出すこのコード。
 long x;                             // データーは24ビット
 x = LPS331read(0x2A); // MSB
 x = LPS331read(0x29) | (x << 8);
 x = LPS331read(0x28) | (x << 8); // LSB

 データーはリトルエンディアンで入っているので、アドレスの上位から逆順に読み出して24ビットに合成しています。余分な変数を使わないので気に入っていたやり方です。でもこうやると真っ先に最上位を読むことになるのでセンサー側で値の準備が間に合わなかったようです。

 そこで以下のように書き直して、LSB側から順に読んで最後にまとめて合成するように変更することで問題は発生しなくなりました。
  long x, x1, x2, x3;
x1 = LPS331read(0x28);
x2 = LPS331read(0x29);
x3 = LPS331read(0x2A);
x = (x3 << 16) | (x2 << 8) | x1; // 合成

 こういうアクセス方法にしないとダメ!とか、データーシートのどこかに書いてあるんでしょうか。全部ちゃんと読んでないです。汗; 

 ただこれだけでは対策として心配なので、念のためにセンサーの変換完了確認ビットが立ってから1msのディレイを入れ、その後データーを読むように修正しています。

 ということで、気圧高度計のスケッチ20140419版、たぶんこれが最終版。

 ついでに、このスケッチで少し面白いことをやっているので解説しておきます。それはsetup()の中の下記の部分。
  if(digitalRead(7)==HIGH){       // CWがoffなら通常点灯(onならWeak Pull Upで点灯)
pinMode(13, OUTPUT); // 測定表示
}

 pin13はArduinoではおなじみのLEDで、このスケッチではセンサーの動作表示に使っています。LEDなので普通はOUTPUTにして使いますが、これをif文でパスさせるとデフォルトである入力ピンに設定されたままになります。

 プログラムの中でLEDを点灯させたい時は、あちこちでdigitalWrite(13,HIGH)とやっているわけですが、これが入力ピンにアサインされていた場合はWeakPullUpされることになり、この場合LEDはプルアップ抵抗に流れる電流で暗く点灯することになります。

 つまり、if文を一行追加するだけでプログラム全体のLEDの明るさを指定する機能を作り込むことができます。別のスイッチにもCW/CCW動作表示LEDのpinModeを操作するようにしているので、LEDの明るさのパターンをいろいろ選択できるようになっています。

 この方法ではLEDを全く点灯させないようにすることは出来ません。でもリセット時のボタンの押し方の組み合わせでLEDの明るさを簡単に暗くすることが出来るので、覚えておくと役に立つと思います。
カレンダー
03 | 2014/04 | 05
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード