MPU6050 With Microchip PIC | Accelerometer Gyroscope Interfacing With PIC

Previous Tutorial Previous Tutorial Tutorial 29 Next Tutorial Next Tutorial
Interfacing Accelerometer/Gyro (MPU6050 IMU) With PIC MCUs
Intermediate Level ★★★☆☆

 

MPU6050 Tutorial With PIC XC8

 

In this tutorial, we’ll discuss how to interface MPU6050 IMU (Accelerometer + Gyroscope) with PIC microcontrollers. And we’ll write a C code driver to get raw data from the sensor with both PIC18F2550 & PIC16F877A. You’ll also know the internal structure of the MPU6050, its register map, and how to configure each part of it. So you can change the data rate/sampling or the scale for each of the accelerometer and gyroscope.

This considerably long article includes all the information you’ll need to get a very good understanding of how to interface the MPU6050 IMU. And to configure it to suit your application and more importantly write your own library from scratch and get raw & converter data. So you can replicate Arduino projects or hopefully implement your own new ideas!

This tutorial includes 3 practical LABs, the last of which will be a speed controller stick using MPU6050 accelerometer. Here is a short demo video for this LAB, you’ll be able to make this as well by the end of this article!

without further ado, let’s get started!

[toc]


   Needed Components For This Tutorial   

 

Qty. Component Name Buy On Amazon.com
1 PIC16F877A

or PIC18F2550

Add

Add

1 BreadBoard Add
1 MPU6050 Add
1 USB-TTL FTDI board Add
1 Jumper Wires Pack Add    Add
1 LM7805 Voltage Regulator (5v) Add
1 4MHz Crystal Oscillator Add
1 PICkit2 or 3 Programmer Add

The Prototyping Board Setup

Prototyping Board - Embedded Systems Tutorials With PIC MCUs

 


   MPU6050 IMU   

 

The MPU6050 is an IMU (inertial measurement unit) consisting of 3 sensors: Accelerometer, Gyroscope, Temperature sensor. The Accelerometer sensor is 3-Axis, The Gyro is 3-Axis as well. Giving you 6DOF (degrees of freedom) motion sensing and detection capability. It has a DMP (digital motion processor) unit that can perform sensor data fusion to give you more advanced and precise motion sensing.

This sensor can be easily interfaced using a two-wire interface (i2c) as we’ll see in this tutorial. Without the need to use external pull-up resistors as they connected already on the sensor’s board.

Pinout & Connection Diagram

MPU6050 Pinout And Connection Diagram With PIC Microcontrollers

Features

Gyroscope Features:

  • Digital-output X-, Y-, and Z-Axis angular rate sensors (gyroscopes) with a user-programmable full-scale range of ±250, ±500, ±1000, and ±2000°/sec
  • Integrated 16-bit ADCs enable simultaneous sampling of gyros
  • Enhanced bias and sensitivity temperature stability reduces the need for user calibration
  • Improved low-frequency noise performance
  • Digitally-programmable low-pass filter
  • Factory calibrated sensitivity scale factor

Accelerometer Features:

  • Digital-output triple-axis accelerometer with a programmable full-scale range of ±2g, ±4g, ±8g, and ±16g
  • Integrated 16-bit ADCs enable simultaneous sampling of accelerometers while requiring no external multiplexer
  • Orientation detection and signaling
  • Tap detection
  • User-programmable interrupts

Extra Features:

  • 9-Axis MotionFusion by the on-chip Digital Motion Processor (DMP)
  • VDD supply voltage range of 2.375V-3.46V
  • 1024 byte FIFO buffer reduces power consumption by allowing the host processor to read the data in bursts and then go into a low-power mode as the MPU collects more data
  • Digital-output temperature sensor
  • User-programmable digital filters for gyroscope, accelerometer, and temp sensor
  • 400kHz Fast Mode I2C for communicating with all registers

