去年电赛备赛期间,我学到了STM32标准库,整个繁琐直接劝退了我。MPU6050年非常痛苦,代码无法理解是抄来抄去,然后是编译,改错,编译无穷。最近参考野火MPU6050代码移植到MSP430f5529之上,今天分享出来。
1.重要性
MPU6050模块是平衡车和四旋翼无人机开发的重要模块。此外,四轮车的转弯闭环控制也非常重要,因此备战电赛控制是不可避免的模块。该模块包括陀螺仪和加速度传感器x,y,z三个方向的角度和各个方向的角速度使用非常方便,这次没有官方使用DMP库。
2.代码
废话不多说,直接上代码,调用。
/* * MPU6050.c * * Created on: 2022年7月17日 * Author: S10 */ #include "driverlib.h" #include "mpu6050.h" void ByteWrite6050(unsigned char REG_Address,unsigned char REG_data); unsigned char ByteRead6050(unsigned char REG_Address); int Get6050Data(unsigned char REG_Address); void InitMPU6050(); float Mpu6050AccelAngle(char dir); float Mpu6050GyroAngle(char dir); ////打开信号 void IIC_start() { SDA_OUT; SCL_OUT; SCL_HIGH; SDA_HIGH; __delay_cycles(10); SDA_LOW; __delay_cycles(10); SCL_LOW; } ////停止信号 void IIC_stop() { SDA_OUT; SCL_OUT; SDA_LOW; SCL_HIGH; __delay_cycles(10); SDA_HIGH; __delay_cycles(10); } //发送应答信号(MCU=>||) void SendACK(unsigned char ack) { SDA_OUT; SCL_OUT; if(ack==1) { SDA_HIGH; } else if(ack==0) { SDA_LOW; } else return; SCL_HIGH; __delay_cycles(10); SCL_LOW; __delay_cycles(10); } 接收应答信号(||=>MCU) unsigned char IIC_testACK() { unsigned char a; SCL_OUT; SDA_IN; //GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P8, GPIO_PIN2); SCL_HIGH; __delay_cycles(10); if(GPIO_getInputPinValue (GPIO_PORT_P8, GPIO_PIN2)==1) { a=1; } else { a=0; } SCL_LOW; __delay_cycles(10); SDA_OUT; return a; } ///向IIC总线发送数据(MCU=>||) void IIC_writebyte(unsigned char IIC_byte) { unsigned char i; SDA_OUT; SCL_OUT; // SCL_LOW; for (i=0; i<8; i++) //8位计数器 { if((IIC_byte<<i)&0x80) { SDA_HIGH; } else { SDA_LOW; } __delay_cycles(10); SCL_HIGH; __delay_cycles(10); SCL_LOW; // __delay_cycles(10); // IIC_byte<<=1; } IIC_testACK(); } IIC接收一个字节(||——>MCU) unsigned char IIC_readebyte(void) { unsigned char i,k=0; SDA_IN; GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P8, GPIO_PIN2); SCL_OUT; SCL_LOW; __delay_cycles(100); for(i=0;i<8;i++) { SCL_HIGH; k=k<<1; if(SDA) k|=1; SCL_LOW; __delay_cycles(100); } SDA_OUT; __delay_cycles(100); return k; } //************************************** //向I2C设备写入一个字节数据 //************************************** void ByteWrite6050(unsigned char REG_Address,unsigned char REG_data) { IIC_start(); //起始信号 IIC_writebyte(SlaveAddress); //发送设备地址+写信号 IIC_writebyte(REG_Address); //内部寄存器地址, IIC_writebyte(REG_data); //内部寄存器数据, IIC_stop(); //发送停止信号 } //************************************** //从I2C设备读取一个字节数据 //************************************** unsigned char ByteRead6050(unsigned char REG_Address) { unsigned char REG_data; IIC_start(); //起始信号 IIC_writebyte(SlaveAddress); //发送设备地址+写信号 IIC_writebyte(REG_Address); //发送存储单元地址,从0开始 IIC_start(); //起始信号 IIC_writebyte(SlaveAddress+1); //发送设备地址+读信号 REG_data=IIC_readebyte(); //读出寄存器数据 SendACK(1); //接收应答信号 IIC_stop(); //停止信号 return REG_data; } //************************************** //合成数据 //************************************** int Get6050Data(unsigned char REG_Address) { char H,L; H=ByteRead6050(REG_Address); L=ByteRead6050(REG_Address+1); return (H<<8)+L; //合成数据 } //************************************** //初始化MPU6050 //************************************** void InitMPU6050() { ByteWrite6050(PWR_MGMT_1, 0x00); // 解除休眠状态 ByteWrite6050(SMPLRT_DIV, 0x07); // 陀螺仪采样率设置(125HZ) ByteWrite6050(CONFIG, 0x06); // 低通
滤波器设置(5HZ频率) ByteWrite6050(GYRO_CONFIG, 0x18); // 陀螺仪自检及检测范围设置(不自检,16.4LSB/DBS/S) ByteWrite6050(ACCEL_CONFIG, 0x01); // 不自检,量程2g } /* ********************************************** **函数名 :float Mpu6050AccelAngle(int8 dir) **函数功能:输出加速度传感器测量的倾角值 ** 范围为2g时,换算关系:16384 LSB/g ** 角度较小时,x=sinx得到角度(弧度), deg = rad*180/3.14 ** 因为x>=sinx,故乘以1.2适当放大 **返回参数:测量的倾角值 **传入参数:dir - 需要测量的方向 ** ACCEL_XOUT - X方向 ** ACCEL_YOUT - Y方向 ** ACCEL_ZOUT - Z方向 ********************************************** */ float Mpu6050AccelAngle(char dir) { float accel_agle; // 测量的倾角值 float result; // 测量值缓存变量 result = (float)Get6050Data(dir); // 测量当前方向的加速度值,转换为浮点数 accel_agle = (result + MPU6050_ZERO_ACCELL)/16384; // 去除零点偏移,计算得到角度(弧度) accel_agle = accel_agle*1.2*180/3.14; //弧度转换为度 return accel_agle; // 返回测量值 } /* ********************************************** **函数名 :float Mpu6050GyroAngle(int8 dir) **函数功能:输出陀螺仪测量的倾角加速度 ** 范围为2000deg/s时,换算关系:16.4 LSB/(deg/s) **返回参数:测量的倾角加速度值 **传入参数:dir - 需要测量的方向 ** GYRO_XOUT - X轴方向 ** GYRO_YOUT - Y轴方向 ** GYRO_ZOUT - Z轴方向 ********************************************** */ float Mpu6050GyroAngle(char dir) { float gyro_angle; gyro_angle = (float)Get6050Data(dir); // 检测陀螺仪的当前值 gyro_angle = -(gyro_angle + MPU6050_ZERO_GYRO)/16.4; //去除零点偏移,计算角速度值,负号为方向处理 return gyro_angle; // 返回测量值 }
/* * MPU6050.h * * Created on: 2022年7月17日 * Author: S10 */
#ifndef MPU6050_H_
#define MPU6050_H_
//********Mpu6050的零点校准值**************
#define MPU6050_ZERO_ACCELL 378
#define MPU6050_ZERO_GYRO 13
//*************定义MPU6050内部地址*******************
#define SMPLRT_DIV 0x19 //输出8位无符号位,输出分频,用来配置采样频率的寄存器。采样率=陀螺仪的输出率/(1+该寄存器值),低通滤波器使能时陀螺仪输出为8k,反之1k。
#define CONFIG 0x1A //配置低通滤波器的寄存器
#define GYRO_CONFIG 0x1B //三个方向角度的自我测试和量程
#define ACCEL_CONFIG 0x1C //三个方向加速度的自我测试和量程
/***************加速度传感器寄存器******************/
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_XOUT ACCEL_XOUT_H // X轴读取地址,高位为起始位
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_YOUT ACCEL_YOUT_H // Y轴读取地址,高位为起始位
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define ACCEL_ZOUT ACCEL_ZOUT_H // Z轴读取地址,高位为起始位
/*****************温度传感器寄存器****************/
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define TEMP_OUT TEMP_OUT_H // 温度传感器读取地址,高位为起始位
//
/陀螺仪相关寄存器//
//
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_XOUT GYRO_XOUT_H // 陀螺仪X轴读取地址,高位为起始位
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_YOUT GYRO_YOUT_H // 陀螺仪Y轴读取地址,高位为起始位
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define GYRO_ZOUT GYRO_ZOUT_H // 陀螺仪Z轴读取地址,高位为起始位
///
其它寄存器/
//
#define PWR_MGMT_1 0x6B //电源管理
#define WHO_AM_I 0x75 //6位iic地址,最后一位A0控制
//
///iic地址设置
/
#define SlaveAddress 0xD0 //A0接地,若接3.3v则0xD1
extern void ByteWrite6050(unsigned char REG_Address,unsigned char REG_data);
extern unsigned char ByteRead6050(unsigned char REG_Address);
extern int Get6050Data(unsigned char REG_Address);
extern void InitMPU6050();
extern float Mpu6050AccelAngle(char dir);
extern float Mpu6050GyroAngle(char dir);
#define SCL_HIGH P1OUT|=BIT2
#define SCL_LOW P1OUT&=~BIT2
#define SDA_HIGH P1OUT|=BIT3
#define SDA_LOW P1OUT&=~BIT3
#define SDA_OUT P1DIR|=BIT3
#define SDA_IN P1DIR&=~BIT3
#define SCL_OUT P1DIR|=BIT2
#define SDA P1IN&BIT3
void IIC_start();//开始
void IIC_stop();//停止
void SendACK(unsigned char ack);//向iic发送标志
void IIC_writebyte(unsigned char IIC_byte);///接收iic标志
unsigned char IIC_testACK();///发送数据
unsigned char IIC_readebyte();///接收数据
#endif /* MPU6050_H_ */