STM32F103C8T6使用SPI采集MPU6500数据

0、写在前面

        第一次接触陀螺仪,纯属个人记录,大佬出门右转。

1、构建硬件SPI

        直接使用硬件SPI1,引脚需求如下:

        配置代码:

void SPI_MPU6500_Init(void)
{
	SPI_InitTypeDef SPI_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	/*SPI时钟*/
	RCC_APB2PeriphClockCmd ( RCC_APB2Periph_SPI1, ENABLE );
	/*SPI相关引脚时钟*/
	RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA, ENABLE );

	/*SCK、MISO、MOSI*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/*CS*/
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/*CS引脚高电平*/
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
	
	/*SPI模式配置*/
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;	 
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;	
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI1, &SPI_InitStructure);
	SPI_Cmd(SPI1, ENABLE);
}

        这里用的标准库,请自行添加相关头文件。

2、SPI1针对MPU6500的读写函数

//读写函数
u8 SPI1_Read_Write_Byte(u8 TxData)
{		 			 
	u8 retry = 0;
	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
	{
		retry++;
		if(retry > 250)	return 0;
	}			  
	SPI_I2S_SendData(SPI1, TxData);      //发送数据到DR寄存器
	retry = 0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
	{
		retry++;
		if(retry > 250) return 0;
	}	  						    
	return SPI_I2S_ReceiveData(SPI1);    //从DR寄存器接收数据		    
}

//写一个字节
u8 MPU_Write_Byte(u8 reg,u8 data)
{
	u8 status;
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);
	delay_200ns();
	status = SPI1_Read_Write_Byte(reg); 
	SPI1_Read_Write_Byte(data);
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
	delay_200ns();
	return status;
}

//读一个字节
u8 MPU_Read_Byte(u8 reg)
{
	u8 reg_val;        //寄存器值
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);
	delay_200ns();         
	SPI1_Read_Write_Byte(reg|0x80);     //写入寄存器地址,地址最高位置1
	reg_val=SPI1_Read_Write_Byte(0xff);  //主机发送一个空字节获取寄存器值
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
	delay_200ns();
	return(reg_val); 
}

        参考链接:MPU6500原始数据读取

3、MPU6500初始化

u8 Mpu_Init(void)
{
	delay_200ns();
	u8 id = MPU_Read_Byte(MPU6500_WHO_AM_I);
	u8 i =0;
	u8 MPU6500_Init_Data[10][2] = {{ MPU6500_PWR_MGMT_1 , 0x80 },  /* 重置设备 */ 
				{ MPU6500_PWR_MGMT_1, 0x03 },      /* 时钟源设置 */ 
				{ MPU6500_PWR_MGMT_2, 0x00 },      /* 启动 Acc & Gyro */ 
 	  			{ MPU6500_CONFIG, 0x04 },          /* 低通滤波 频率 41Hz */ 
				{ MPU6500_GYRO_CONFIG, 0x18 },     /* +-2000dps */ 
				{ MPU6500_ACCEL_CONFIG, 0x10 },    /* +-8G */ 
				{ MPU6500_ACCEL_CONFIG_2, 0x02 },  /* 使能低通滤波器  设置 Acc 低通滤波 */ 
				{ MPU6500_USER_CTRL, 0x20 },};     /* 使能 AUX */ 
	for (i = 0; i < 10; i++)
	{
		MPU_Write_Byte(MPU6500_Init_Data[i][0], MPU6500_Init_Data[i][1]);
		delay_200ns();
	}
	return 0;
}

        这里主要关注角速度和加速度的量程(我设置的+-2000dps和+-8G),后面原始数据采集后要进行转换,或者好像直接带入DMP进行姿态解算好像不需要转换数据(我没用过)。

        宏定义和结构体声明如下,可以自行根据MPU6500的寄存器映射地址增加。