Applications

  • Robotic Motion Sensing And Control
  • Robotics Localization And Mapping Tasks
  • MotionCommand™ technology (for Gesture Short-cuts)
  • Motion-enabled game and application framework
  • InstantGesture™ iG™ gesture recognition
  • Location-based services, points of interest, and dead reckoning
  • Handset and portable gaming
  • Motion-based game controllers
  • 3D remote controls for Internet-connected TVs and set-top boxes, 3D mice, etc
  • Wearable sensors for health, fitness, and sports
  • Toys
  • And Much More…

Block Diagram

MPU6050 Block Diagram

3-Axis Gyroscope

The MPU-60X0 consists of three independent vibratory MEMS rate gyroscopes, which detect rotation about the X-, Y-, and Z- Axes. When the gyros are rotated about any of the sense axes, the Coriolis Effect causes a vibration that is detected by a capacitive pickoff. The resulting signal is amplified, demodulated, and filtered to produce a voltage that is proportional to the angular rate. This voltage is digitized using individual on-chip 16-bit Analog-to-Digital Converters (ADCs) to sample each axis.

The full-scale range of the gyro sensors may be digitally programmed to ±250, ±500, ±1000, or ±2000 degrees per second (dps). The ADC sample rate is programmable from 8,000 samples per second, down to 3.9 samples per second, and user-selectable low-pass filters enable a wide range of cut-off frequencies.

3-Axis Accelerometer

The MPU-60X0’s 3-Axis accelerometer uses separate proof masses for each axis. Acceleration along a particular axis induces displacement on the corresponding proof mass, and capacitive sensors detect the displacement differentially. The MPU-60X0’s architecture reduces the accelerometers’ susceptibility to fabrication variations as well as to thermal drift.

When the device is placed on a flat (horizontal) surface, it will measure 0g on the X- and Y-axes and +1g on the Z-axis. The accelerometers’ scale factor is calibrated at the factory and is nominally independent of the supply voltage. Each sensor has a dedicated sigma-delta ADC for providing digital outputs. The full-scale range of the digital output can be adjusted to ±2g, ±4g, ±8g, or ±16g. Note that: +1g is equal to = 9.8m/s2 Which is the gravitational acceleration.

Digital Motion Processor (DMP)

The DMP acquires data from accelerometers, gyroscopes, and additional 3rd party sensors such as magnetometers, and processes the data. The resulting data can be read from the DMP’s registers or can be buffered in a FIFO. The DMP has access to one of the MPU’s external pins, which can be used for generating interrupts.

The purpose of the DMP is to offload both timing requirements and processing power from the host processor. Typically, motion processing algorithms should be run at a high rate, often around 200Hz, in order to provide accurate results with low latency. This is required even if the application updates at a much lower rate.

Sensor Data Registers

The sensor data registers contain the latest gyro, accelerometer, auxiliary sensor, and temperature measurement data. They are read-only registers and are accessed via the serial interface. Data from these registers may be read anytime. However, the interrupt function may be used to determine when new data is available.

FIFO Memory

The MPU6050 contains a 1024-byte FIFO register that is accessible via the Serial Interface. The FIFO configuration register determines which data is written into the FIFO. Possible choices include gyro data, accelerometer data, temperature readings, auxiliary sensor readings, and FSYNC input. A FIFO counter keeps track of how many bytes of valid data are contained in the FIFO. The FIFO register supports burst reads. The interrupt function may be used to determine when new data is available.

Interrupts

Interrupt functionality is configured via the Interrupt Configuration register. The interrupt status can be read from the Interrupt Status register.

The MPU6050 has a programmable interrupt system which can generate an interrupt signal on the INT pin. Status flags indicate the source of an interrupt. Interrupt sources may be enabled and disabled individually.

MPU6050 Interrupt Sources Table

Register Map

As you’ve seen in the above block diagram that the memory registers are easily accessible by different modules on the data bus. The Acceleration, Gyro, and Temperature sensing results are written to specific registers in the memory (which are read-only for the I2C host module). Some other registers are used by the DMP to set its configurations and others for setting the sampling rate, ranges, and other parameters for the Acc & Gyro.

