PICを使って、加速度、角速度をBMX055から読み出すプログラムを作ってみた
2023/05/28
秋葉原の秋月電子で、「BMX055使用9軸センサーモジュール」というものがあった。
このBMX055というのはナント!!、あの有名なBOSCH社のICで、それを使ったモジュールなのである。
特に最近はドローンなどに使われているものだそうで、なかなか興味深いものなのである。
そのモジュールがせいぜい1680円で手に入るということなので、早速秋葉原に出向いて買ってきた。
さて、どうなるのであろうか?
ネット上には「Arduino」とか「RaspberryPi」と組み合わせて使ったものが出ており、割と簡単そうなことが書いてある。
そうかそうかと、気軽にPICでも読み込めるかと思ったら、そう簡単なものではなかった。
今回は加速度と角速度の読み込みをやってみた。
磁気データも取り込めるのだが、どうもどう使ったらよいか判らなかったので、磁気データは取り込まなかった。
ただ、やり方はアドレスとデータの長さが違うだけなので、必要となればすぐに出来るとは思うのである。
まずは、ジャンパーピンの4と5をハンダで導通させ、I2Cの信号線をプルアップする。
私が作る回路には、LCDがもう付いており、I2Cで通信しているので、本来はプルアップは不要なのだが、テストでLCDを外したりするので、一応やっておく。
もう一つはJ6ピンで、これは電源と、信号のレベルを両方共5Vにする設定にする。
PICは相変わらずPIC18F4550で5V動作である。
I2C通信のプログラムは、LCDのテストで使用したものをそのまま使用している。
ただ、LCDのときはデータの書き込みのみだったのが、今回はセンサーからのデータを受け取るルーチンが追加になる。
その部分のI2Cのヘッダー
#include // include processor files - each processor file is guarded.
void I2C_Master_Init(void);
void I2C_Master_Wait(void);
void I2C_Master_Wait2(void);
void I2C_Master_Start(void);
void I2C_Master_ReStart(void);
void I2C_Master_Stop(void);
void I2C_Master_Write(unsigned d);
unsigned char I2C_Master_Read(unsigned char a);
#define _XTAL_FREQ 48000000 // 使用するPIC等により動作周波数値を設定する
// 水晶は20MHzでPLLで48MHz動作
I2C通信のデータの受け取りルーチンを追加
unsigned char I2C_Master_Read(unsigned char ack)
{
unsigned char temp;
I2C_Master_Wait();
RCEN=1; //Enable reception in Master device
I2C_Master_Wait();
temp = SSPBUF; //Read data from SSP1BUF
I2C_Master_Wait();
ACKDT = ack; //Acknowledge bit 1:NACK 0:ACK
ACKEN = 1; //Acknowledge sequence
return temp; //return received data
}
BMX055のI2C通信は、デフォルトのアドレスが、加速度は0x19、ジャイロが0x69なのであるが、なかなかうまく動作してくれなかった。
しかたなく、BMX055のマニュアルをポンコツ頭で解読していくと、どうもLCDとは様子が違う。
BMX055のマニュアルを見ると、I2Cのアドレスは7bitを使用し、0bit目は、readとwriteのフラグとして使用していると出ている。
ただしPICのI2C通信は8bitのアドレスなので、1bitずらしたアドレスになる。
まずは読み出したいアドレスを書き込んで、次から読み込みを複数バイト実行し、アクノリッジを立てるまで、マルチバイトの読み込みが可能だそうである。
このあたりは、私がなにぶんポンコツな英語力なので、何処まで正確なのか不明なのであるが、なんとなく動いているようなので良しとしている。
BMX055処理のヘッダーファイル
#include // include processor files - each processor file is guarded.
#define BMX055_ACC_ADDR 0x32 // x19<<1 加速度センサのアドレス
#define BMX055_ACC_DATA 0x02 // 加速度センサのデータアドレス
#define BMX055_GYRO_ADDR 0xD2 // 0x69<<1 ジャイロセンサのアドレス
#define BMX055_GYRO_DATA 0x02 // ジャイロセンサのデータアドレス
//#define BMX055_MAG_ADDR 0x26 // 0x13<<1磁気センサのアドレス
void BMX055_init(void);
void BMX055_GET_ACC(int acc_data[4]);
void BMX055_GET_GYRO(int gyro_data[3]);
BMX055の初期設定は、基本的に各センサの初期設定である。
加速度の読み込みは、3軸と、温度データもついでに読み込める。
温度データは23度を0として+/-を0.5度刻みで計測したデータだそうである。
加速度のデータは、分解能が12bitで+/-2gで設定しているので、範囲は4gである。
したがって分解能は、4g/4096で、bitあたり0.0009765gということになる。
ジャイロのデータは角速度で、分解能は16bitで、+/-125度という設定をしているので、範囲は250度である。
したがって分解能は、250度/65536で、bitあたり0.003815度/sということになる。
BMX055読み込みプログラムは以下のようなものになる。
#include "I2C.h"
#include "BMX055.h"
void BMX055_init()
{
//-----------------------------------------
I2C_Master_Start();
I2C_Master_Write(BMX055_ACC_ADDR); // 加速度センサ
I2C_Master_Write(0x0F); // Select PMU_Range register
I2C_Master_Write(0x03); // Range = +/- 2g
I2C_Master_Stop();
__delay_ms(100) ; // ms
//-----------------------------------------
I2C_Master_Start();
I2C_Master_Write(BMX055_ACC_ADDR); // 加速度センサ
I2C_Master_Write(0x10); // Select PMU_BW register
I2C_Master_Write(0x08); // Bandwidth = 7.81 Hz
I2C_Master_Stop();
__delay_ms(100) ; // ms
//-----------------------------------------
I2C_Master_Start();
I2C_Master_Write(BMX055_ACC_ADDR); // 加速度センサ
I2C_Master_Write(0x11); // Select PMU_LPW register
I2C_Master_Write(0x00); // Normal mode, Sleep duration = 0.5ms
I2C_Master_Stop();
__delay_ms(100) ; // ms
//-----------------------------------------
I2C_Master_Start();
I2C_Master_Write(BMX055_GYRO_ADDR); // ジャイロセンサ
I2C_Master_Write(0x0F); // Select Range register
I2C_Master_Write(0x04); // Full scale = +/- 125 degree/s
I2C_Master_Stop();
__delay_ms(100) ; // ms
//-----------------------------------------
I2C_Master_Start();
I2C_Master_Write(BMX055_GYRO_ADDR); // ジャイロセンサ
I2C_Master_Write(0x10); // Select Bandwidth register
I2C_Master_Write(0x07); // ODR = 100 Hz
I2C_Master_Stop();
__delay_ms(100) ; // ms
//-----------------------------------------
I2C_Master_Start();
I2C_Master_Write(BMX055_GYRO_ADDR); // ジャイロセンサ
I2C_Master_Write(0x11); // Select LPM1 register
I2C_Master_Write(0x00); // Normal mode, Sleep duration = 2ms
I2C_Master_Stop();
__delay_ms(100) ; // ms
//-----------------------------------------
}
//
// 加速度を取得
void BMX055_GET_ACC(int acc_data[4]) {
unsigned char data[7];
LATAbits.LA1 = 1;
I2C_Master_Start();
I2C_Master_Write(BMX055_ACC_ADDR); // 加速度センサ
I2C_Master_Write(BMX055_ACC_DATA); // Select data register
I2C_Master_Stop();
I2C_Master_Start();
I2C_Master_Write(BMX055_ACC_ADDR+1); // 加速度センサ読み込み
for (int i = 0; i < 6; i++) {
data[i] = I2C_Master_Read(0); // Request 1 byte of data
// Read 7 bytes of data
// xAccl lsb,msb, yAccl lsb,msb, zAccl lsb,msb temp
}
data[6] = I2C_Master_Read(1); // Request 1 byte of data
I2C_Master_Stop();
//data[0] = 0xFF;
//data[1] = 0xFF;
//data[6] = 0xFF;
acc_data[0] = (data[0] >> 4) + (data[1] << 4);
acc_data[1] = (data[2] >> 4) + (data[3] << 4);
acc_data[2] = (data[4] >> 4) + (data[5] << 4);
acc_data[3] = data[6];
if(acc_data[0] > 2047) acc_data[0] = acc_data[0] - 4096;
if(acc_data[1] > 2047) acc_data[1] = acc_data[1] - 4096;
if(acc_data[2] > 2047) acc_data[2] = acc_data[2] - 4096;
if(acc_data[3] > 127) acc_data[3] = acc_data[3] - 256;
acc_data[3] = acc_data[3] + 46; // 23*2 0.5度単位
LATAbits.LA1 = 0;
}
//
// 角速度を取得
void BMX055_GET_GYRO(int gyro_data[3]) {
unsigned char data[6];
LATAbits.LA1 = 1;
I2C_Master_Start();
I2C_Master_Write(BMX055_GYRO_ADDR); // ジャイロセンサ
I2C_Master_Write(BMX055_GYRO_DATA); // Select data register
I2C_Master_Stop();
I2C_Master_Start();
I2C_Master_Write(BMX055_GYRO_ADDR+1); // 角速度センサ読み込み
for (int i = 0; i < 5; i++) {
data[i] = I2C_Master_Read(0); // Request 1 byte of data
// Read 6 bytes of data
// xAccl lsb,msb, yAccl lsb,msb, zAccl lsb,msb temp
}
data[5] = I2C_Master_Read(1); // Request 1 byte of data
I2C_Master_Stop();
//data[0] = 0xFF;
//data[1] = 0xFF;
gyro_data[0] = data[0] + (data[1] << 8);
gyro_data[1] = data[2] + (data[3] << 8);
gyro_data[2] = data[4] + (data[5] << 8);
if(gyro_data[0] > 32767) gyro_data[0] = gyro_data[0] - 65536;
if(gyro_data[1] > 32767) gyro_data[1] = gyro_data[1] - 65536;
if(gyro_data[2] > 32767) gyro_data[2] = gyro_data[2] - 65536;
LATAbits.LA1 = 0;
}
メインのプログラム。
今回は、BMX055から、加速度とジャイロのデータを取り出し、加速度のデータと温度データをLCDに表示している。
/*
* File: MAIN.c
* Author: rsy88
*
* Created on 2023/05/05, 14:31
*/
#include
#include
#include "I2C.h"
#include "LCD.h"
#include "BMX055.h"
// コンフィギュレーション pic18f4550 c18
#pragma config PLLDIV = 5, CPUDIV = OSC1_PLL2, USBDIV = 2
#pragma config FOSC = HSPLL_HS, FCMEN = OFF, IESO = OFF
#pragma config PWRT = ON, BOR = OFF, BORV = 0
#pragma config VREGEN = ON, WDT = OFF, WDTPS = 1
#pragma config CCP2MX = OFF, PBADEN = OFF, LPT1OSC = OFF
#pragma config MCLRE = OFF, STVREN = OFF, LVP = OFF
#pragma config ICPRT = OFF, XINST = OFF, DEBUG = OFF
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF
#pragma config CPB = OFF, CPD = OFF
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF
#pragma config WRTC = OFF, WRTB = OFF, WRTD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF, EBTRB = OFF
void main(void) {
unsigned char x;
unsigned char y;
unsigned char chr;
unsigned char z;
int data1 = 12345;
int data2 = 19876;
int temp_i;
int temp_j;
char pdata[16];
int acc_data[4]; // x,y,z + temp
int gyro_data[3]; // x,y,z
TRISA = 0b00000000; //PORTA=0-7 output
TRISD = 0b00000000; //PORTD=0-7 output
TRISB = 0b11111111; //PORTB=0-7 input
LATD = 0;
I2C_Master_Init();
__delay_ms(5) ; // 5ms
lcd_init();
LATAbits.LA0 = 1;
BMX055_init();
LATAbits.LA0 = 0;
while(1){
LATAbits.LA0 = 1;
__delay_ms(100) ; // ms
BMX055_GET_ACC(acc_data);
BMX055_GET_GYRO(gyro_data);
z = acc_data[0];
z = gyro_data[0];
LATD = z;
lcd_cls();
sprintf(pdata,"X=%d Y=%d",acc_data[0],acc_data[1]);
//sprintf(pdata,"X=%d Y=%d",gyro_data[0],gyro_data[1]);
lcd_loc(0,0);
lcd_str(pdata);
temp_i = acc_data[3] >> 1;
temp_j = (acc_data[3] - (temp_i << 1)) * 5;
sprintf(pdata,"Z=%d T=%d.%d",acc_data[2],temp_i,temp_j);
//sprintf(pdata,"Z=%d T=%d.%d",gyro_data[2],temp_i,temp_j);
lcd_loc(0,1);
lcd_str(pdata);
LATAbits.LA0 = 0;
__delay_ms(100) ; // ms
}
return;
}
今回実験した装置
オシロスコープに表示されているのはRA0とRA1の波形で、無限ループの先頭でLATAbits.LA0 = 1;でRA0がオンになり
BMX055_GET_ACC(acc_data);とBMX055_GET_GYRO(gyro_data);の中でRA1がオンになり、抜けるときにオフになる。
その後にLCDの表示を行ってからRA0がオフになるのを繰り返している。
表示されているLCDの値は、Xが27、Yが-53、Zが1001で、気温が23.5度となっている。
値はかなりふらついており、ノイズが乗っているのか?、感度が良すぎるのか?、このあたりは考慮が必要なようである。
Zの値が1001なので、0.0009765を乗算すると0.9775gということで、ほぼ1gの重力加速度がZ軸にかかっていると考えられる。
センサーを乗せている台は、どうしても若干傾いているので、薄い本などをちょっとかませて水平を試す。
なかなか微妙で難しいのだが、なんとかX軸とY軸が一桁以内になるようにしてみる。
ところが、そのときのZ軸の値が1001〜1002ということで、あまり変わらないのである。
本来は、X軸とY軸が0になった状態で、全ての重力加速度がZ軸のみにかかり、Zの値が最大になるはずなのである。
このへんの誤差とか、どういうものなのであろうか?
と思っていたら、時間とともにだんだんと値が変化してくるのである。
2時間くらい(昼食の時間)ほっといたら、X,Yの値が-3と-9くらいになり、Zの値が1003〜1004になっているのである。
確かに、センサーのようなアナログの物体は、時間や温度によってそうとう値がずれるのである。
昔、アマチュア無線の勉強をしていたときに、水晶振動子でさえも温度でドリフトするので、恒温槽に入れた方が良いなどと習ったのである。
HOME