Arduino Nano R4の活用 ⑦ I2C LPS22HBのスケッチ スケッチの説明<第3回>

  前回、I2Cバスの利用例で気圧センサのLPS22HBをつないで、気圧を読みだすスケッチを作りました。そのスケッチを説明します。

   Arduino Nano R4の活用 ⑥ I2C LPS22HB Wire①

環境

  • Arduino IDE;2.3.5
  • Windows11;24H2
  • Arduino Nano R4 1.5.1 PCはマザーボードのUSBポートから直接つなぐ。

グローバル変数

 LEDの点滅やスイッチ入力では、一度だけ実行する setup() と繰り返す loop() の二つのブロックがありました。

 このWireの応用例では、最初の部分に、その二つの関数の外に記述があります。

#include <Wire.h>
 
 Wireライブラリを利用するためにライブラリをincludeしています。
 
unsigned char LPS22HB_address = 0x5d;
 
 I2Cでは、デバイス(センサなど)を複数つなげられますが、それぞれを区別するために固有のアドレスを持っています。デバイスによっては変更できるものもありますが、製品自体に一つのアドレスが固定されていることもあります。
 ここでは、LPS22HBのアドレスが0x5dだと記述しています。変数の記述ですが、このアドレスはスケッチ全体を通して変化することはないので、定数(じょうすう)として記述すことが望ましいです。
 その場合の記述は次の通りになります。
 
  const unsigned char LPS22HB_address = 0x5d;
 
  気圧のデータは3バイト分あるので、配列でその読み出したデータ3個を収納できるようにします。
 
byte result[3];
 
 これらが、最初に書いてある場所はグローバル領域と呼ばれます。スケッチ全体で利用できる変数や配列、定数になります。
 グローバルに対するのはローカルです。関数の中だけや、forループの中だけで利用する変数などはローカル変数と呼ばれ、別の関数やfor文からは独立しています。宣言された関数の中でのみで利用できます。
 
 グローバル変数は、どこでも読み書きができるので便利です。しかし、スケッチが大きくなったり、分割して関数を記述すると、全く同じ名称の変数を複数個所で宣言したりすることがあって、トラブルの原因になります。世の中の巨大なプログラム開発ではグローバル変数の宣言は好まれません。
 しかし、スケッチがほとんどが短いので見通しもよく、Arduinoでは利用することが多いです。
 
 

setup()

 二つの処理が記述されています。

 一つはWire関係、もう一つは後半のSerial関係です。Serial関係はシリアルモニタの通信にかかわるもので、前回のスイッチのスケッチでも出てきました。

  Arduino Nano R4の活用 ⑤ スイッチ入力のスケッチ スケッチの説明<第2回>

Wire.begin();
 
 Wireライブラリを使い始める記述です。初期化などが行われます。

    Wire.beginTransmission(LPS22HB_address);
        Wire.write(0x10); Wire.write(0x10); //1Hz
    Wire.endTransmission();
 

 I2Cバスのデバイスに書き込みを行う記述です。最初の1行目では、デバイスのアドレスを指定して、これから書き込みを始めるとしています。ここに書かれたアドレスのデバイスだけが、以降のやり取りをします。

 2行目は、実際の書き込みです。ここでは2回書き込みを行っています。普通のI2Cバスでは8ビット単位になります。

 最初の書き込みは、LPS22HBのコントロール・レジスタ1であるCTRL_REG1(0x10)の値を書き込みます。次の書き込みは0x10を書き込みます。

 具体的には、LPS22HBのコントロールレジスタに繰り返しが1Hzになるようにレジスタに設定をしてもらいました。このセンサは電源がONもしくはリセット後はスリープしています。この1Hzの設定をすることで活動を始めます。1Hz以外にも設定は可能です。データシートを参照してください。

 どちらもたまたま同じ0x10ですが意味が異なります。

 最後の3行目では書き込みは終了だという記述です。

    Serial.begin(9600);
    delay(1000);
    Serial.println("start ");

 これら3行は、シリアル通信を利用できるようにしてstartというメッセージを送ります。メッセージは、IDEの下のブロックのシリアルモニタに表示されます。