We need to know the addresses and functionality of these registers in order to send the desired configurations to the right registers & read the results from the right memory locations! Down below are snippets from the memory map from the sensor’s datasheet. We’ll copy it to a header file in our code later on.

MPU6050 Register Map1

MPU6050 Register Map2

MPU6050 Register Map3

To Get The Full Register Map For MPU6050

Registers’ Descriptions

As I’ve mentioned earlier, each register has specific functionality and it may be read/write or Read-Only. All these pieces of information are detailed in the MPU6050 register map document. And I highly recommend you download it and have a look at some of these registers.

Here is an example for a register that is used to configure the Accelerometer, for example, it’s called ACCEL_CONFIG (which makes a lot of sense in fact!)

ACCEL_CONFIG Register

ACCEL_CONFIG Register Description

This register is used to trigger the accelerometer self-test and configure the accelerometer full-scale range. This register also configures the Digital High Pass Filter (DHPF). The accelerometer self-test permits users to test the mechanical and electrical portions of the accelerometer. The self-test for each accelerometer axis can be activated by controlling the XA_ST, YA_ST, and ZA_ST bits of this register. Self-test for each axis may be performed independently or all at the same time.

When the self-test is activated, the on-board electronics will actuate the appropriate sensor. This actuation simulates an external force. The actuated sensor, in turn, will produce a corresponding output signal. The output signal is used to observe the self-test response.

AFS_SEL selects the full-scale range of the accelerometer outputs according to the following table.

Accelerometer Range Table

And that’s it for this single register. There are many others out there in the specifications document. Just take the time to skip through it and highlight each register/bit you see interesting to get a specific functionality out of your MPU6050 sensor to make the best use of it!


   Interfacing MPU6050 With PIC MCUs   

Connection Diagram (Hardware)

MPU6050 Pinout And Connection Diagram With PIC Microcontrollers

Driver Components (Software Parts)

Serial Terminal: For debugging purposes, we’ll need to send out the sensor’s data over the UART serial port to the computer so we can check its validity.

I2C Driver: the MPU6050 interface we’ll be using is built on the I2C communication protocol and we’ll need the I2C hardware device driver code which we’ve developed in a previous tutorial. You’ll have to change this code if you’re planning to use another PIC MCU chip or even AVR MCU.

Register Map Definitions: For MPU6050 interfacing, we’ll need to address each register individually and by its own address stated in the specifications sheet. So, we’ll create a header file with all registers names and addresses to be used in the MPU6050.c source code file.

Initialization Settings For MPU6050: The MPU6050.c source file must have at least a single function (routine) to initialize the required settings for the sensor during operation. You can add more functions to change the data rate or the range of readings for each of the accelerometer and the gyroscope. Actually you can add more functionality to control how the MPU6050 will operate. But all in all, you’ll need at least a single initialization function MPU6050_Init();

Raw Data Reading: The MPU6050.c source file should also include a function to get the readings from the sensor. You can either create separate functions to read each sensor at a time (accelerometer, gyro, or temperature). But as you can see, at least, one function can be used at least to get all the raw sensor’s readings/data. Mathematical manipulations and conversions can thereafter be applied to this data. More functions can be added to our library’s source file MPU6050.c, but I’ll implement Raw_Data_Read() for this tutorial. Then you can replicate what other guys are doing with Arduino and so.

 


   Implementing MPU6050 Driver (Raw)   

1  Serial Port

The readings from the sensor will be printed over the UART-USB converter, so we’ll need the following routines. Which we’ve developed in a previous tutorial (UART).

2  I2C Driver

In order to communicate with the MPU6050 sensor, we’ll need to use our I2C device driver which we’ve implemented in a previous tutorial (I2C). Here are the prototypes for these functions. The exact implementation (functions’ definitions) can be found in the next LAB hereafter or in the I2C tutorial itself.

3  MPU6050 Register Map Definitions

4  MPU6050 Initialization Settings

You can actually create multiple functions (routines) to set the configurations of the MPU6050 sensor or alternatively, for sake of simplicity, we can put all together in a single function which will be called afterward to initialize the MPU6050 with some default settings of our choice! let’s call it

