mpu6050
今天有点时间,来说说MPU6050吧,MPU-6050为全球首例整合性6轴运动处理组件,整合了3轴陀螺仪、3轴加速器,并含可藉由第二个I2C端口连接其他厂牌之加速器、磁力传感器、或其他传感器的数位运动处理(DMP: Digital Motion Processor)硬件加速引擎,由主要I2C端口以单一数据流的形式,向应用端输出完整的9轴融合演算技术InvenSense的运动处理资料库,可处理运动感测的复杂数据,降低了运动处理运算对操作系统的负荷,并为应用开发提供架构化的API。其与MCU通信是通过I2C,今天是用STM32F401进行读取MPU6050的数据,MPU6050模块的电源我是用的3.3V,另外SCL和SDA两个脚分别接一个3.3K或2K的上拉电阻,先写好底层驱动I2C(由于STM32的硬件I2C不太稳定,此次用的是软件仿真I2C)
#include "i2c.h" #define I2C_Direction_Transmitter ((uint8_t)0x00) #define I2C_Direction_Receiver ((uint8_t)0x01)
#define SCL_H GPIOB->BSRRL = GPIO_Pin_6 /* GPIO_SetBits(GPIOB , GPIO_Pin_6) */ #define SCL_L GPIOB->BSRRH = GPIO_Pin_6 /* GPIO_ResetBits(GPIOB , GPIO_Pin_6) */
#define SDA_H GPIOB->BSRRL = GPIO_Pin_7 /* GPIO_SetBits(GPIOB , GPIO_Pin_7) */ #define SDA_L GPIOB->BSRRH = GPIO_Pin_7 /* GPIO_ResetBits(GPIOB , GPIO_Pin_7) */
#define SCL_read GPIOB->IDR & GPIO_Pin_6 /* GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_6) */ #define SDA_read GPIOB->IDR & GPIO_Pin_7 /* GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_7) */
static void I2C_delay(void) { volatile int i = 7; while (i) i--; }
static bool I2C_Start(void) { SDA_H; SCL_H; I2C_delay(); if (!SDA_read) return false; SDA_L; I2C_delay(); if (SDA_read) return false; SDA_L; I2C_delay(); return true; }
static void I2C_Stop(void) { SCL_L; I2C_delay(); SDA_L; I2C_delay(); SCL_H; I2C_delay(); SDA_H; I2C_delay(); }
static void I2C_Ack(void) { SCL_L; I2C_delay(); SDA_L; I2C_delay(); SCL_H; I2C_delay(); SCL_L; I2C_delay(); }
static void I2C_NoAck(void) { SCL_L; I2C_delay(); SDA_H; I2C_delay(); SCL_H; I2C_delay(); SCL_L; I2C_delay(); }
static bool I2C_WaitAck(void) { SCL_L; I2C_delay(); SDA_H; I2C_delay(); SCL_H; I2C_delay(); if (SDA_read) { SCL_L; return false; } SCL_L; return true; }
static void I2C_SendByte(uint8_t byte) { uint8_t i = 8; while (i--) { SCL_L; I2C_delay(); if (byte & 0x80) SDA_H; else SDA_L; byte <<= 1; I2C_delay(); SCL_H; I2C_delay(); } SCL_L; }
static uint8_t I2C_ReceiveByte(void) { uint8_t i = 8; uint8_t byte = 0;
SDA_H; while (i--) { byte <<= 1; SCL_L; I2C_delay(); SCL_H; I2C_delay(); if (SDA_read) { byte |= 0x01; } } SCL_L; return byte; }
void i2cInit(void) { GPIO_InitTypeDef gpio; RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE);
gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; gpio.GPIO_Speed = GPIO_Speed_2MHz; gpio.GPIO_Mode=GPIO_Mode_OUT; gpio.GPIO_OType= GPIO_OType_OD; gpio.GPIO_PuPd=GPIO_PuPd_UP; GPIO_Init(GPIOB, &gpio); }
bool i2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t len, uint8_t * data) //µÚÒ»¸ö²ÎÊýÊÇÆ÷¼þµØÖ· reg±íʾҪ¶ÁÈ¡µÃÊý¾ÝµÄ¼Ä´æÆ÷µØÖ· lenÊÇÊý¾Ý³¤¶È *dataÊÇ´æ´¢¶Á³öÊý¾ÝµÄÖ¸Õë { int i; if (!I2C_Start()) return false; I2C_SendByte(addr << 1 | I2C_Direction_Transmitter); // ×îºóһλΪ·¢ËÍ»òÕß½ÓÊÕµÄÑ¡Ôñ±ê־λ if (!I2C_WaitAck()) { I2C_Stop(); return false; } I2C_SendByte(reg); I2C_WaitAck(); for (i = 0; i < len; i++) { I2C_SendByte(data[i]); if (!I2C_WaitAck()) { I2C_Stop(); return false; } } I2C_Stop(); return true; }
bool i2cWrite(uint8_t addr, uint8_t reg, uint8_t data) { if (!I2C_Start()) return false; I2C_SendByte(addr << 1 | I2C_Direction_Transmitter); if (!I2C_WaitAck()) { I2C_Stop(); return false; } I2C_SendByte(reg); I2C_WaitAck(); I2C_SendByte(data); I2C_WaitAck(); I2C_Stop(); return true; }
bool i2cRead(uint8_t addr, uint8_t reg, uint8_t len, uint8_t* buf) { if (!I2C_Start()) return false; I2C_SendByte(addr << 1 | I2C_Direction_Transmitter); if (!I2C_WaitAck()) { I2C_Stop(); return false; } while (len) //½«len³¤¶ÈµÄÕâô¶à×ֽڷŵ½*bufÀï { I2C_SendByte(reg); I2C_WaitAck(); I2C_Start(); I2C_SendByte(addr << 1 | I2C_Direction_Receiver); I2C_WaitAck();
*buf = I2C_ReceiveByte(); if (len == 1) I2C_NoAck(); else I2C_Ack(); buf++; len--; reg++; } I2C_Stop(); return true; }
uint16_t i2cGetErrorCounter(void) { // TODO maybe fix this, but since this is test code, doesn't matter. return 0; }
u8 i2cRead_Reg(uint8_t addr, uint8_t reg) { u8 a; if (!I2C_Start()) return false; I2C_SendByte(addr << 1 | I2C_Direction_Transmitter); if (!I2C_WaitAck()) { I2C_Stop(); return false; } I2C_SendByte(reg); I2C_WaitAck(); I2C_Start(); I2C_SendByte(addr << 1 | I2C_Direction_Receiver); I2C_WaitAck(); a = I2C_ReceiveByte(); I2C_NoAck(); I2C_Stop(); return a; }
运用MPU6050得根据其寄存器手册来写代码,芯片的默认地址为0X68,下面是MPU的代码:
uint8_t mpu6050_buffer[14]; S_INT16_XYZ GYRO_OFFSET,ACC_OFFSET; u8 GYRO_OFFSET_OK = 1; u8 ACC_OFFSET_OK = 1; S_INT16_XYZ MPU6050_ACC_LAST,MPU6050_GYRO_LAST; /**************************ʵÏÖº¯Êý******************************************** //½«iic¶ÁÈ¡µ½µÃÊý¾Ý·Ö²ð,·ÅÈëÏàÓ¦¼Ä´æÆ÷ ¼ÓËٶȺͽÇËٶȷֱð¶ÁÈ¡200¸öÈ»ºóȡƽ¾ùÖµ×÷Ϊ³õʼÎó²î Ëã³öÎó²îºó¾Í²»ÔÙÔËÐмÆËãÎó²îµÄ²¿·Ö *******************************************************************************/ void MPU6050_Dataanl(void) //ÿִÐÐÒ»´Î¶ÁÈ¡Ò»×éÊý¾Ý µÚÒ»¸ö200´ÎºóËãÒ»´Îƽ¾ùÖµ×÷ΪÁãƮ֮ºó¾Í²»×Ô¶¯ËãÁãÆ®ÁË { MPU6050_ACC_LAST.X=((((int16_t)mpu6050_buffer[0]) << 8) | mpu6050_buffer[1]) - ACC_OFFSET.X; //¼õÈ¥µÄÁãÆ®ÊǵÚÒ»¸ö200msÄÚËã³öµÄ MPU6050_ACC_LAST.Y=((((int16_t)mpu6050_buffer[2]) << 8) | mpu6050_buffer[3]) - ACC_OFFSET.Y; MPU6050_ACC_LAST.Z=((((int16_t)mpu6050_buffer[4]) << 8) | mpu6050_buffer[5]) - ACC_OFFSET.Z; //Ìø¹ýζÈADC MPU6050_GYRO_LAST.X=((((int16_t)mpu6050_buffer[8]) << 8) | mpu6050_buffer[9]) - GYRO_OFFSET.X; MPU6050_GYRO_LAST.Y=((((int16_t)mpu6050_buffer[10]) << 8) | mpu6050_buffer[11]) - GYRO_OFFSET.Y; MPU6050_GYRO_LAST.Z=((((int16_t)mpu6050_buffer[12]) << 8) | mpu6050_buffer[13]) - GYRO_OFFSET.Z; // if((MPU6050_ACC_LAST.X/8192.0>1.5)||(MPU6050_ACC_LAST.X/8192.0<-1.5)) MPU6050_ACC_LAST.X=0; // if((MPU6050_ACC_LAST.Y/8192.0>1.5)||(MPU6050_ACC_LAST.Y/8192.0<-1.5)) MPU6050_ACC_LAST.Y=0; // if((MPU6050_ACC_LAST.Z/8192.0>1.5)||(MPU6050_ACC_LAST.Z/8192.0<-1.5)) MPU6050_ACC_LAST.Z=0;
if(!GYRO_OFFSET_OK) { static int32_t tempgx=0,tempgy=0,tempgz=0; static uint8_t cnt_g=0; // LED1_ON; if(cnt_g==0) { GYRO_OFFSET.X=0; GYRO_OFFSET.Y=0; GYRO_OFFSET.Z=0; tempgx = 0; tempgy = 0; tempgz = 0; cnt_g = 1; return; } tempgx+= MPU6050_GYRO_LAST.X; tempgy+= MPU6050_GYRO_LAST.Y; tempgz+= MPU6050_GYRO_LAST.Z; if(cnt_g==200) { GYRO_OFFSET.X=tempgx/cnt_g; GYRO_OFFSET.Y=tempgy/cnt_g; GYRO_OFFSET.Z=tempgz/cnt_g; cnt_g = 0; GYRO_OFFSET_OK = 1; // EE_SAVE_GYRO_OFFSET();//±£´æÊý¾Ý return; } cnt_g++; } if(!ACC_OFFSET_OK) { static int32_t tempax=0,tempay=0,tempaz=0; static uint8_t cnt_a=0; // LED1_ON; if(cnt_a==0) { ACC_OFFSET.X = 0; ACC_OFFSET.Y = 0; ACC_OFFSET.Z = 0; tempax = 0; tempay = 0; tempaz = 0; cnt_a = 1; return; } tempax+= MPU6050_ACC_LAST.X; tempay+= MPU6050_ACC_LAST.Y; // tempaz+= MPU6050_ACC_LAST.Z; if(cnt_a==200) { ACC_OFFSET.X=tempax/cnt_a; ACC_OFFSET.Y=tempay/cnt_a; ACC_OFFSET.Z=tempaz/cnt_a; cnt_a = 0; ACC_OFFSET_OK = 1; // EE_SAVE_ACC_OFFSET();//±£´æÊý¾Ý return; } cnt_a++; } }
/**************************ʵÏÖº¯Êý******************************************** //½«iic¶ÁÈ¡µ½µÃÊý¾Ý·Ö²ð,·ÅÈëÏàÓ¦¼Ä´æÆ÷,¸üÐÂMPU6050_Last *******************************************************************************/ void MPU6050_READ(void) { // u8 i; //i2cRead(devAddr,MPU6050_RA_ACCEL_XOUT_H,14,mpu6050_buffer); mpu6050_buffer[0]=i2cRead_Reg(devAddr, MPU6050_RA_ACCEL_XOUT_H); mpu6050_buffer[1]=i2cRead_Reg(devAddr, MPU6050_RA_ACCEL_XOUT_L);
mpu6050_buffer[2]=i2cRead_Reg(devAddr, MPU6050_RA_ACCEL_YOUT_H); mpu6050_buffer[3]=i2cRead_Reg(devAddr, MPU6050_RA_ACCEL_YOUT_L);
mpu6050_buffer[4]=i2cRead_Reg(devAddr, MPU6050_RA_ACCEL_ZOUT_H); mpu6050_buffer[5]=i2cRead_Reg(devAddr, MPU6050_RA_ACCEL_XOUT_L);
mpu6050_buffer[6]=i2cRead_Reg(devAddr, MPU6050_RA_TEMP_OUT_H); mpu6050_buffer[7]=i2cRead_Reg(devAddr, MPU6050_RA_TEMP_OUT_L);
mpu6050_buffer[8]=i2cRead_Reg(devAddr, MPU6050_RA_GYRO_XOUT_H); mpu6050_buffer[9]=i2cRead_Reg(devAddr, MPU6050_RA_GYRO_XOUT_L);
mpu6050_buffer[10]=i2cRead_Reg(devAddr, MPU6050_RA_GYRO_YOUT_H); mpu6050_buffer[11]=i2cRead_Reg(devAddr, MPU6050_RA_GYRO_YOUT_L);
mpu6050_buffer[12]=i2cRead_Reg(devAddr, MPU6050_RA_GYRO_ZOUT_H); mpu6050_buffer[13]=i2cRead_Reg(devAddr, MPU6050_RA_GYRO_ZOUT_L);
}
/**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: u8 IICwriteBit(u8 dev, u8 reg, u8 bitNum, u8 data) *¹¦¡¡¡¡ÄÜ: ¶Á ÐÞ¸Ä Ð´ Ö¸¶¨É豸 Ö¸¶¨¼Ä´æÆ÷Ò»¸ö×Ö½Ú ÖеÄ1¸öλ ÊäÈë dev Ä¿±êÉ豸µØÖ· reg ¼Ä´æÆ÷µØÖ· bitNum ÒªÐÞ¸ÄÄ¿±ê×Ö½ÚµÄbitNumλ data Ϊ0 ʱ£¬Ä¿±ê뽫±»Çå0 ·ñÔò½«±»ÖÃλ ·µ»Ø ³É¹¦ Ϊ1 ʧ°ÜΪ0 *******************************************************************************/ void IICwriteBit(u8 dev, u8 reg, u8 bitNum, u8 data){ u8 b; i2cRead(dev, reg, 1, &b); b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum)); i2cWrite(dev, reg, b); } /**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: u8 IICwriteBits(u8 dev,u8 reg,u8 bitStart,u8 length,u8 data) *¹¦¡¡¡¡ÄÜ: ¶Á ÐÞ¸Ä Ð´ Ö¸¶¨É豸 Ö¸¶¨¼Ä´æÆ÷Ò»¸ö×Ö½Ú ÖеĶà¸öλ ÊäÈë dev Ä¿±êÉ豸µØÖ· reg ¼Ä´æÆ÷µØÖ· bitStart Ä¿±ê×Ö½ÚµÄÆðʼλ length 볤¶È data ´æ·Å¸Ä±äÄ¿±ê×Ö½ÚλµÄÖµ ·µ»Ø ³É¹¦ Ϊ1 ʧ°ÜΪ0 *******************************************************************************/ void IICwriteBits(u8 dev,u8 reg,u8 bitStart,u8 length,u8 data) { u8 b,mask; i2cRead(dev, reg, 1, &b); mask = (0xFF << (bitStart + 1)) | 0xFF >> ((8 - bitStart) + length - 1); data <<= (8 - length); data >>= (7 - bitStart); b &= mask; b |= data; i2cWrite(dev, reg, b); } /**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: void MPU6050_setClockSource(uint8_t source) *¹¦¡¡¡¡ÄÜ: ÉèÖà MPU6050 µÄʱÖÓÔ´ * CLK_SEL | Clock Source * --------+-------------------------------------- * 0 | Internal oscillator * 1 | PLL with X Gyro reference * 2 | PLL with Y Gyro reference * 3 | PLL with Z Gyro reference * 4 | PLL with external 32.768kHz reference * 5 | PLL with external 19.2MHz reference * 6 | Reserved * 7 | Stops the clock and keeps the timing generator in reset *******************************************************************************/ void MPU6050_setClockSource(uint8_t source){ IICwriteBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_CLKSEL_BIT, MPU6050_PWR1_CLKSEL_LENGTH, source); } /** Set full-scale gyroscope range. * @param range New full-scale gyroscope range value * @see getFullScaleRange() * @see MPU6050_GYRO_FS_250 * @see MPU6050_RA_GYRO_CONFIG * @see MPU6050_GCONFIG_FS_SEL_BIT * @see MPU6050_GCONFIG_FS_SEL_LENGTH */ void MPU6050_setFullScaleGyroRange(uint8_t range) { IICwriteBits(devAddr, MPU6050_RA_GYRO_CONFIG, MPU6050_GCONFIG_FS_SEL_BIT, MPU6050_GCONFIG_FS_SEL_LENGTH, range); }
/**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: void MPU6050_setFullScaleAccelRange(uint8_t range) *¹¦¡¡¡¡ÄÜ: ÉèÖà MPU6050 ¼ÓËٶȼƵÄ×î´óÁ¿³Ì *******************************************************************************/ void MPU6050_setFullScaleAccelRange(uint8_t range) { IICwriteBits(devAddr, MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, range); } /**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: void MPU6050_setSleepEnabled(uint8_t enabled) *¹¦¡¡¡¡ÄÜ: ÉèÖà MPU6050 ÊÇ·ñ½øÈë˯Ãßģʽ enabled =1 ˯¾õ enabled =0 ¹¤×÷ *******************************************************************************/ void MPU6050_setSleepEnabled(uint8_t enabled) { IICwriteBit(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, enabled); }
/**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: void MPU6050_setI2CMasterModeEnabled(uint8_t enabled) *¹¦¡¡¡¡ÄÜ: ÉèÖà MPU6050 ÊÇ·ñΪAUX I2CÏßµÄÖ÷»ú *******************************************************************************/ void MPU6050_setI2CMasterModeEnabled(uint8_t enabled) { IICwriteBit(devAddr, MPU6050_RA_USER_CTRL, MPU6050_USERCTRL_I2C_MST_EN_BIT, enabled); }
/**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: void MPU6050_setI2CBypassEnabled(uint8_t enabled) *¹¦¡¡¡¡ÄÜ: ÉèÖà MPU6050 ÊÇ·ñΪAUX I2CÏßµÄÖ÷»ú *******************************************************************************/ void MPU6050_setI2CBypassEnabled(uint8_t enabled) { IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_I2C_BYPASS_EN_BIT, enabled); }
void MPU6050_setDLPF(uint8_t mode) { IICwriteBits(devAddr, MPU6050_RA_CONFIG, MPU6050_CFG_DLPF_CFG_BIT, MPU6050_CFG_DLPF_CFG_LENGTH, mode); } /**************************ʵÏÖº¯Êý******************************************** *º¯ÊýÔÐÍ: void MPU6050_initialize(void) *¹¦¡¡¡¡ÄÜ: ³õʼ»¯ MPU6050 ÒÔ½øÈë¿ÉÓÃ״̬¡£ *******************************************************************************/ u8 MPU6050_INIT(void) { // I2C2_Write_1Byte(0xd0,0x19,0x07);//1khz // I2C2_Write_1Byte(0xd0,0x1a,0x03);//44hzÂ˲¨ // I2C2_Write_1Byte(0xd0,0x1b,0x00);//gyro 250du/s // I2C2_Write_1Byte(0xd0,0x1c,0x08);//acc +-4g // I2C2_Write_1Byte(0xd0,0x24,13);//400khz // I2C2_Write_1Byte(0xd0,0x6a,0x00);//mst_en=0 // I2C2_Write_1Byte(0xd0,0x6b,0x00);//sleep=0 MPU6050_REST(); delay_ms(10); MPU6050_REST(); MPU6050_setClockSource(MPU6050_CLOCK_PLL_XGYRO); //ÉèÖÃʱÖÓ 0x6b 0x01 delay_ms(5); MPU6050_setFullScaleGyroRange(MPU6050_GYRO_FS_2000);//ÍÓÂÝÒÇ×î´óÁ¿³Ì +-2000¶ÈÿÃë delay_ms(5); MPU6050_setFullScaleAccelRange(MPU6050_ACCEL_FS_4); //¼ÓËٶȶÈ×î´óÁ¿³Ì +-4G delay_ms(5); MPU6050_setDLPF(MPU6050_DLPF_BW_42); delay_ms(5); MPU6050_setSleepEnabled(0); //½øÈ빤×÷״̬ delay_ms(5); MPU6050_setI2CMasterModeEnabled(0); //²»ÈÃMPU6050 ¿ØÖÆAUXI2C delay_ms(5); MPU6050_setI2CBypassEnabled(1); //Ö÷¿ØÖÆÆ÷µÄI2CÓë MPU6050µÄAUXI2C ֱͨ¡£¿ØÖÆÆ÷¿ÉÒÔÖ±½Ó·ÃÎÊHMC5883L delay_ms(5); return 0; // //ÅäÖÃMPU6050 µÄÖжÏģʽ ºÍÖжϵçƽģʽ // IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_INT_LEVEL_BIT, 0); // IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_INT_OPEN_BIT, 0); // IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_LATCH_INT_EN_BIT, 1); // IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_INT_RD_CLEAR_BIT, 1); // //¿ªÊý¾Ýת»»Íê³ÉÖÐ¶Ï // IICwriteBit(devAddr, MPU6050_RA_INT_ENABLE, MPU6050_INTERRUPT_DATA_RDY_BIT, 1); }
void MPU6050_REST(void) { IICwriteBit(devAddr,MPU6050_RA_PWR_MGMT_1,7,1); }
下面就将数据通过串口1打印出来: for(a=0;a<14;a++)
{
printf("mpu6050_buffer[%d] is %d \n",a ,mpu6050_buffer[a]);
delay_ms(10);
}