MPU9250
9軸のセンサー
磁気3、ジャイロ3、加速度3軸持つセンサー
I2C、SPIどちらの通信でも可能。
SPIによる方法を説明する
データシート
ハードウェア https://invensense.tdk.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf
レジスタ https://cdn.sparkfun.com/assets/learn_tutorials/5/5/0/MPU-9250-Register-Map.pdf
接続
|MPU9250 |expression |Arduino:マイコン |
|---|---|---|--- |
|Vcc |3.3V | 3.3V |
|GND |GND |GND |
|SCL|SPI-clock|CLK:13|
|SDA|Data Input|MOSI:11|
|EDA|センサを追加する場合|NoConection|
|ECL|に使用する|NoConection|
|ADO|Data Output|MISO:12|
|INT|割り込み出力らしい|NoConection|
|NCS|ChipSelect|CS:10|
|FSYNC|不明|GNDにしておけば良いらしい|
5V-3.3V変換はよくわからない。
変換を入れなくても、入れてもちゃんと動作した事例がある。
しかし、入れた結果、電圧が足りないのかArduino側が判定しない(ロジアナで見るとデータが出てるのに)事例があった。
変換ICを持っていない場合は直で繫いで試しても良いと思う
持っている場合は付けて見て、だめなら外しては試して見ると良いと思う
SPI
通信モードは3、立ち上がりラッチ、基本SCK状態はHIGH
SCL周波数は、読み込みのみなら20MHzまで
書き込みもする場合は1MHzにすると良いらしい(1MHzで動いた)
SPIプロトコル
読み込み
CS->HIGH
アドレス8bit(アドレスの先頭ビットが1=Read,0=Write )
空データ8bit送信と同時に受信
CS->LOW
書き込み
CS->HIGH
アドレス8bit(アドレスの先頭ビットが1=Read,0=Write )
書き込みデータ8bit
CS->LOW
動作確認プログラム:MBED用
# include "mbed.h"
# include "Serial.h"
Serial pc(USBTX, USBRX); // USBシリアルポートのインスタンス
SPI spi(D11,D12,D13);
DigitalOut cs(D10);
int main() {
spi.format(8,3);
spi.frequency(1000000);
cs=1;
pc.baud(250000);
cs=0;
int val = spi.write(0xF5);
val = spi.write(0x00);
cs = 1;
pc.printf("START\r\n");
pc.printf("%8x \r\n",val);
while(1){
}
}
これで、71が読み込めている場合、通信成功。
プログラムは、アドレス0x75(WHO_AM_I)を読み込んでいる。
正確には、Readなので先頭ビットを1にしてアドレス0xF5を読んでいる。
動作確認:arduino用
# include <SPI.h>
# include<avr/io.h>
# include<avr/interrupt.h>
# define cs 10
void setup() {
pinMode(cs,OUTPUT); //2020.4.09 追加
SPI.setBitOrder(MSBFIRST); //最上位ビット(MSB)から送信
SPI.setClockDivider(SPI_CLOCK_DIV4); //通信速度をデフォルト
SPI.setDataMode(SPI_MODE3); //アイドル5Vで0V→5Vの変化で送信する
SPI.begin(); //開始
Serial.begin(250000);
}
void loop() {
byte data = Read(0x75);
Serial.println(data, HEX);
delay(100);
}
void Write(byte address, byte data) {
digitalWrite(cs, LOW);
SPI.transfer(address);
SPI.transfer(data);
digitalWrite(cs, HIGH);
}
byte Read(byte address) {
digitalWrite(cs, LOW);
SPI.transfer(address | 0x80);
byte data = SPI.transfer(0);
digitalWrite(cs, HIGH);
return data;
}
0x71が読めれば、成功です。
ジャイロ、加速度読み込みプログラム
# include <SPI.h>
# include<avr/io.h>
# include<avr/interrupt.h>
# define cs 10
void setup() {
pinMode(cs,OUTPUT); //2020.4.09追加
SPI.setBitOrder(MSBFIRST); //最上位ビット(MSB)から送信
SPI.setClockDivider(SPI_CLOCK_DIV4); //通信速度をデフォルト
SPI.setDataMode(SPI_MODE3); //アイドル5Vで0V→5Vの変化で送信する
SPI.begin(); //開始
Serial.begin(250000);
byte data = Read(0x75);
Serial.println(data, HEX);
delay(100);
}
void loop() {
byte dataH = Read(0x3B);
byte dataL = Read(0x3C);
int AX = dataH << 8 | dataL;
dataH = Read(0x3D);
dataL = Read(0x3E);
int AY = dataH << 8 | dataL;
dataH = Read(0x3F);
dataL = Read(0x40);
int AZ = dataH << 8 | dataL;
dataH = Read(0x43);
dataL = Read(0x44);
int GX = dataH << 8 | dataL;
dataH = Read(0x45);
dataL = Read(0x46);
int GY = dataH << 8 | dataL;
dataH = Read(0x47);
dataL = Read(0x48);
int GZ = dataH << 8 | dataL;
if (AX > 32768) {
AX = AX - 65535;
}
if (AY > 32768) {
AY = AY - 65535;
}
if (AZ > 32768) {
AZ = AZ - 65535;
}
if (GX > 32768) {
GX = GX - 65535;
}
if (GY > 32768) {
GY = GY - 65535;
}
if (GZ > 32768) {
GZ = GZ - 65535;
}
//if(Flag == 1){
Serial.print(AX );
Serial.print(" ");
Serial.print(AY );
Serial.print(" ");
Serial.print(AZ );
Serial.print(" ");
Serial.print(GX );
Serial.print(" ");
Serial.print(GY );
Serial.print(" ");
Serial.print(GZ );
Serial.println(" ");
}
void Write(byte address, byte data) {
digitalWrite(cs, LOW);
SPI.transfer(address);
SPI.transfer(data);
digitalWrite(cs, HIGH);
}
byte Read(byte address) {
digitalWrite(cs, LOW);
SPI.transfer(address | 0x80);
byte data = SPI.transfer(0);
digitalWrite(cs, HIGH);
return data;
}
mbedでもやりましたが、なぜか読めないバイトがあったりして難しいので止めました
各種設定について
sleep解除、スケール設定、LPF、出力周波数設定を上記ではしていません。
しなくてもなぜか動きました。I2Cで使うなら必要なはずなのですが・・・
初期設定では
+-250dps,+-2g,1kHz更新 っぽいです
ジャイロの感度設定
Write(0x1B,0x00); //250dps
Write(0x1B,0x08); //500dps
Write(0x1B,0x10); //1000dps
Write(0x1B,0x18); //2000dps
ローパスフィルタのカットオフ周波数設定
F_CHOICEは00にしておけばOK(デフォルト)
デフォルト250Hz
Write(0x1A, 0x06); //gyro LPF5Hz
Write(0x1A, 0x03); //gyro LPF41Hz
Write(0x1D, 0x03); //acce LPF45Hz
加速度計の感度設定
Write(0x1C, 0x04); //acce +-4g
Write(0x1C, 0x10); //acce +-8g
Write(0x1C, 0x14); //acce +-16g
使うやつ以外をコメントアウトすれば使えます(確認済み)
追記:Arduino Dueを使用する場合
DueにはSPIが一つあり、ICSPヘッダのみから利用できます。Pin13,12,11はSPIピンにはなりません。
この図の中央の6本のオスヘッダのSCK,MOSI,MISOにさして利用します。
プログラムは#includeの部分の
# include<avr/io.h>
# include<avr/interrupt.h>
を除くことで動作できます。
# include <SPI.h>
# define cs 10
void setup() {
pinMode(cs,OUTPUT);
SPI.setBitOrder(MSBFIRST); //最上位ビット(MSB)から送信
SPI.setClockDivider(SPI_CLOCK_DIV32); //通信速度をデフォルト
SPI.setDataMode(SPI_MODE3); //アイドル5Vで0V→5Vの変化で送信する
SPI.begin(); //開始
Serial.begin(250000);
byte data = Read(0x75);
Serial.println(data, HEX);
delay(100);
}
void loop() {
byte dataH = Read(0x3B);
byte dataL = Read(0x3C);
int AX = dataH << 8 | dataL;
dataH = Read(0x3D);
dataL = Read(0x3E);
int AY = dataH << 8 | dataL;
dataH = Read(0x3F);
dataL = Read(0x40);
int AZ = dataH << 8 | dataL;
dataH = Read(0x43);
dataL = Read(0x44);
int GX = dataH << 8 | dataL;
dataH = Read(0x45);
dataL = Read(0x46);
int GY = dataH << 8 | dataL;
dataH = Read(0x47);
dataL = Read(0x48);
int GZ = dataH << 8 | dataL;
if (AX > 32768) {
AX = AX - 65535;
}
if (AY > 32768) {
AY = AY - 65535;
}
if (AZ > 32768) {
AZ = AZ - 65535;
}
if (GX > 32768) {
GX = GX - 65535;
}
if (GY > 32768) {
GY = GY - 65535;
}
if (GZ > 32768) {
GZ = GZ - 65535;
}
//if(Flag == 1){
/*
Serial.print(AX );
Serial.print(" ");
Serial.print(AY );
Serial.print(" ");
Serial.print(AZ );
Serial.print(" ");
*/
Serial.print(GX );
Serial.print(" ");
Serial.print(GY );
Serial.print(" ");
Serial.print(GZ );
Serial.println(" ");
}
void Write(byte address, byte data) {
digitalWrite(cs, LOW);
SPI.transfer(address);
SPI.transfer(data);
digitalWrite(cs, HIGH);
}
byte Read(byte address) {
digitalWrite(cs, LOW);
SPI.transfer(address | 0x80);
byte data = SPI.transfer(0);
digitalWrite(cs, HIGH);
return data;
}
SPI.setClockDivider(SPI_CLOCK_DIV32);
で4MHzクロックになってました。
追記: Arduino Mega接続
|MPU9250 |expression |Mega |
|---|---|---|--- |
|Vcc |3.3V | 3.3V |
|GND |GND |GND |
|SCL|SPI-clock|CLK:52|
|SDA|Data Input|MOSI:51|
|EDA|センサを追加する場合|NoConection|
|ECL|に使用する|NoConection|
|ADO|Data Output|MISO:50|
|INT|割り込み出力らしい|NoConection|
|NCS|ChipSelect|CS:53|
|FSYNC|不明|GNDにしておけば良いらしい|