前言
上一节掌握了使用pwm驱动电机,接下来介绍如何使用msp432读取mpu6050数据
正文
首先我们得知道mpu6050通信方式,由于mpu6050只能用i2c通信,所以学会使用msp432的i2c,msp432的i2c驱动可以调用driverlib库来使用msp432的硬件i2c,但是i2c库方法复杂使用起来会比较麻烦,
这里我选择偷个懒,用软件方式模拟i2c驱动。
I2C
建立一个my_i2c.h
/*
* my_i2c.h
*
* Created on: 2021年7月29日
* Author: Administrator
*/
#ifndef MY_I2C_H_
#define MY_I2C_H_
#include
#include
#define SDA_IN() GPIO_setAsInputPin(GPIO_PORT_P6,GPIO_PIN4)
#define SDA_OUT() GPIO_setAsOutputPin(GPIO_PORT_P6,GPIO_PIN4)
#define IIC_SCL_High() GPIO_setOutputHighOnPin(GPIO_PORT_P6,GPIO_PIN5) //SCL_High
#define IIC_SCL_Low() GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN5) //SCL_Low
#define IIC_SDA_High() GPIO_setOutputHighOnPin(GPIO_PORT_P6,GPIO_PIN4) //SDA_High
#define IIC_SDA_Low() GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN4) //SDA_Low
#define READ_SDA GPIO_getInputPinValue(GPIO_PORT_P6,GPIO_PIN4) //输入SDA
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(uint8_t txd); //IIC发送一个字节
uint8_t IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
uint8_t IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
#endif /* MY_I2C_H_ */
my_i2c.c
/*
* my_i2c.c
*
* Created on: 2021年7月29日
* Author: Administrator
*/
#include
void IIC_Init (void){
GPIO_setAsOutputPin(GPIO_PORT_P6,GPIO_PIN5 ); //CLK
GPIO_setAsOutputPin(GPIO_PORT_P6,GPIO_PIN4);//DIN
IIC_SCL_High();
IIC_SDA_High();
}
void IIC_Start(void)//SDA 10 SCL 010
{
SDA_OUT(); //sda线输出
IIC_SCL_High();
IIC_SDA_High();
delay_us(4);
IIC_SDA_Low();//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL_Low();//钳住I2C总线,准备发送或接收数据
}
void IIC_Stop(void)//SDA 01 SCL 01
{
SDA_OUT();//sda线输出
IIC_SCL_Low();//STOP:when CLK is high DATA change form low to high
IIC_SDA_Low();
delay_us(4);
IIC_SCL_High();
IIC_SDA_High();//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
uint8_t IIC_Wait_Ack(void)//
{
uint8_t cy;
SDA_IN(); //SDA设置为输入
IIC_SCL_High();delay_us(10);
IIC_SDA_High();delay_us(10);
if(READ_SDA)
{
cy=1;
IIC_SCL_Low();
return cy;
}
else
{
cy=0;
}
IIC_SCL_Low();//时钟输出0
return cy;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL_Low();
SDA_OUT();
IIC_SDA_Low();
delay_us(2);
IIC_SCL_High();
delay_us(2);
IIC_SCL_Low();
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL_Low();
SDA_OUT();
IIC_SDA_High();
delay_us(2);
IIC_SCL_High();
delay_us(2);
IIC_SCL_Low();
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
IIC_SCL_Low();//拉低时钟开始数据传输
delay_us(2);
for(t=0;t<8;t++)
{
if(txd&0x80)
{
IIC_SDA_High();delay_us(2);
}
else
{
IIC_SDA_Low();delay_us(2);
}
txd<<=1;
IIC_SCL_High();
delay_us(4);
IIC_SCL_Low();
delay_us(2);
}
delay_us(2);
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL_Low();
delay_us(2);
IIC_SCL_High();
receive<<=1;
if(READ_SDA)
receive++;
delay_us(2);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
好了到这里i2c驱动有了,就可以继续下一步了
MPU6050
mpu6050.h
/*
* MPU6050.H
*
* Created on: 2021年7月29日
* Author: Administrator
*/
#ifndef MPU6050_H_
#define MPU6050_H_
#include
#include
#include
#include
#include
#include
#include
#define MPU6050_ADDR 0x68
#define MPU6050_SMPLRT_DIV 0x19
#define MPU6050_CONFIG 0x1a
#define MPU6050_GYRO_CONFIG 0x1b
#define MPU6050_ACCEL_CONFIG 0x1c
#define MPU6050_WHO_AM_I 0x75
#define MPU6050_PWR_MGMT_1 0x6b
#define MPU6050_PWR_MGMT_2 0x6c
#define MPU_ACCEL_XOUTH_REG 0x3b
#define MPU_GYRO_XOUTH_REG 0x43
#define MPU6050_TEMP_H 0x41
#define MPU6050_TEMP_L 0x42
#define MPU_DEVICE_ID_REG 0x75
typedef uint8_t u8;
typedef uint16_t u16;
#define PI 3.1415926535897932384626433832795
extern int16_t rawAccX, rawAccY, rawAccZ,rawGyroX, rawGyroY, rawGyroZ;
extern float gyroXoffset, gyroYoffset, gyroZoffset;
extern float temp, accX, accY, accZ, gyroX, gyroY, gyroZ;
extern float angleGyroX, angleGyroY, angleGyroZ,angleAccX, angleAccY, angleAccZ;
extern float angleX, angleY, angleZ;
extern uint32_t timer;
extern float accCoef;
extern float gyroCoef;
u8 MPU_Init(void);
void calcGyroOffsets(void);
void mpu_update(void);
u8 MPU_Set_Gyro_Fsr(u8 fsr);
u8 MPU_Set_Accel_Fsr(u8 fsr);
u8 MPU_Set_LPF(u16 lpf);
u8 MPU_Set_Rate(u16 rate);
short MPU_Get_Temperature();
u8 MPU_Get_Gyroscope(int16_t *gx,int16_t *gy,int16_t *gz);
u8 MPU_Get_Accelerometer(int16_t *ax,int16_t *ay,int16_t *az);
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf);
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf);
u8 MPU_Write_Byte(u8 reg,u8 data);
u8 MPU_Read_Byte(u8 reg);
#endif /* MPU6050_H_ */
mpu6050.c
/*
* MPU6050.C
*
* Created on: 2021年7月29日
* Author: Administrator
*/
#include
int16_t rawAccX, rawAccY, rawAccZ,rawGyroX, rawGyroY, rawGyroZ;
float gyroXoffset, gyroYoffset, gyroZoffset;
float temp, accX, accY, accZ, gyroX, gyroY, gyroZ;
float angleGyroX, angleGyroY, angleGyroZ,angleAccX, angleAccY, angleAccZ;
float angleX, angleY, angleZ;
float gyroCoef,accCoef;
uint32_t timer,preInterval;
float interval;
u8 MPU_Init(void)
{
accCoef = 0.02;
gyroCoef = 0.98;
IIC_Init();
MPU_Write_Byte(MPU6050_SMPLRT_DIV, 0x00);
MPU_Write_Byte(MPU6050_CONFIG, 0x00);
MPU_Write_Byte(MPU6050_GYRO_CONFIG, 0x08);
MPU_Write_Byte(MPU6050_ACCEL_CONFIG, 0x00);
MPU_Write_Byte(MPU6050_PWR_MGMT_1,0X01);
mpu_update();
angleGyroX = 0;
angleGyroY = 0;
preInterval = timer;
return 0;
}
void calcGyroOffsets(void){
float x = 0, y = 0, z = 0;
int16_t rx, ry, rz;
int i;
for(i =0; i < 1000; i++){
MPU_Get_Gyroscope(&rx,&ry,&rz);
x += ((float)rx) / 65.5;
y += ((float)ry) / 65.5;
z += ((float)rz) / 65.5;
}
gyroXoffset = x / 1000;
gyroYoffset = y / 1000;
gyroZoffset = z / 1000;
}
void mpu_update(void){
MPU_Get_Accelerometer(&rawAccX, &rawAccY, &rawAccZ);
temp = MPU_Get_Temperature();
MPU_Get_Gyroscope(&rawGyroX,&rawGyroY,&rawGyroZ);
accX = ((float)rawAccX) / 16384.0;
accY = ((float)rawAccY) / 16384.0;
accZ = ((float)rawAccZ) / 16384.0;
angleAccX = atan2(accY, accZ + abs(accX)) * 360 / 2.0 / PI;
angleAccY = atan2(accX, accZ + abs(accY)) * 360 / -2.0 / PI;
gyroX = ((float)rawGyroX) / 65.5;
gyroY = ((float)rawGyroY) / 65.5;
gyroZ = ((float)rawGyroZ) / 65.5;
gyroX -= gyroXoffset;
gyroY -= gyroYoffset;
gyroZ -= gyroZoffset;
angleGyroX += gyroX * interval;
angleGyroY += gyroY * interval;
angleGyroZ += gyroZ * interval;
interval = (timer - preInterval) * 0.001;
angleX = (gyroCoef * (angleX + gyroX * interval)) + (accCoef * angleAccX);
angleY = (gyroCoef * (angleY + gyroY * interval)) + (accCoef * angleAccY);
angleZ = angleGyroZ;
preInterval = timer ;
}
//设置MPU6050陀螺仪传感器满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
// 其他,设置失败
u8 MPU_Set_Gyro_Fsr(u8 fsr)
{
return MPU_Write_Byte(MPU6050_GYRO_CONFIG,fsr<<3);//设置陀螺仪满量程范围
}
//设置MPU6050加速度传感器满量程范围