前端开发哪里培训好,一个前端妹子的面试笔记

执行引擎(Execution Engine)总结

  返回  

基于MSP432P401R的MPU6050陀螺仪串口输出姿态角程序

2021/7/21 20:41:54 浏览:

基于MSP432P401R的MPU6050陀螺仪串口输出姿态角程序

目录

基于MSP432P401R的MPU6050陀螺仪串口输出姿态角程序

前言

一、实验器材

二、硬件资源

1.usb转ttl

2.串口1(波特率:9600,P2.2/P2.3)

3.MPU6050陀螺仪控制信号线

三.软件架构

四.代码

五.实验现象

六.注意事项  

总结




前言

最近做电赛申请到了MSP432P401R板子,队友让我开发开发陀螺仪,期间遇到了一些问题,不过都解决了,所以写一篇总结记录一下ouo。

一、实验器材

MSP432P401R MPU6050陀螺仪

二、硬件资源

1.usb转ttl

2.串口1(波特率:9600,P2.2/P2.3)

3.MPU6050陀螺仪控制信号线

SDA <-------------> P6.4 
 SCL <-------------> P6.5 

VCC <-------------> 3.3V   

GND <-------------> GND

三.软件架构

keil5 

四.代码

//main.c 主要配置
#include  "main.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "systeminit.h"
#include "motor.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include  "string.h"
#include "driverlib.h"
#include "delay.h"
#include "usart.h"
#include "uart_calc.h"
#include "motor.h"
//陀螺仪方向设置
static signed char gyro_orientation[9] = { 1, 0, 0,
                                           0, 1, 0,
                                           0, 0, 1};
