I need your help for a project.
I have actually 2 parallel sensors of the type: MS5803-05BA, which supports I2C and SPI connection. One sensor is on I2C bus and one sensor is on SPI. They are both sending to my Arduino Mega. The I2C works perfect with short cables.
Here the datasheet of the sensor:
https://www.amsys.de/downloads/data/MS5803-05BA-AMSYS-datasheet.pdf
For some informations who wants to do the same with I2C. Here you can find a good code. (You can find the other MS580X typs there too). For the communication between the sensor and the Arduino Mega you need an logic converter like this txs0108e, which can be bought with a break out board (you need pull up resistors on the sensor side!):
https://github.com/millerlp/MS5803_05
But to my problem: I have an sensor distance for about 3-5 meters and the I2C connections doesnt work. Yes I can try to fix the pullup resistors but it doesnt worked for me (I have tried some different lower resistors between 3-10kOhm). Therefore I want to switch to the SPI bus.
I have edit the code from https://github.com/millerlp/MS5803_05, https://github.com/vic320/Arduino-MS5803-14BA and https://arduino.stackexchange.com/questions/13720/teensy-spi-and-pressure-sensor.
The File is added. (You have to put the .h and .cpp files in the folder of the arduino code (.spi).
I have problems with the code from the SPI (ccp and header). There is no right communication. I have checked my cables twice. I couldnt find a problem and the connection with the txs0108e works for parallel I2C sensor. Both sensors are working on I2C.
Here is the main code (arduino .spi) for SPI and I2C parallel:
/_____ I N C L U D E S
#include <stdio.h>
#include <math.h>
#include <SPI.h>
#include <Wire.h>
#include "MS5803_05.h"
#include "MS5803_05_SPI.h"
const int miso_port = 50; //SDI
const int mosi_port = 51; //SDO
const int sck_port = 52; //SLCK
const int slaveSelectPin = 53; // CSB
MS_5803 sensor = MS_5803(512);
MS_5803_SPI sensor_spi = MS_5803_SPI(4096, slaveSelectPin);
void setup()
{
pinMode(miso_port, INPUT);
pinMode(mosi_port, OUTPUT);
pinMode(slaveSelectPin, OUTPUT);
pinMode(sck_port, OUTPUT);
Serial.begin(9600);
//SPI BUS
if (sensor_spi.initializeMS_5803_SPI()) {
Serial.println( "MS5803 SPI CRC check OK." );
}
else {
Serial.println( "MS5803 SPI CRC check FAILED!" );
}
//I2C BUS
delay(1000);
if (sensor.initializeMS_5803()) {
Serial.println( "MS5803 I2C CRC check OK." );
}
else {
Serial.println( "MS5803 I2C CRC check FAILED!" );
}
}
void loop()
{
Serial.println("SPI Sensor first pressure [mbar], than temperature[°C]:");
sensor_spi.readSensor();
// Show pressure
Serial.print("Pressure = ");
Serial.print(sensor_spi.pressure());
Serial.println(" mbar");
// Show temperature
Serial.print("Temperature = ");
Serial.print(sensor_spi.temperature());
Serial.println("C");
////********************************************************
Serial.println("");
Serial.println("I2C Sensor first pressure [mbar], than temperature[°C]:");
sensor.readSensor();
// Show pressure
Serial.print("Pressure = ");
Serial.print(sensor.pressure());
Serial.println(" mbar");
// Show temperature
Serial.print("Temperature = ");
Serial.print(sensor.temperature());
Serial.println("C");
delay(2000);
}
}
The first connection with SPI is here (.cpp):
#include "MS5803_05_SPI.h"
#include <SPI.h>
#define CMD_RESET 0x1E // ADC reset command
#define CMD_ADC_READ 0x00 // ADC read command
#define CMD_ADC_CONV 0x40 // ADC conversion command
#define CMD_ADC_D1 0x00 // ADC D1 conversion
#define CMD_ADC_D2 0x10 // ADC D2 conversion
#define CMD_ADC_256 0x00 // ADC resolution=256
#define CMD_ADC_512 0x02 // ADC resolution=512
#define CMD_ADC_1024 0x04 // ADC resolution=1024
#define CMD_ADC_2048 0x06 // ADC resolution=2048
#define CMD_ADC_4096 0x08 // ADC resolution=4096
#define CMD_PROM_RD 0xA0 // Prom read command
#define spi_write SPI_MODE3
#define spi_write2 SPI_MODE1
// Create array to hold the 8 sensor calibration coefficients
static unsigned int sensorCoeffs[8]; // unsigned 16-bit integer (0-65535)
// D1 and D2 need to be unsigned 32-bit integers (long 0-4294967295)
static uint32_t D1 = 0; // Store uncompensated pressure value
static uint32_t D2 = 0; // Store uncompensated temperature value
// These three variables are used for the conversion steps
// They should be signed 32-bit integer initially
// i.e. signed long from -2147483648 to 2147483647
static int32_t dT = 0;
static int32_t TEMP = 0;
// These values need to be signed 64 bit integers
// (long long = int64_t)
static int64_t Offset = 0;
static int64_t Sensitivity = 0;
static int64_t T2 = 0;
static int64_t OFF2 = 0;
static int64_t Sens2 = 0;
// Some constants used in calculations below
const uint64_t POW_2_33 = 8589934592ULL; // 2^33 = 8589934592
SPISettings settings_write(500000, MSBFIRST, spi_write);
SPISettings settings_write2(500000, MSBFIRST, spi_write2);
//-------------------------------------------------
// Constructor
MS_5803_SPI::MS_5803_SPI( uint16_t Resolution, uint16_t cs) {
// The argument is the oversampling resolution, which may have values
// of 256, 512, 1024, 2048, or 4096.
_Resolution = Resolution;
//Chip Select
_cs=cs;
}
boolean MS_5803_SPI::initializeMS_5803_SPI(boolean Verbose) {
digitalWrite( _cs, HIGH );
SPI.begin();
// Reset the sensor during startup
resetSensor();
if (Verbose)
{
// Display the oversampling resolution or an error message
if (_Resolution == 256 | _Resolution == 512 | _Resolution == 1024 | _Resolution == 2048 | _Resolution == 4096){
Serial.print("Oversampling setting: ");
Serial.println(_Resolution);
} else {
Serial.println("*******************************************");
Serial.println("Error: specify a valid oversampling value");
Serial.println("Choices are 256, 512, 1024, 2048, or 4096");
Serial.println("*******************************************");
}
}
// Read sensor coefficients
for (int i = 0; i < 8; i++ )
{
SPI.beginTransaction(settings_write2);
digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low
unsigned int ret;
unsigned int rC = 0;
SPI.transfer(CMD_PROM_RD + i * 2); // send PROM READ command
/*
ret = SPI.transfer(0x00); // send 0 to read the MSB
rC = 256 * ret;
ret = SPI.transfer(0x00); // send 0 to read the LSB
rC = rC + ret;
*/
// send a value of 0 to read the first byte returned:
rC = SPI.transfer( 0x00 );
rC = rC << 8;
rC |= SPI.transfer( 0x00 ); // and the second byte
sensorCoeffs[i] = (rC);
digitalWrite( _cs, HIGH );
delay(3);
}
//SPI.endTransaction(); // interrupt can now be accepted
// The last 4 bits of the 7th coefficient form a CRC error checking code.
unsigned char p_crc = sensorCoeffs[7];
// Use a function to calculate the CRC value
unsigned char n_crc = MS_5803_CRC(sensorCoeffs);
if (Verbose) {
for (int i = 0; i < 8; i++ )
{
// Print out coefficients
Serial.print("C");
Serial.print(i);
Serial.print(" = ");
Serial.println(sensorCoeffs[i]);
delay(10);
}
Serial.print("p_crc: ");
Serial.println(p_crc);
Serial.print("n_crc: ");
Serial.println(n_crc);
}
// If the CRC value doesn't match the sensor's CRC value, then the
// connection can't be trusted. Check your wiring.
if (p_crc != n_crc) {
return false;
}
// Otherwise, return true when everything checks out OK.
return true;
}
// Sends a power on reset command to the sensor.
void MS_5803_SPI::resetSensor() {
SPI.beginTransaction(settings_write);
digitalWrite(_cs, LOW); //csb_lo(); // pull CSB low to start the command
SPI.transfer(CMD_RESET); // send reset sequence
delay(3); // wait for the reset sequence timing delay(3)
digitalWrite(_cs, HIGH); //csb_hi(); // pull CSB high to finish the command
SPI.endTransaction(); // interrupt can now be accepted
}
The Code can be downloaded at: https://forum.arduino.cc/index.php?topic=670661.0
There you can find the schematic and output picture too.
Thanks a lot :).
I have a program that lets an LED pulse. I also connected the PC8574 GPIO expander with a push button. I want to evaluate the keypress. However, I can only read the status of the INT (interrupt) while the program is in the part between making the LED brighter and making it darker again (between the two for loops)
I know that the problem is the delays withing the for loops but I have no idea how to avoid that.
Would it be possible to evaluate the interrupt related code more often or like a real interrupt - always when the actual key is pressed? And if so, how?
I use this library: https://github.com/WereCatf/PCF8574_ESP
/*LED_Breathing.ino Arduining.com 20 AUG 2015
Using NodeMCU Development Kit V1.0
Going beyond Blink sketch to see the blue LED breathing.
A PWM modulation is made in software because GPIO16 can't
be used with analogWrite().
*/
#include <pcf8574_esp.h>
#include <Wire.h>
TwoWire testWire;
// Initialize a PCF8574 at I2C-address 0x20, using GPIO5, GPIO4 and testWire for the I2C-bus
PCF857x pcf8574(0x20, &testWire);
#define LED D1 // Led in NodeMCU at pin GPIO16 (D0).
#define BRIGHT 300 //max led intensity (1-500)
#define INHALE 1250 //Inhalation time in milliseconds.
#define PULSE INHALE*1000/BRIGHT
#define REST 1000 //Rest Between Inhalations.
#define PIN_INT D5
#define PIN_SDA D7
#define PIN_SCL D8
//----- Setup function. ------------------------
void setup() {
Serial.begin(115200);
Wire.pins(PIN_SDA, PIN_SCL);//SDA - D1, SCL - D2
Wire.begin();
pinMode(PIN_INT, INPUT_PULLUP);
pcf8574.begin( 0xFF);
pcf8574.resetInterruptPin();
pinMode(LED, OUTPUT); // LED pin as output.
}
bool CheckKey(byte key, byte num){ //0, 1, 2, 3
return key & (1 << num);
}
//----- Loop routine. --------------------------
void loop() {
//ramp increasing intensity, Inhalation:
for (int i=1;i<BRIGHT;i++){
digitalWrite(LED, LOW); // turn the LED on.
delayMicroseconds(i*10); // wait
digitalWrite(LED, HIGH); // turn the LED off.
delayMicroseconds(PULSE-i*10); // wait
delay(0); //to prevent watchdog firing.
}
if( digitalRead(PIN_INT)==LOW ){
delay(50);
byte b = pcf8574.read8();
Serial.println( "INT: " + String(b));
byte keys = ((~b)) & 0x0F;
if( CheckKey(keys, 8) ){
Serial.println( "KEY 7");
delay(2000);
}
}
//ramp decreasing intensity, Exhalation (half time):
for (int i=BRIGHT-1;i>0;i--){
digitalWrite(LED, LOW); // turn the LED on.
delayMicroseconds(i*10); // wait
digitalWrite(LED, HIGH); // turn the LED off.
delayMicroseconds(PULSE-i*10); // wait
i--;
delay(0); //to prevent watchdog firing.
}
delay(REST); //take a rest...
}
You could use the PCF8574 INT pin as an interrupt to the ESP8266 via Arduino's attachInterrupt() function, but you wouldn't gain much from that, since in order to detect which key was pressed you need to call pcf8574.read8(), and you can't do that from the interrupt handler.
The ESP8266 Arduino core is based on the Espressif NONOS SDK, so you can't have a separate thread to monitor key presses. I would suggest defining a helper function that checks if a key is currently being pressed, and then calling that function as often as you can in your main loop, e.g. at every iteration of each of your two for loops. The LED brightness ramps would be slightly disrupted when there is a key press, but I think it wouldn't be noticeable to the human eye.
So the helper function could be defined as:
byte GetKeyPress(void) {
if (digitalRead(PIN_INT) == LOW) {
return ~pcf8574.read8();
}
else {
return 0;
}
}
Then, at the beginning of the loop() function declare a static variable static byte keyPress;, and call the above function in each of the two for loops:
if (keyPress == 0) {
keyPress = GetKeyPress();
}
When you want to process a key press (e.g. between the two for loops like in your code), you can do like that:
if (keyPress) {
/* Do your stuff. */
keyPress = 0;
}
I have an ATTiny85 connected to an NRF24L01+ module using this wiring diagram: diagram. The ATTiny85 periodically goes in and out of sleep to send some value to a receiver, an Arduino Uno. If the ATTiny is running off the Arduino power supply (3.3v), everything works correctly. When I run the ATTiny off of a separate CR2032 coin cell that delivers around 3v, the Arduino never receives any data. I have a status LED hooked up to the ATTiny to ensure that the ATTiny is waking correctly, which it is. Here's the code for both:
EDIT:
Connecting it to an external 3.3v not from the Uno makes everything work - why wouldn't the coin cell's voltage work? I think everything is rated below 2.8v, the CR2032 minimum.
ATTiny Code
#include <avr/sleep.h>
#include <avr/interrupt.h>
// Routines to set and claer bits (used in the sleep code)
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define CE_PIN 3
#define CSN_PIN 3 //Since we are using 3 pin configuration we will use same pin for both CE and CSN
#include "RF24.h"
RF24 radio(CE_PIN, CSN_PIN);
byte address[11] = "SimpleNode";
unsigned long payload = 0;
void setup() {
radio.begin(); // Start up the radio
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openWritingPipe(address); // Write to device address 'SimpleNode'
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
delay(500);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
delay(500);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
delay(1000);
setup_watchdog(6);
}
volatile int watchdog_counter = 0;
ISR(WDT_vect) {
watchdog_counter++;
}
void loop()
{
sleep_mode(); //Go to sleep!
if(watchdog_counter >= 5)
{
digitalWrite(4, HIGH);
watchdog_counter = 0;
payload = 123456;
radio.write( &payload, sizeof(unsigned long) ); //Send data to 'Receiver' ever second
delay(1000);
digitalWrite(4, LOW);
}
}
//Sleep ATTiny85
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System actually sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
}
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCR = bb;
WDTCR |= _BV(WDIE);
}
Receiver Code
#define CE_PIN 7
#define CSN_PIN 8
#include <SPI.h>
#include "RF24.h"
RF24 radio(CE_PIN, CSN_PIN);
byte address[11] = "SimpleNode";
unsigned long payload = 0;
void setup() {
while (!Serial);
Serial.begin(115200);
radio.begin(); // Start up the radio
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openReadingPipe(1, address); // Write to device address 'SimpleNode'
radio.startListening();
Serial.println("Did Setup");
}
void loop(void){
if (radio.available()) {
radio.read( &payload, sizeof(unsigned long) );
if(payload != 0){
Serial.print("Got Payload ");
Serial.println(payload);
}
}
}
Is the problem here that the ATTiny and Uno need to be turned on at the same time to establish a connection, or is it something to do with the battery, or something else entirely? Any help would be appreciated.
I'm experiencing the same problem when running Arduino Nano from a battery.
Nano has a 3.3V pin that I'm using for powering the NRF24L01+ module.
When the voltage from my battery-pack drops under 3.3V, the 3.3V pin voltage also drops. After few minutes, the RF module is not sending any messages.
I fixed the problem temporarily by routing the battery through a 12V step-up regulator that I bought earlier for a different project. These 12V then go to the "UN" pin on Nano which accepts 6-20V. This setup works nicely but is definitely not optimal.
Therefore I'm planning to use a 3.3V step-up regulator such as Pololu 3.3V Step-Up Voltage Regulator U1V11F3 which, according to the supplier, can efficiently generate 3.3V from input voltages as low as 0.5V.
I think this might be helpful to your project as well.
I'm multiplexing 3 IMU-6050 using a MUX4051. This is the original code:
#include "Wire.h"
const int MPU=0x68; // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
int Acc_ctrl_1 = 9;
int Acc_ctrl_2 = 10;
int Acc_ctrl_3 = 11;
int chip_enable1 = 5;
void setup() {
Wire.begin(); // wake up I2C bus
// set I/O pins to outputs
Wire.beginTransmission(MPU);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
Serial.begin(115200);
pinMode(Acc_ctrl_1, OUTPUT); //S0
pinMode(Acc_ctrl_2, OUTPUT); //S1
pinMode(Acc_ctrl_3, OUTPUT); //S2 address lines
pinMode(chip_enable1, OUTPUT);
//S0=1, S1=2 and S2=4 so Y0= S0=0,S1=0,S2=0, Y4=S0=0,S1=0,S2=1
}
void loop() {
//Enable the MUX Chip 1 - Active Low
digitalWrite(chip_enable1, LOW);
// control signal for First Accelerometer
Serial.println("IMU 1");
digitalWrite(Acc_ctrl_1, LOW);
digitalWrite(Acc_ctrl_2, LOW);
digitalWrite(Acc_ctrl_3, LOW);
readAccele();
delay(500);
// control signal for SECOND Accelerometer
Serial.println("IMU 2");
digitalWrite(Acc_ctrl_1, HIGH);
digitalWrite(Acc_ctrl_2, LOW);
digitalWrite(Acc_ctrl_3, LOW);
readAccele();
delay(500);
// control signal for THIRD Accelerometer
Serial.println("IMU 3");
digitalWrite(Acc_ctrl_1, LOW);
digitalWrite(Acc_ctrl_2, HIGH);
digitalWrite(Acc_ctrl_3, LOW);
readAccele();
delay(500);
}
void readAccele()
{
Wire.beginTransmission(MPU);// I2C address code thanks to John Boxall
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU,14,true); // request a total of 14 registers
AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
Serial.print("AcX = "); Serial.print(AcX);
Serial.print(" | AcY = "); Serial.print(AcY);
Serial.print(" | AcZ = "); Serial.print(AcZ);
Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53); //equation for temperature in degrees C from datasheet
Serial.print(" | GyX = "); Serial.print(GyX);
Serial.print(" | GyY = "); Serial.print(GyY);
Serial.print(" | GyZ = "); Serial.println(GyZ);
delay(5);
}
I implemented it into the Jeff Rowberg example code:
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0)
// 6/21/2012 by Jeff Rowberg <jeff#rowberg.net>
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
bool dmpReady = false; // set true if DMP init was successful
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64];
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
MPU6050 mpu;
// uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
// quaternion components in a [w, x, y, z] format (not best for parsing
// on a remote host such as Processing or something though)
//#define OUTPUT_READABLE_QUATERNION
// uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles
// (in degrees) calculated from the quaternions coming from the FIFO.
// Note that Euler angles suffer from gimbal lock (for more info, see
// http://en.wikipedia.org/wiki/Gimbal_lock)
#define OUTPUT_READABLE_EULER
// uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration
// components with gravity removed and adjusted for the world frame of
// reference (yaw is relative to initial orientation, since no magnetometer
// is present in this case). Could be quite handy in some cases.
#define OUTPUT_READABLE_WORLDACCEL
int Acc_ctrl_1 = 9;
int Acc_ctrl_2 = 10;
int Acc_ctrl_3 = 11;
int chip_enable1 = 5;
int chip_enable2 = 6;
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;
// MPU control/status vars
//uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
pinMode(Acc_ctrl_1, OUTPUT); //S0
pinMode(Acc_ctrl_2, OUTPUT); //S1
pinMode(Acc_ctrl_3, OUTPUT); //S2 address lines
pinMode(chip_enable1, OUTPUT);
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
// (115200 chosen because it is required for Teapot Demo output, but it's
// really up to you depending on your project)
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
while (Serial.available() && Serial.read()); // empty buffer
while (!Serial.available()); // wait for data
while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
}
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
//Enable the MUX Chip 1 - Active Low
digitalWrite(chip_enable1, LOW);
// control signal for First Accelerometer
Serial.println("IMU 1");
digitalWrite(Acc_ctrl_1, LOW);
digitalWrite(Acc_ctrl_2, LOW);
digitalWrite(Acc_ctrl_3, LOW);
readAccele();
delay(500);
// control signal for SECOND Accelerometer
Serial.println("IMU 2");
digitalWrite(Acc_ctrl_1, HIGH);
digitalWrite(Acc_ctrl_2, LOW);
digitalWrite(Acc_ctrl_3, LOW);
readAccele();
delay(500);
// control signal for THIRD Accelerometer
Serial.println("IMU 3");
digitalWrite(Acc_ctrl_1, LOW);
digitalWrite(Acc_ctrl_2, HIGH);
digitalWrite(Acc_ctrl_3, LOW);
readAccele();
delay(500);
}
void readAccele(){
// if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize) {
// other program behavior stuff here
}
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & 0x02) {
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
#ifdef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("quat\t");
Serial.print(q.w);
Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
Serial.println(q.z);
#endif
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180/M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180/M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180/M_PI);
#endif
#ifdef OUTPUT_READABLE_WORLDACCEL
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
Serial.print("aworld\t");
Serial.print(aaWorld.x);
Serial.print("\t");
Serial.print(aaWorld.y);
Serial.print("\t");
Serial.println(aaWorld.z);
#endif
;
}
}
But this is what the serial prints, FIFO Overflow.. I tried to fix it but couldn't. I can't upload an image so Ill copy and paste the serial output here as code...
Send any character to begin DMP programming and demo:
Initializing DMP...
Enabling DMP...
Enabling interrupt detection (Arduino external interrupt 0)...
DMP ready! Waiting for first interrupt...
IMU 1
IMU 2
IMU 3
IMU 1
FIFO overflow!
IMU 2
IMU 3
IMU 1
FIFO overflow!
IMU 2
IMU 3
IMU 1
FIFO overflow!
IMU 2
IMU 3
IMU 1
FIFO overflow!
IMU 2
IMU 3
IMU 1
FIFO overflow!
IMU 2
IMU 3
IMU 1
FIFO overflow!
IMU 2
IMU 3
IMU 1
FIFO overflow!
IMU 2
IMU 3
IMU 1
I have been working on a stable library to get all the useful information using the MPU6050_6Axis_MotionApps20 provided by I2Cdev package. I don't know if it is useful for you, but I upload it for everyone having problems dealing with it:
GYRO.h:
#ifndef GYRO
#define GYRO
#include "Arduino.h"
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
#define INTERRUPT_PIN 2 //24
#define CALIBRATION_LOOPS 500
//Error codes
#define EC_NO_ERROR 0
#define EC_DMP_MEMORY_WRITING_FAILED 1
#define EC_DMP_CONFIG_WRITING_FAILED 2
#define EC_NO_CONNECTION 3
//Offsets, put your own offsets here
#define GYRO_GX_OFFSET 93
#define GYRO_GY_OFFSET 0
#define GYRO_GZ_OFFSET 7
#define GYRO_AX_OFFSET -2550
#define GYRO_AY_OFFSET 1978
#define GYRO_AZ_OFFSET 499
class GYRO{
public:
GYRO(void);
uint8_t begin(void);
void update(void);
//All are made following the arrows with the right hand rule
inline VectorFloat getGyroscope(){return gyroscope; }
//All are made following the arrows
inline VectorDouble getAccelerometer(){return accelerometer; }
//A positive 1, indicates that the gravity is going in the oppsite way of the arrow drawed on the sensor
inline VectorFloat getGravity(){return gravity; }
//Returns the temperature in ºC
inline float getTemperature(){return temperature; }
//The time that has passed for calculating the speed with the acceleration
inline unsigned long getMicrosSpent(){return microsSpent; }
inline bool isGyroscopeUpdated(){return gyroscopeUpdated; }
private:
//Gyroscope
MPU6050 gyro; //Gyroscope configured with pin ADO-LOW
//Gyroscope readings
// MPU control/status vars
uint8_t gyroIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorFloat gravity; // [x, y, z] gravity vector
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
VectorFloat gyroscope; // [x, y, z] gyroscope vector
VectorInt16 rawAccelerometer; // [x, y, z] raw acceleromer
VectorDouble accelerometer; // [x, y, z] accelerometer in m/s2
float temperature; // temperature in ºC
unsigned long lastMicros;
unsigned long actualMicros;
unsigned long microsSpent;
bool gyroscopeUpdated;
int loops_before_calibration;
};
#endif
GYRO.cpp:
#include "GYRO.h"
#include "Arduino.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
volatile bool interrupt = false;
void dmpDataReady(void) {
interrupt = true;
}
GYRO::GYRO(void){
gyro = MPU6050(0x68); //Change to 0x69 if the AD0 pin of your MPU6050 is HIGH
}
uint8_t GYRO::begin(void){
Wire.begin();
Wire.setClock(400000);
uint8_t errorCode;
//Gyro initialization
gyro.initialize();
pinMode(INTERRUPT_PIN, INPUT);
if(gyro.testConnection()){
Serial.println(F("\nSend any character to begin the calibration and initialization of the gyro: "));
while (Serial.available() && Serial.read());
while (!Serial.available());
while (Serial.available() && Serial.read());
devStatus = gyro.dmpInitialize();
gyro.setXGyroOffset(GYRO_GX_OFFSET);
gyro.setYGyroOffset(GYRO_GY_OFFSET);
gyro.setZGyroOffset(GYRO_GZ_OFFSET);
gyro.setXAccelOffset(GYRO_AX_OFFSET);
gyro.setYAccelOffset(GYRO_AY_OFFSET);
gyro.setZAccelOffset(GYRO_AZ_OFFSET);
if (devStatus == 0) {
gyro.setDMPEnabled(true);
lastMicros = micros();
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
gyroIntStatus = gyro.getIntStatus();
packetSize = gyro.dmpGetFIFOPacketSize();
}else if(devStatus == 1) return EC_DMP_MEMORY_WRITING_FAILED;
else if(devStatus == 2) return EC_DMP_CONFIG_WRITING_FAILED;
}else return EC_NO_CONNECTION;
loops_before_calibration = 0;
return EC_NO_ERROR;
}
void GYRO::update(void){
//temperature = gyro.getTemperature()/340.0+36.53; //When discommenting this line i get rarely FIFO overflows, but without it, i have not recived eaither one
gyroscopeUpdated = false;
while (!interrupt && fifoCount < packetSize){
if (interrupt && fifoCount < packetSize){
fifoCount = gyro.getFIFOCount();
}
}
interrupt = false;
gyroIntStatus = gyro.getIntStatus();
fifoCount = gyro.getFIFOCount();
if ((gyroIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024){
gyro.resetFIFO();
fifoCount = gyro.getFIFOCount();
Serial.println(F("FIFO overflow!"));
}else if (gyroIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)){
while (fifoCount < packetSize) fifoCount = gyro.getFIFOCount();
gyro.getFIFOBytes(fifoBuffer, packetSize);
actualMicros = micros();
microsSpent = actualMicros - lastMicros;
lastMicros = actualMicros;
fifoCount -= packetSize;
gyro.dmpGetQuaternion(&q, fifoBuffer);
gyro.dmpGetGravity(&gravity, &q);
gyro.dmpGetYawPitchRoll(ypr, &q, &gravity);
gyro.dmpGetAccel(&rawAccelerometer, fifoBuffer);
gyro.dmpGetLinearAccel(&rawAccelerometer, &rawAccelerometer, &gravity);
//gyro.dmpGetLinearAccelInWorld(&rawAccelerometer, &rawAccelerometer, &q);
accelerometer.x = rawAccelerometer.x/8192.0*9.8;
accelerometer.y = rawAccelerometer.y/8192.0*9.8;
accelerometer.z = rawAccelerometer.z/8192.0*9.8;
gyroscope.x = ypr[2];
gyroscope.y = ypr[1]*-1;
gyroscope.z = ypr[0]*-1;
if(loops_before_calibration > CALIBRATION_LOOPS){
gyroscopeUpdated = true;
}else loops_before_calibration++;
}
}
Example code(To upload to arduino):
#include <GYRO.h>
#include <helper_3dmath.h>
GYRO gyro = GYRO();
VectorFloat gravity;
VectorFloat gyroscope;
VectorDouble accelerometer;
void setup() {
Serial.begin(115200);
Serial.println(gyro.begin());
}
void loop() {
gyro.update();
if(gyro.isGyroscopeUpdated()){
gravity = gyro.getGravity();
accelerometer = gyro.getAccelerometer();
gyroscope = gyro.getGyroscope();
Serial.print("gyroscope\t");
Serial.print(gyroscope.x * 180/M_PI);
Serial.print("\t");
Serial.print(gyroscope.y * 180/M_PI);
Serial.print("\t");
Serial.print(gyroscope.z * 180/M_PI);
Serial.print("\taccelerometer\t");
Serial.print(accelerometer.x);
Serial.print("\t");
Serial.print(accelerometer.y);
Serial.print("\t");
Serial.print(accelerometer.z);
Serial.print("\tgravity\t");
Serial.print(gravity.x);
Serial.print("\t");
Serial.print(gravity.y);
Serial.print("\t");
Serial.print(gravity.z);
Serial.print("\ttemperature\t");
Serial.print(gyro.getTemperature());
Serial.print(", micros: ");
Serial.println(gyro.getMicrosSpent());
}
}
You have to provide your own offsets. To obtain it, you can use this link
I hope this code is useful.
I know it is too late but maybe will help others...
The first MPU6050 initialization part in the setup() is done before even the mux initialized.
So you have to do the following, inside the setup(), at the right order:
initialize wire
initialize the outputs for the mux
select the first MPU using the right output levels
initialize the first MPU6050
select the second MPU using the right output levels
initialize the second MPU6050
select the third MPU using the right output levels
initialize the third MPU6050
The code is below, slightly modified from a tutorial. I am working on a Teensy3.1. I added #include <SoftwareSerial.h> but it did not help. I also tried SerialUSB.begin(9600); instead of WiredSerial.begin(9600); //use native port on Due
#include <SoftwareSerial.h>
//minimal sketch for connection to ADS129n family. Load this script and open Tools/SerialMonitor.
//You should see text like this
// Device Type (ID Control Register): 62 Channels: 8
//If you see "Channels: 0" then check your wiring
#include "ads1298.h"
#include "adsCMD.h"
#include <Arduino.h>
#include <SPI.h> // include the SPI library:
int gMaxChan = 0; //maximum number of channels supported by ads129n = 4,6,8
int gIDval = 0; //Device ID : lower 5 bits of ID Control Register
int activeSerialPort = 0; //data will be sent to serial port that last sent commands. E.G. bluetooth or USB port
const int kPIN_LED = 13;//pin with in-built light - typically 13, 11 for Teensy 2.0.
#if defined(__SAM3X8E__)
#define isDUE //Detect Arduino Due
#define WiredSerial SerialUSB //Use Due's Native port
#else
#define WiredSerial Serial
#endif
void setup(){
using namespace ADS1298;
//prepare pins to be outputs or inputs
//pinMode(PIN_SCLK, OUTPUT); //optional - SPI library will do this for us
//pinMode(PIN_DIN, OUTPUT); //optional - SPI library will do this for us
//pinMode(PIN_DOUT, INPUT); //optional - SPI library will do this for us
pinMode(IPIN_CS, OUTPUT);
pinMode(PIN_START, OUTPUT);
pinMode(IPIN_DRDY, INPUT);
//pinMode(PIN_CLKSEL, OUTPUT);//*optional
//pinMode(IPIN_RESET, OUTPUT);//*optional
//pinMode(IPIN_PWDN, OUTPUT);//*optional
//start small peripheral interface
SPI.begin();
SPI.setBitOrder(MSBFIRST);
#ifndef isDUE
SPI.setClockDivider(SPI_CLOCK_DIV4); //http://forum.pjrc.com/threads/1156-Teensy-3-SPI-Basic-Clock-Questions
#endif
SPI.setDataMode(SPI_MODE1);
//Start ADS1298
delay(500); //wait for the ads129n to be ready - it can take a while to charge caps
adc_send_command(SDATAC); // Send SDATAC Command (Stop Read Data Continuously mode)
delay(10);
// Determine model number and number of channels available
gIDval = adc_rreg(ID); //lower 5 bits of register 0 reveal chip type
switch (gIDval & B00011111 ) { //least significant bits reports channels
case B10000: //16
gMaxChan = 4; //ads1294
break;
case B10001: //17
gMaxChan = 6; //ads1296
break;
case B10010: //18
gMaxChan = 8; //ads1298
break;
case B11110: //30
gMaxChan = 8; //ads1299
break;
default:
gMaxChan = 0;
}
//start serial port
SerialUSB.begin(9600); //use native port on Due
//WiredSerial.begin(9600); //use native port on Due
while (WiredSerial.read() >= 0) {} //http://forum.arduino.cc/index.php?topic=134847.0
//while (!WiredSerial) ; //required by Leonardo http://arduino.cc/en/Serial/IfSerial (ads129n requires 3.3v signals, Leonardo is 5v)
delay(200); // Catch Due reset problem
pinMode(kPIN_LED, OUTPUT);
}
void loop()
{
WiredSerial.print("Device Type (ID Control Register): "); SerialUSB.print(gIDval); SerialUSB.print(" Channels: "); SerialUSB.println(gMaxChan);
digitalWrite(kPIN_LED, HIGH); // turn the LED on (HIGH is the voltage level)
if (gMaxChan > 0)
delay(500); //long pause if OK
else
delay(50); //rapid blink if error
digitalWrite(kPIN_LED, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
Try using Serial instead of SerialUSB, I've tried it while using Arduino UNO.