I recently bought an GY251 breakkout board with the MPU-6050. It is possible to use it via I2C.
This is my first I2C project. Instead of using a libary, I wanted to learn more about the protocol and how to use it.
I tried to write my own code, to interface the MPU-6050 via I2C. I looked up the registers and addresses in the datasheet.
My code does two things:
In the setup, the Scaling of the readings is set.
In the loop, I tried to read some values of the registers.
When reading the values, I only get 0s.
I think that there is a problem there.
As I was writing the code, I was very confused with the Wire.h libary. I tried to replicate the I2C behaviour required by the datasheet with the commands I could use. I think there might be a problem there, as the Wire.h libary does not offer the possability to "just send" an Stop, Start, Read, Write or NACK bit.
I would be very happy if you could take a glance over my code, and explain me what I did wrong.
(code as attachement)
It makes no sense to post a picture of code or text.
Please read and follow the directions in the "How to use this forum" post, and post both code or text inline, using code or quote tags.
If you want to learn the I2C protocol, the Wire library is the last place to look. And you should not confuse the Arduino I2C hardware module with the protocol specifications.
There are various implementations of "bit bang" or software I2C source code that bring the details of the protocol into the open. Here is one example.
Here is a minimal example of how to use the <Wire.h> library to read one data register from the MPU-6050.
You can experiment to see if it is necessary to "wake up" the MPU-6050 first, but of course the acceleration value won't make sense if the sensor is not actively collecting data.
#include<Wire.h>
const int MPU_addr=0x68; // I2C address of the MPU-6050
int AcX;
void setup(){
Serial.begin(9600);
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,1,true); // request one register
AcX=Wire.read(); // 0x3B (ACCEL_XOUT_H)
Serial.print("AcX (H) = "); Serial.println(AcX);
}
void loop(){
}
jremington:
You can experiment to see if it is necessary to "wake up" the MPU-6050 first
This was the issue. It was required to wake up the MPU, by setting one register. I thought, that the wake state would be the default one.
It turns out, that my code was not that wrong. To someone reading this in the future, these are the instructions and functions I use:
Wire.beginTransmission(MPU_ADDR); // wake up the Chip
Wire.write(PWR_CFG_1_ADDR); // MPU_ADDR = 0x68 ; PWR_CFG_1_ADDR = 0x6B
Wire.write(0x00);
Wire.endTransmission();
Read the bytes:
byte getByte(int slave_address, int reg_address){
byte output = 0;
Wire.beginTransmission(slave_address); //start transmission
Wire.write(reg_address); //send register address
Wire.endTransmission(false); // resend start condition
Wire.requestFrom(slave_address,1); // request data
if (1 <= Wire.available()) { // if one bytes were received
output = Wire.read(); // receive byte
}
Wire.endTransmission(); // send stop condition
return output;
}
Together with this function you are able to easily read the registers for each axis:
A Wire.requestFrom() should not be followed by a Wire.endTransmission(). Explanation: common mistakes #2.
Using "if (1 <= Wire.available())" is weird (I know that some official Arduino examples use it ).
You can do this:
byte getByte(int slave_address, int reg_address)
{
byte output = 0;
Wire.beginTransmission(slave_address); //start
Wire.write(reg_address); // set register address
Wire.endTransmission(false); // omit the stop to create a repeated start
Wire.requestFrom(slave_address,1); // request 1 byte
if (Wire.available() == 1) { // received the same amount as requested ?
output = Wire.read(); // get the received byte
}
return output;
}
or this:
byte getByte(int slave_address, int reg_address)
{
byte output = 0;
Wire.beginTransmission(slave_address); //start
Wire.write(reg_address); // set register address
Wire.endTransmission(false); // omit the stop to create a repeated start
int n = Wire.requestFrom(slave_address,1); // request 1 byte
if (n == 1) { // received the same amount as requested ?
output = Wire.read(); // get the received byte
}
return output;
}
If your I2C bus is really bad, then you could check the return value of Wire.endTransmission() and the return value of Wire.requestFrom() and, for example, return a 'false' to notify that something is wrong.