void Wait_Connection(void)
{
    unsigned char str[8];
    sprintf((char*)str,"sw0.val=1\xff\xff\xff");
    while(keyvalue!=5)
    {
        GPIO_toggleOutputOnPin(GPIO_PORT_P2,GPIO_PIN1);
        USART1PutString(str);
        delay_ms(300);
    }
    GPIO_setOutputLowOnPin(GPIO_PORT_P2,GPIO_PIN1);
}
u8 mpu_dmp_init1(void)
{
	u8 res=0;
            IIC_Init(); 		//初始化IIC总线
            if(1)	//初始化MPU6050
            {	 
            res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器
            if(res)return 1;
            else
            {
                sprintf((char*)str,"1\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL);//设置FIFO
            if(res)return 2;
            else
            {
                sprintf((char*)str,"2\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=mpu_set_sample_rate(DEFAULT_MPU_HZ);	//设置采样率
            if(res)return 3; 
            else
            {
                sprintf((char*)str,"3\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=dmp_load_motion_driver_firmware();		//加载dmp固件
            if(res)return 4; 
            else
            {
                sprintf((char*)str,"4\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向
            if(res)return 5;
            else
            {
                sprintf((char*)str,"5\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP|	//设置dmp功能
                DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
                DMP_FEATURE_GYRO_CAL);
            if(res)return 6;
            else
            {
                sprintf((char*)str,"6\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=dmp_set_fifo_rate(DEFAULT_MPU_HZ);	//设置DMP输出速率(最大不超过200Hz)
            if(res)return 7;
            else
            {
                sprintf((char*)str,"7\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=run_self_test();		//自检
            if(res)return 8;
            else
            {
                sprintf((char*)str,"8\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            res=mpu_set_dmp_state(1);	//使能DMP
            if(res)return 9;
            else
            {
                sprintf((char*)str,"9\r\n");
                USART1PutString(str);
                delay_ms(100);
            }
            }
}
int main(void)
{
        u8 report=0;

        float pitch,roll,yaw; 		//欧拉角
		SystemClockInit(HFXT);//系统时钟初始化(系统主时钟)
		SystemClockInit(DCO);//系统时钟初始化(子系统时钟)
        Usart1tInit();
        MPU_Init();
        mpu_dmp_init(); 
        delay_ms(100);
        while(mpu_dmp_get_data(&pitch,&roll,&yaw))
        {
            sprintf((char*)str,"roll=%f,pitch=%f,yaw=%f\r\n",(roll),(pitch),(yaw));
                    USART1PutString(str);
            delay_ms(100);
        }
        while(1)
        {      
                    mpu_dmp_get_data(&pitch,&roll,&yaw);
        			sprintf((char*)str,"roll=%f,pitch=%f,yaw=%f\r\n",(roll),(pitch),(yaw));
                    USART1PutString(str);
                    delay_ms(100);
         }
}
//myiic.h主要配置
#ifndef __MYIIC_H
#define __MYIIC_H
#include "main.h" 
#include "stdio.h"
//IO方向设置
#define SDA_IN()  GPIO_setAsInputPin(GPIO_PORT_P6,GPIO_PIN4)	//SDA输入模式
#define SDA_OUT() GPIO_setAsOutputPin(GPIO_PORT_P6,GPIO_PIN4) //SDA输出模式
//IO操作函数	 
#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 

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif
//myiic.c主要配置
#include "myiic.h"
#include "delay.h"
#include "oled.h"
#include "usart.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F407开发板
//IIC 驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/5/6
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
// 	

//初始化IIC
void IIC_Init(void)
{			
    GPIO_setAsOutputPin(SCL_PORT,SCL_PIN ); //CLK         
    GPIO_setAsOutputPin(SDA_PORT,SDA_PIN);//DIN
	IIC_SCL_High();
	IIC_SDA_High();
}
//产生IIC起始信号
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总线,准备发送或接收数据 
}	  
//产生IIC停止信号
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,接收应答成功
u8 IIC_Wait_Ack(void)//
{
	u8 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(u8 txd)
{                        
    u8 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   
    u8 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;
}
//mpu6050.c主要配置
#include "mpu6050.h"
#include "main.h"
#include "delay.h"
#include "usart.h"  
#include  "string.h"
#include "oled.h"
#include "stdio.h"
//初始化MPU6050
//返回值:0,成功
//    其他,错误代码
u8 MPU_Init(void)
{ 
	u8 res;
    
	IIC_Init();//初始化IIC总线
    MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);//唤醒MPU6050
    MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80);//初始化MPU6050
    delay_ms(100);
    MPU_Write_Byte(MPU_SAMPLE_RATE_REG,0x07);
    MPU_Write_Byte(MPU_CFG_REG,0x06);
    MPU_Write_Byte(MPU_GYRO_CFG_REG,0x18);
    MPU_Write_Byte(MPU_ACCEL_CFG_REG,0x01);
	MPU_Set_Gyro_Fsr(3);					//陀螺仪传感器,±2000dps
	MPU_Set_Accel_Fsr(0);					//加速度传感器,±2g
	MPU_Set_Rate(50);						//设置采样率50Hz
	MPU_Write_Byte(MPU_INT_EN_REG,0X00);	//关闭所有中断
	MPU_Write_Byte(MPU_USER_CTRL_REG,0X00);	//I2C主模式关闭
	MPU_Write_Byte(MPU_FIFO_EN_REG,0X00);	//关闭FIFO
	MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80);	//INT引脚低电平有效
	res=MPU_Read_Byte(0X75);
    sprintf((char*)str,"res=%d\r\n",res);
    USART1PutString(str);
	if(res==MPU_ADDR)//器件ID正确
	{
		MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);	//设置CLKSEL,PLL X轴为参考
		MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);	//加速度与陀螺仪都工作
		MPU_Set_Rate(50);						//设置采样率为50Hz
 	}else return 1;
	return 0;
}
//设置MPU6050陀螺仪传感器满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_Gyro_Fsr(u8 fsr)
{
	return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);//设置陀螺仪满量程范围  
}
//设置MPU6050加速度传感器满量程范围
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_Accel_Fsr(u8 fsr)
{
	return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);//设置加速度传感器满量程范围  
}
//设置MPU6050的数字低通滤波器
//lpf:数字低通滤波频率(Hz)
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_LPF(u16 lpf)
{
	u8 data=0;
	if(lpf>=188)data=1;
	else if(lpf>=98)data=2;
	else if(lpf>=42)data=3;
	else if(lpf>=20)data=4;
	else if(lpf>=10)data=5;
	else data=6; 
	return MPU_Write_Byte(MPU_CFG_REG,data);//设置数字低通滤波器  
}
//设置MPU6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_Rate(u16 rate)
{
	u8 data;
	if(rate>1000)rate=1000;
	if(rate<4)rate=4;
	data=1000/rate-1;
	data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);	//设置数字低通滤波器
 	return MPU_Set_LPF(rate/2);	//自动设置LPF为采样率的一半
}

//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
    u8 buf[2]; 
    short raw;
	float temp;
	MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf); 
    raw=((u16)buf[0]<<8)|buf[1];  
    temp=36.53+((double)raw)/340;  
    return temp*100;;
}
//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
{
    u8 buf[6],res;  
	res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
	if(res==0)
	{
		*gx=((u16)buf[0]<<8)|buf[1];  
		*gy=((u16)buf[2]<<8)|buf[3];  
		*gz=((u16)buf[4]<<8)|buf[5];
	} 	
    return res;;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
    u8 buf[6],res;  
	res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
	if(res==0)
	{
		*ax=((u16)buf[0]<<8)|buf[1];  
		*ay=((u16)buf[2]<<8)|buf[3];  
		*az=((u16)buf[4]<<8)|buf[5];
	} 	
    return res;;
}
//IIC连续写
//addr:器件地址 
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//    其他,错误代码
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
	u8 i; 
    IIC_Start(); 
	IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
	for(i=0;i<len;i++)
	{
		IIC_Send_Byte(buf[i]);	//发送数据
		if(IIC_Wait_Ack())		//等待ACK
		{
			IIC_Stop();	 
			return 1;		 
		}		
	}    
    IIC_Stop();	 
	return 0;	
} 
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//    其他,错误代码
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
 	IIC_Start(); 
	IIC_Send_Byte(MPU_WRITE);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
    IIC_Start();
	IIC_Send_Byte(MPU_READ);//发送器件地址+读命令	
    IIC_Wait_Ack();		//等待应答 
	while(len)
	{
		if(len==1)*buf=IIC_Read_Byte(0);//读数据,发送nACK 
		else *buf=IIC_Read_Byte(1);		//读数据,发送ACK  
		len--;
		buf++; 
	}    
    IIC_Stop();	//产生一个停止条件 
	return 0;	
}
//IIC写一个字节 
//reg:寄存器地址
//data:数据
//返回值:0,正常
//    其他,错误代码
u8 MPU_Write_Byte(u8 reg,u8 data) 				 
{ 
    IIC_Start(); 
	IIC_Send_Byte(MPU_WRITE);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();	
        sprintf((char*)str,"error\r\n");
        USART1PutString(str);
        delay_ms(100);
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答 
	IIC_Send_Byte(data);//发送数据
	if(IIC_Wait_Ack())	//等待ACK
	{
		IIC_Stop();	 
		return 1;		 
	}		 
    IIC_Stop();
	return 0;
}
//IIC读一个字节 
//reg:寄存器地址 
//返回值:读到的数据
u8 MPU_Read_Byte(u8 reg)
{
	u8 res;
    IIC_Start(); 
	IIC_Send_Byte(MPU_WRITE);//发送器件地址+写命令	
	IIC_Wait_Ack();      
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();
    IIC_Start();
	IIC_Send_Byte(MPU_READ);//发送器件地址+读命令	
    IIC_Wait_Ack(); 
	res=IIC_Read_Byte(0);//读取数据,发送nACK 
    IIC_Stop();			//产生一个停止条件 
	return res;		
}

五.实验现象

串口输出姿态角 ,PC端显示

六.注意事项
  

        1,串口波特率为9600.
        2,MPU6050供电电压为3.3V,因为测试发现5V的电平跳变速度不够快会对时序产生影响
        3.使用串口1不要使能串口0


总结

代码是基于STM32F4的,移植过来之后在调试的过程中发现了F4的代码编写存在一些问题,具体表现是MSP432发送读指令0xD1给MPU6050的时候由于SDA变为高电平的时间不够导致最后接受的指令成了0XD0,所以造成了读指令失败的情况。

源码工程已经上传等待审核完成我会放上链接,需要的朋友可以下载看看,当然也可以在评论区留下邮箱我有空就会私发(考研中可能很少看)。

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号