#define		MPU6500_WHO_AM_I				0X75
#define		MPU6500_PWR_MGMT_1				0X6B
#define		MPU6500_PWR_MGMT_2				0X6C
#define		MPU6500_CONFIG					0X1A
#define		MPU6500_GYRO_CONFIG				0X1B
#define		MPU6500_ACCEL_CONFIG			0X1C
#define		MPU6500_ACCEL_CONFIG_2		    0X1D
#define		MPU6500_USER_CTRL				0X6A
#define		MPU6500_ACCEL_XOUT_H			0X3B		
#define		MPU6500_ACCEL_YOUT_H			0X3D			
#define		MPU6500_ACCEL_ZOUT_H			0X3F			
#define		MPU6500_ACCEL_XOUT_L			0X3C			
#define		MPU6500_ACCEL_YOUT_L			0X3E			
#define		MPU6500_ACCEL_ZOUT_L			0X40			
#define		MPU6500_GYRO_XOUT_H				0X43		
#define		MPU6500_GYRO_YOUT_H				0X45	
#define		MPU6500_GYRO_ZOUT_H				0X47	
#define		MPU6500_GYRO_XOUT_L				0X44	
#define		MPU6500_GYRO_YOUT_L				0X46	
#define		MPU6500_GYRO_ZOUT_L				0X48	
#define		MPU6500_TEMP_OUT_H				0X41	
#define		MPU6500_TEMP_OUT_L				0X42	
#define		MPU6500_EXT_SENS_DATA_00	    0X49	
#define		MPU6500_EXT_SENS_DATA_01	    0X4A	
#define		MPU6500_EXT_SENS_DATA_02	    0X4B	
#define		MPU6500_EXT_SENS_DATA_03	    0X4C	
#define		MPU6500_EXT_SENS_DATA_04	    0X4D	
#define		MPU6500_EXT_SENS_DATA_05	    0X4E	

typedef struct
{
	float ax;
	float ay;
	float az;
	float gx;
	float gy;
	float gz;
	float temp;
}MPU6500_Data;
extern MPU6500_Data mpu_data;

4、角速度和加速度采集函数

//将两个字节数据处理成字
float Get_16Bit_Data(uint8_t addr_h, uint8_t addr_l)
{
  static uint8_t buf[2];
  static short data;
	
  buf[0] = MPU_Read_Byte(addr_l);
  buf[1] = MPU_Read_Byte(addr_h);
  data = (buf[1]<<8)|buf[0];
	
	return data;   
}

//读取MPU6500数据
MPU6500_Data mpu_data;
void Get_MPU6500_Data(void)
{
	GPIO_ResetBits(GPIOA,GPIO_Pin_4);
    //加速度数据	单位:g的倍数
	mpu_data.ax = (float)Get_16Bit_Data(MPU6500_ACCEL_XOUT_H,MPU6500_ACCEL_XOUT_L) / (0xffff/16);
	mpu_data.ay = (float)Get_16Bit_Data(MPU6500_ACCEL_YOUT_H,MPU6500_ACCEL_YOUT_L) / (0xffff/16);
	mpu_data.az = (float)Get_16Bit_Data(MPU6500_ACCEL_ZOUT_H,MPU6500_ACCEL_ZOUT_L) / (0xffff/16);
	
	//角速度数据	单位:°/s
	mpu_data.gx = (float)Get_16Bit_Data(MPU6500_GYRO_XOUT_H,MPU6500_GYRO_XOUT_L) / (0xffff/4000);
	mpu_data.gy = (float)Get_16Bit_Data(MPU6500_GYRO_YOUT_H,MPU6500_GYRO_YOUT_L) / (0xffff/4000);
	mpu_data.gz = (float)Get_16Bit_Data(MPU6500_GYRO_ZOUT_H,MPU6500_GYRO_ZOUT_L) / (0xffff/4000);
	
	//温度数据
	mpu_data.temp = Get_16Bit_Data(MPU6500_TEMP_OUT_H,MPU6500_TEMP_OUT_L)/333.87f +21;
	GPIO_SetBits(GPIOA,GPIO_Pin_4);
}

        采集的原始数据/(0XFFFF/量程),就是转换后的数据,单位代码写在注释上了。

5、主循环调用

int main(void)
{
	systick_Init();
	SPI_MPU6500_Init();
	Mpu_Init();
	
	while(1)
	{
		Get_MPU6500_Data();
	}
}

        systick初始化是用来写延时函数的,这里就不展开啦,百度一大堆。

6、仿真结果

        没滤波的数据果然很差,而且实际运用是不是需要校准啊?不太清楚,反正采集数据的目的达到了。(有问题有错误欢迎指出~)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值