// MPU-6050 Accelerometer + Gyro // ----------------------------- // // By arduino.cc user "Krodal". // June 2012 // Open Source / Public Domain // Modified by Debra - http://www.geekmomprojects.com/gyroscopes-and-accelerometers-on-a-chip/ // // Using Arduino 1.0.1 // It will not work with an older version, // since Wire.endTransmission() uses a parameter // to hold or release the I2C bus. // // Documentation: // - The InvenSense documents: // - "MPU-6000 and MPU-6050 Product Specification", // PS-MPU-6000A.pdf // - "MPU-6000 and MPU-6050 Register Map and Descriptions", // RM-MPU-6000A.pdf or RS-MPU-6000A.pdf // - "MPU-6000/MPU-6050 9-Axis Evaluation Board User Guide" // AN-MPU-6000EVB.pdf // // The accuracy is 16-bits. // // Temperature sensor from -40 to +85 degrees Celsius // 340 per degrees, -512 at 35 degrees. // // At power-up, all registers are zero, except these two: // Register 0x6B (PWR_MGMT_2) = 0x40 (I read zero). // Register 0x75 (WHO_AM_I) = 0x68. // #include "MPU6050.h" //quote marks are local #include //<> is global #define output(directions,pin) (directions |= pin) // set port direction for output #define set(port,pin) (port |= pin) // set port pin #define clear(port,pin) (port &= (~pin)) // clear port pin #define pin_test(pins,pin) (pins & pin) // test for port pin #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set #define bit_delay_time 104 // bit delay for 9600 with overhead #define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay #define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay #define char_delay() _delay_ms(10) // char delay // The name of the sensor is "MPU-6050". // For program code, I omit the '-', // therefor I use the name "MPU6050....". #define serial_port PORTA #define serial_direction DDRA //#define serial_pins PINA //#define serial_pin_in (1 << PA4) #define serial_pin_out (1 << PA5) //Spoon state definitions int SpoonState = 0; int lastSpoonState = 0; int SpoonStates[3]; #define SpoonDown 1 #define SpoonFlat 2 #define Spoops 3 // Declaring an union for the registers and the axis values. // The byte order does not match the byte order of // the compiler and AVR chip. // The AVR chip (on the Arduino board) has the Low Byte // at the lower address. // But the MPU-6050 has a different order: High Byte at // lower address, so that has to be corrected. // The register part "reg" is only used internally, // and are swapped in code. typedef union accel_t_gyro_union { struct { uint8_t x_accel_h; uint8_t x_accel_l; uint8_t y_accel_h; uint8_t y_accel_l; uint8_t z_accel_h; uint8_t z_accel_l; uint8_t t_h; uint8_t t_l; uint8_t x_gyro_h; uint8_t x_gyro_l; uint8_t y_gyro_h; uint8_t y_gyro_l; uint8_t z_gyro_h; uint8_t z_gyro_l; } reg; struct { int16_t x_accel; int16_t y_accel; int16_t z_accel; int16_t temperature; int16_t x_gyro; int16_t y_gyro; int16_t z_gyro; } value; }; int read_gyro_accel_vals(uint8_t* accel_t_gyro_ptr) { // Read the raw values. // Read 14 bytes at once, // containing acceleration, temperature and gyro. // With the default settings of the MPU-6050, // there is no filter enabled, and the values // are not very stable. Returns the error value accel_t_gyro_union* accel_t_gyro = (accel_t_gyro_union *) accel_t_gyro_ptr; int error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) accel_t_gyro, sizeof(*accel_t_gyro)); // Swap all high and low bytes. // After this, the registers values are swapped, // so the structure name like x_accel_l does no // longer contain the lower byte. uint8_t swap; #define SWAP(x,y) swap = x; x = y; y = swap SWAP ((*accel_t_gyro).reg.x_accel_h, (*accel_t_gyro).reg.x_accel_l); SWAP ((*accel_t_gyro).reg.y_accel_h, (*accel_t_gyro).reg.y_accel_l); SWAP ((*accel_t_gyro).reg.z_accel_h, (*accel_t_gyro).reg.z_accel_l); SWAP ((*accel_t_gyro).reg.t_h, (*accel_t_gyro).reg.t_l); SWAP ((*accel_t_gyro).reg.x_gyro_h, (*accel_t_gyro).reg.x_gyro_l); SWAP ((*accel_t_gyro).reg.y_gyro_h, (*accel_t_gyro).reg.y_gyro_l); SWAP ((*accel_t_gyro).reg.z_gyro_h, (*accel_t_gyro).reg.z_gyro_l); return error; } void put_char(volatile unsigned char *port, unsigned char pin, char txchar) { // // send character in txchar on port pin // assumes line driver (inverts bits) // // start bit // cli(); clear(*port,pin); bit_delay(); // // unrolled loop to write data bits // if bit_test(txchar,0) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,1) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,2) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,3) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,4) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,5) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,6) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,7) set(*port,pin); else clear(*port,pin); bit_delay(); // // stop bit // set(*port,pin); bit_delay(); sei(); // // char delay // bit_delay(); } void put_string(volatile unsigned char *port, unsigned char pin, char *str) { // // print a null-terminated string // static int index; index = 0; do { put_char(port, pin, str[index]); ++index; } while (str[index] != 0); } void setup() { int error; uint8_t c; set(serial_port, serial_pin_out); output(serial_direction, serial_pin_out); put_string(&serial_port, serial_pin_out, "started\n"); // Serial.begin(115200); /* Serial.println(F("InvenSense MPU-6050")); Serial.println(F("June 2012")); */ // Initialize the 'Wire' class for the I2C-bus. Wire.begin(); // default at power-up: // Gyro at 250 degrees second // Acceleration at 2g // Clock source at internal 8MHz // The device is in sleep mode. // error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1); /* Serial.print(F("WHO_AM_I : ")); Serial.print(c,HEX); Serial.print(F(", error = ")); Serial.println(error,DEC); */ // According to the datasheet, the 'sleep' bit // should read a '1'. But I read a '0'. // That bit has to be cleared, since the sensor // is in sleep mode at power-up. Even if the // bit reads '0'. error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1); /* Serial.print(F("PWR_MGMT_2 : ")); Serial.print(c,HEX); Serial.print(F(", error = ")); Serial.println(error,DEC); */ // Clear the 'sleep' bit to start the sensor. MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0); //Initialize the angles //calibrate_sensors(); // // initialize output pins // } void loop() { int error =0; accel_t_gyro_union accel_t_gyro; /* Serial.println(F("")); Serial.println(F("MPU-6050")); */ int16_t x_accel=0; int16_t y_accel=0; int16_t z_accel=0; for (int i = 0; i < 32; i++) { error += read_gyro_accel_vals((uint8_t *) &accel_t_gyro); x_accel += accel_t_gyro.value.x_accel; // y_accel += accel_t_gyro.value.y_accel; // z_accel += accel_t_gyro.value.z_accel; delay(10); } x_accel /= 32; // y_accel /= 32; // z_accel /= 32; //int16_t x = x_accel; //int16_t y = y_accel; //int16_t z = z_accel; /* //declaring the state of the spoon if (x_accel <= -15) SpoonState = SpoonDown; if ((x_accel <= 15) && (x_accel >= -15)) SpoonState = SpoonFlat; if ((x_accel >= 20) || (y_accel >= 60) || (y_accel <= -40)) SpoonState = Spoops; //if the last spoon state is not the same it will print the current state if (lastSpoonState != SpoonState) { lastSpoonState = SpoonState; Serial.println(SpoonState); SpoonStates[2]=SpoonStates[1]; SpoonStates[1]=SpoonStates[0]; SpoonStates[0]=SpoonState; if ((SpoonStates[0]==SpoonFlat) && (SpoonStates[1]==SpoonDown) && (SpoonStates[2]==SpoonFlat)); Serial.println("squirt"); } */ char buff [50]; sprintf (buff, "%02X, %d, %d, %d \n",error , x_accel, y_accel, z_accel); put_string(&serial_port, serial_pin_out, buff); // Delay so we don't swamp the serial port delay(100); //Serial.write(10); } // -------------------------------------------------------- // MPU6050_read // // This is a common function to read multiple bytes // from an I2C device. // // It uses the boolean parameter for Wire.endTransMission() // to be able to hold or release the I2C-bus. // This is implemented in Arduino 1.0.1. // // Only this function is used to read. // There is no function for a single byte. // int MPU6050_read(int start, uint8_t *buffer, int size) { int i, n, error; Wire.beginTransmission(MPU6050_I2C_ADDRESS); n = Wire.write(start); if (n != 1) return (-10); n = Wire.endTransmission(false); // hold the I2C-bus if (n != 0) return (n); // Third parameter is true: relase I2C-bus after data is read. Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true); i = 0; while(Wire.available() && i