loop()

    Wire.beginTransmission(LPS22HB_address);
        Wire.write(0x28 | 0x80);
    Wire.endTransmission();
 
 LPS22HBに0x28 | 0x80という値を書き込みます。データシートによれば、気圧データは24ビットで、その最小バイトが保存されているレジスタのアドレスが0x28です。0x80とビット論理和を取っているのは、最上位ビットを強制的に1にするためです。
 最小バイトを読みだすためだけなら0x28だけでよいのです。0x28を書き込んで1バイトを読みだす、次は真ん中のバイトを読みたいので0x29を書き込んで読みだす、最後の最上位バイトを読み出したいので、0x2aを書き込んで読みだすという記述をするのが標準的な方法です。
 しかし、多くのセンサでは複数バイトを読みだすとき、最小バイトが入っているアドレスを指定した後、連続して読みだすと、勝手にレジスタのアドレスがインクリメントされて記述が簡単ですっきりするという事例が多くあります。
 

 
 このLPS22HBでもそうしたいのですが、自動インクリメントの機能がoffになっているようで、onにするには最上位ビットを1にするように、データシートに書かれています。と思って確認したのですが、間違っていました
 最上位ビットを強制的に1にしないといけないのは類似の気圧センサLPS25HBでした。最初にこのデバイスを使っていて、LPS22HBもそのプログラムを流用したので、0x28 | 0x80という記述にしていただけでした。
 
Wire.write(0x28);
 
の記述で問題ありませんでした。
 
 
    Wire.requestFrom(LPS22HB_address, 3);
    result[0] = Wire.read();
    result[1] = Wire.read();
    result[2] = Wire.read();
 
 3バイトを読み出し、配列に収納します。
 
    float press = (result[2]<<16 | result[1]<<8 | result[0]) / 4096.0;
 
 三つのデータを24ビットのデータに並べます。byteデータを左にシフトすると消えてしまいそうですが、問題なく24ビットデータになりました。それをデータシートに書かれているように、4096で割ると、hPaの値が得られます。
 
 
 
    Serial.print(result[0]);Serial.print(" ");
    Serial.print(result[1]);Serial.print(" ");
    Serial.print(result[2]);Serial.print(" ");

    Serial.println(" press= "+String(press,1)+"hPa");
 
 読みだした値と気圧の値をシリアルモニタに送ります。
 
新しいスケッチ
 スケッチの中に0x10などを直接書いても問題はないのですが、複数の場所でその変数名が使われていると、エディタで変更していると間違いが混入することがあります。そういう場合、先頭のエリアで、変数名と数値の対応を書いておくと、修正が楽です。
 #defineの3行が修正したところです。
#include <Wire.h>
const unsigned char LPS22HB_address = 0x5d;
byte result[3];
#define CTRL_REG1 0x10
#define Output_data_rate 0x10  //1Hz
#define PRESS_OUT_XL 0x28

void setup() {
    Wire.begin();
    Wire.beginTransmission(LPS22HB_address);
        Wire.write(CTRL_REG1); Wire.write(Output_data_rate); 
    Wire.endTransmission(); 
    Serial.begin(9600);
    delay(1000);
    Serial.println("start ");
}

void loop() {
    Wire.beginTransmission(LPS22HB_address);
        Wire.write(PRESS_OUT_XL);
    Wire.endTransmission(); 
    Wire.requestFrom(LPS22HB_address, 3);
    result[0] = Wire.read();
    result[1] = Wire.read();
    result[2] = Wire.read();
    float press = (result[2]<<16 | result[1]<<8 | result[0]) / 4096.0;

    Serial.print(result[0]);Serial.print(" ");
    Serial.print(result[1]);Serial.print(" ");
    Serial.print(result[2]);Serial.print(" ");

    Serial.println(" press= "+String(press,1)+"hPa");

    delay(3000);
}
 

前へ

Arduino Nano R4の活用 ⑥ I2C LPS22HB Wire①