Simulink Support Package for Raspberry Piをmatlabにインストールをして、ラズパイ4のI2CバスにAdafruitのSCD30センサ・ボードを接続しました。
環境
- matlab home License R2022b update2
- Simulink Support Package for Raspberry Pi Hardware バージョン22.2.0
- Windows 10 Pro 22H2 メモリ40Gバイト
- Raspberry Pi 4 Model B 2MB
インストールは、次の記事を参照してください。
Simulink Support Package for Raspberry Pi ① インストール
動作確認
ライブラリを使わず(存在しない?)、レジスタをたたいてセンサのデータを得ます。下記のマニュアルを参照しました。
Sensirion_CO2_Sensors_SCD30_Interface_Description.pdf
動作を確認するため、CircuitPythonでアクセスしました。
CircuitPython 10行プログラミング Step9 (7) CO2センサSCD30
プログラム
IEEE754 単精度浮動小数点数の形式:binary32 の実数への変換
センサから読み取ったCO2、温度、湿度の値は、4バイトで構成されるbinary32の形式です。Pythonはstructのunpackで簡単に変換できます。
simulinkのfunctionでは、
matlab SimulinkのBLE functionを作ってみた その2 備忘録
でプログラムを実装しましたが、今現在、 extrinsic declarationsがエラーになってしまいます。そこで、ブロックを組み合わせて、サブシステムを作ります。
この実数表現は、メモリの中では32ビットの領域を使います。
- 符号ビット: 1ビット
- 指数部の幅: 8ビット
- 仮数部の幅: 23ビット
IEEE754 単精度浮動小数点数の形式:binary32 の変換
この記事にあるように、共用体unionを使う方法、ポインタを使う方法がありますが、どうも、matlabでは実現できないようです。
メーカのプログラムではunionを使っていました。
そこで、オーソドックスに、符号、指数、仮数をそれぞれ計算して、最後に掛け合わせて実数に変換する方法をとりました。
Arduinoだと、次のコードになります。iiがbinary32のデータです。
int8_t f = pow(-1, int(bitRead(ii,31)));
double k = 1 + (double)((((ii<<1)<<8)>>9))/pow(2,23);
float s = (float)pow(2,(int8_t)((uint8_t)((ii<<1)>>24)-127));
Serial.print("内部形式を実数に戻した ");Serial.println(f*k*s,6);
ほぼ、上記のスケッチを実装しました。
ウキ「単精度浮動小数点数」
も参考になります。
動作を確認して、サブシステムにしました。
メインのプログラム
左上から、順にパラメタを示します。
functionです。18バイトを読み取り、2バイトごとにCRCが入っているので、そこをスキップして、4バイトごとにデータをまとめています。
function [c,t,h]= fcn(u)
persistent c1;
persistent c2;
persistent c3;
persistent c4;
persistent t1;
persistent t2;
persistent t3;
persistent t4;
persistent h1;
persistent h2;
persistent h3;
persistent h4;
c1=u(1)*256*256*256;
c2=u(2)*256*256;
c3=u(4)*256;
c4=u(5);
c = uint32(c1+c2+c3+c4);
t1=u(7)*256*256*256;
t2=u(8)*256*256;
t3=u(10)*256;
t4=u(11);
t = uint32(t1+t2+t3+t4);
h1=u(13)*256*256*256;
h2=u(14)*256*256;
h3=u(16)*256;
h4=u(17);
h = uint32(h1+h2+h3+h4);
配置と実行順
試行錯誤していると、配置が乱雑になって、デバッグの情報のオーバーレイ、実行順序を実行すると、変な順番に並んでいることがあります。修正する方法がわからないので、あたらしい空のモデルを作り、順番にコピペしていきます。また、プロパティの優先順位も、順番に数値を振っておきます。
でも、readコマンドを送ったのに読み取りができないとかが起こることがあります。
I2Cバスの転送速度は100kHzですが、50kHzに変更する方法を見つけていません。SCLクロック・ストレッチは実装されているようですが、時々変なデータ(0xff)を読むのは、クロックが早いのが理由かもしれません。
I2Cバスでの確認
正しいデータが読めていませんが、シーケンスは正しい順番で実行されています。
このデバイス、ヒータがあるのが理由かもしれませんが、1か月ほど連続使用したら、読み出した値がおかしくなっていました。
その後、電源を入れて数分は正常な値が返えることが多くあります。壊れかけのようです。