The implementation (definition) of this function will be as shown below

Down below are the different parts of this function’s implementation (definition)

4.1 Power-Up Delay & I2C Initialization

4.2 Setting The Sampling (data) Rate Divider

MPU6050 Sampling Rate Divider

MPU6050 Sampling Rate Divider Register

which means, if you want to set the sampling rate to 1kHz, all you have to do is passing 0x07 to this register in the MPU6050 memory. And that’s what we’re doing below

4.3 Setting The MPU6050 Clock Source

MPU6050 PWM Management Register

MPU6050 PWM Management Register Description

Which means, we can simply pass 0x01 to this register in the MPU6050’s memory. So that it uses the clock of the gyro and not put it in sleep mode as well. Here is how to pass this 0x01 value to the PWR_MGMT_1 register.

4.4 Configure The Digital Low Pass Filter (DLPF)

MPU6050 CONFIG register

MPU6050 CONFIG register description

MPU6050 CONFIG register description2

We’ll not use external input so we don’t need the sync function and for the digital low pass filter inside the MPU6050, we’ll pick the highest bandwidth frequency, just to test out how stable the readings will be. Therefore, the value which we’ll write to the CONFIG register will be 0x00. And here is how to pass it to the MPU6050 register in C.

4.5 Configure The Accelerometer

ACCEL_CONFIG Register MPU6050

ACCEL_CONFIG Register MPU6050 description1ACCEL_CONFIG Register MPU6050 description2We won’t use the self-test feature in these tutorials, so we don’t need to configure anything about it. And as for the full-scale range, we’ll pick ± 2g (which is= ± 2 x 9.8 m/s2). You can create a separate function just to set the FSR of the accelerometer so the user has the ability to easily pick the value he wants. But for this tutorial, we’ll keep it fixed to ±2g. So, we’ll move 0x00 to ACCEL_CONFIG register. And here is how to do this in C, so you can easily change it however you want in your application.

4.6 Configure The Gyroscope

GYRO CONFIG Register MPU6050

ACCEL_CONFIG Register MPU6050 description1

GYRO CONFIG Register MPU6050 description2

As we’ve done with the accelerometer previously, the self-test mode won’t be used in this tutorial. And as for the full-scale range, let’s pick the widest range span ±2000 °/s. Therefore, the value which we’ll have to pass to the GYRO_CONFIG register will be 0x18. You can change the range however you want. And here is how to do it in code.

4.7 Enable Internal Interrupts (When Data Ready)

INT Enable Register MPU6050

To enable the internal interrupts when data is ready, we’ll need to move 0x01 to the INT_ENABLE register inside the MPU6050’s memory. And here is the code to do this.

Finally: you can read the WHO_AM_I register and check if the sensor is responding correctly or not. If not, then return 0, if yes, return 1. And yes, you’ll need to change the function’s type it won’t be void anymore.

In this way, you can check the returned value in your main function. This enables the user to determine if the MPU6050 sensor is working and initialized successfully or not! And that’s it! we won’t do this in our tutorial to keeps things as simple as possible, but here you got it. DIY it if you want!

5  Raw Data Reading

The reading from MPU6050 IMU consists of 7 parameters saved in 14 consecutive registers in the memory. We’ll need to read them all one by one. (1) Accelerometer readings ACCEL_X, ACCEL_Y, ACCEL_Z. (2) Gyroscope readings GYRO_X, GYRO_Y, GYRO_Z. (3) Temperature sensor value.

Firstly, we’ll send the address of the first register containing the results (readings) and it’s ACCEL_XOUT_H. After reading this register from the MPU6050, the MCU should ACK receiving it, so the MPU6050 will send out the next register’s value and so on until we’ve received the 14 registers successfully. Then, the MCU will NACK and stop the I2C communication.

We can return the results as an array of integers or even pass a buffer array by reference to the Read() function which will write the readings into it directly using the pointer. However, and for the sake of simplicity, in this tutorial we’ll just print out the results to the terminal within the Read() function itself. So, it’s going to be void.

