msp432搭建平衡小车(二)

2023-03-28 23:00   222   0  

前言


上一节掌握了使用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加速度传感器满量程范围


登录icspec成功后,会自动跳转查看全文
博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。