And here you got the idea, implement the return method on your own until another tutorial is released in the future. Or maybe I’ll just add it as an update at the conclusion of this article, IDK.

Here is the implementation of the Read() function!

 


   MPU6050 Raw Example – LAB1   

MPU6050 Interfacing With PIC16F877A

Lab Name Interfacing MPU6050 Raw Data Read Example
Lab Number 35
Lab Level Intermediate
Lab Objectives Learn how to interface the MPU6050 Accelerometer/Gyroscope IMU with a microcontroller over the I2C serial bus.

 

       1. Coding       

 

Open the MPLAB IDE and create a new project, name it “MPU6050_Raw”. If you have some issues doing so, you can always refer to the previous tutorial using the link below.

timer-preloading

Set the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.

timer-preloading

Now, open the main.c file and let’s start developing the firmware for our project.

Here is the Full Code Listing For This LAB

 

       2. Prototyping       

 

MPU6050 Interfacing With PIC Microcontroller XC8 LAB1

MPU6050 Interfacing With PIC Microcontroller XC8 LAB11

And here are the results (Raw Sensors Data) on the terminal screen. It may not make a lot of sense to you if it’s your first time dealing with this IMU. But for me, this makes a lot of sense XD!

MPU6050 Raw Data LAB1

Put the sensor in a horizontal position and notice only the value of Az, it should be as near as possible to 214=16384. As you can see in the data, it’s close enough. Try pointing the module in such a way that the x-direction mark on the board is facing the ground. Now, Ax value should be approaching 16384. And the same for y-direction.

The catch is: the full-scale range we’re using is 2g and the acceleration result is signed int 16 -bit. So it’s ranging from (-32768 to +32768) which corresponds to (-2g to +2g). The gravitational acceleration is +1g which means the sensor’s reading will be nearly 16384 and in the same direction towards the earth.

 

Download Project

 


   MPU6050 Converted Data – LAB2   

MPU6050 Interfacing With PIC18F2550

Lab Name Interfacing MPU6050 Converted Data Example
Lab Number 36
Lab Level Intermediate
Lab Objectives Learn how to interface the MPU6050 Accelerometer/Gyroscope IMU with a microcontroller over the I2C serial bus.

 

       1. Coding       

 

Open the MPLAB IDE and create a new project, name it “MPU6050”. If you have some issues doing so, you can always refer to the previous tutorial using the link below.

timer-preloading

Set the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.

timer-preloading

Now, open the main.c file and let’s start developing the firmware for our project.

Here is the Full Code Listing For This LAB

Here is the implementation for the MPU6050_Read() function

 

       2. Prototyping       

 

Here are the results on the serial terminal (Converted Sensors Data).

MPU6050 Interfacing With PIC XC8 Raw Data LAB2

 

 

Download Project

 


   Stick Speed Controller – LAB3   

The MCU I’ve Used For This LAB is PIC18F2550

Lab Name Stick Speed Controller With MPU6050
Lab Number 37
Lab Level Intermediate
Lab Objectives Learn how to interface the MPU6050 Accelerometer/Gyroscope IMU with a microcontroller over the I2C serial bus.

 

       1. Coding       

 

Open the MPLAB IDE and create a new project, name it “MPU6050_Stick”. If you have some issues doing so, you can always refer to the previous tutorial using the link below.

timer-preloading

Set the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.

timer-preloading

Now, open the main.c file and let’s start developing the firmware for our project.

Here is the Full Code Listing For This LAB

 

As you might have noticed, nothing interesting happens in the main.c file actually!

The PWM duty cycle is being changed in the MPU6050_Read() function. And this is done according to the reading of acceleration in the y-Axis direction. The stick I’ve built has a pivot point in such a way it rotates around the y-axis. So the acceleration affecting on the y-axis is the gravitational acceleration = +1g = 9.81m/s2 or in the digital world (as for the sensor output) it’s ±16384

MPU6050 Speed Controller

When the MPU6050 accelerometer sensor is pointing in -y direction, the reading of the sensor will be -16384 and moving the stick to the other end will make the sensor pointing in +y direction and the sensor data output will be +16384, and in between the data from the sensor will be between those two end limits.

Step1 is to add a bias to this result from the sensor in order to get a positive value as a result ranging from 0 up to 32768.

Step2 is to perform a mapping from this domain to the PWM duty cycle which will be set to 10-Bits of resolution. Ranging from 0 up to 1023 (0-100% DC). This can be done by dividing by 32 or left-shifting the result >>5 times!

This figure explains what I’m trying to say in a graphical way

MPU6050 Speed Controller Stick LAB

Note: in order to get 10-Bits of DutyCycle resolution, we’ll set the PWM frequency to 2.9kHz, Fosc=48MHz, Timer2PS=16. Refer to the resolution equation in the datasheet (PWM page).

Note: to eliminate flickering in the output DC (due to mechanical friction or whatever), you can reduce the bandwidth frequency of the digital low pass filter (DLPF) in the MPU6050 settings and that’s what I’ve done in the initialization code. 

Another Note: please, check the code of PWM settings to get an idea of what i’m talking about. Also, check the initialization function for MPU6050 to see how i’ve changed the settings of the DLPF, and check also the MPU6050_Read() function as it’s doing all the work i’ve explained earlier. And you can re-write it in a different way as it appeals to you. But first of all, take a look and see how things are working. The download link is available at the end of this LAB section.

 

       2. Prototyping       

 

Nothing interesting in connections for this lab. just hook the i2c lines to the sensor and give it power +5v. And take the PWM output to an LED or transistor driver for motor speed control. Here is a video demo for testing the final output of the system on an LED & DSO, then on a DC motor.

Play Video On YouTube

 

Download the project code from the link down below. And check the functions I’ve highlighted previously in this article. And don’t hesitate to leave me any questions you’ve got. And also please, drop me a comment even if you’ve got everything right, I’m a little bit curious to know whether I could make everything clear or not.

 

Download Project

 

 


   Concluding Remarks   

 

Will Be Added Soon!

 

 

You Can Support This Work By Sharing These Tutorials On Social Networks! I’d Really Appreciate That A lot!

 

 

Previous Tutorial Previous Tutorial Tutorial 29 Next Tutorial Next Tutorial
Share This Page With Your Network!
Join Our +25,000 Newsletter Subscribers!

Stay Updated With All New Content Releases. You Also Get Occasional FREE Coupon Codes For Courses & Other Stuff!

Photo of author
Author
Khaled Magdy
Embedded systems engineer with several years of experience in embedded software and hardware design. I work as an embedded SW engineer in the Automotive & e-Mobility industry. However, I still do Hardware design and SW development for DSP, Control Systems, Robotics, AI/ML, and other fields I'm passionate about.
I love reading, writing, creating projects, and teaching. A reader by day and a writer by night, it's my lifestyle. I believe that the combination of brilliant minds, bold ideas, and a complete disregard for what is possible, can and will change the world! I will be there when it happens, will you?

11 thoughts on “MPU6050 With Microchip PIC | Accelerometer Gyroscope Interfacing With PIC”

  1. Hi Khaled and thank you for this tutorial! Is there a way to manually calibrate your accelerometer with PIC microcontroller, so that the start value is (0,0,0)?

    Reply
    • Calibration is a whole different story. But what I can see from your question is what you’re searching for is biasing.
      And yes, you can bias the result readings from the accelerometer to start from 0 and go up. This can easily be done by adding the minimum value for the current configuration (ex if you’re using +-2g sensitivity, then you can add 16384 to the result, and so on).

      Reply
    • You don’t actually need the PLL in particular. However, in this lab you’ll need to store and manipulate floating point numbers and convert them to strings. I did use the standard sprintf function for that and the code side has grown up to the point where it can’t fit for pic16f877a. That’s why this lab in particular is done using a pic18f device. Aside of this, every thing is the same here and there.

      Regards,

      Reply

Leave a Comment