完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
用STM32实现MPU6050原始数据的读取
最近项目组在做自主导航的小车,需要读取底盘的姿态,所以准备往上面加mpu6050,于是整理了这样的文档供以后学习,程序是在正点原子的库上更改的。 了解MPU6050 MPU-60x0 是全球首例 9 轴运动处理传感器。它集成了 3 轴MEMS陀螺仪,3 轴MEMS加速度计,以及一个可扩展的数字运动处理器 DMP(Digital Motion Processor)。 MPU-60x0 对陀螺仪和加速度计分别用了三个 16 位的 ADC,将其测量的模拟量转化为可输出的数字量。为了精确跟踪快速和慢速的运动,传感器的测量范围都是用户可控的,陀螺仪可测范围为 ±250,±500,±1000,±2000°/秒(dps),加速度计可测范围为 ±2,±4,±8,±16g。简单总结的话,mpu6050使用陀螺仪传感器测角度,使用加速度传感器测加速度。 同时,mpu6050有自带的I2C接口连接非惯性的数字传感器,比如压力传感器。其内部也集成了温度传感器,以及一个dmp数字运动处理器,可以解算mpu6050获取的原始数据,进行片内处理。 接线 我们测试时使用的是战舰V3开发板,其中
MPU6050是一个 I2C 器件,里面有很多寄存器(但是我们用到的只有几个),我们通过读写寄存器来操作这个芯片。所以首要问题就是STM32 和 MPU6050 的 I2C 通信。 软件模拟IIC 首先初始化IIC void MPU_IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11); } 其次要用软件模拟吃IIC的起始信号、停止信号、应答信号。这三个信号是IIC通信所要用到的信号,具体底层的原理就不在本文中仔细讲解,软件模拟时主要时要模拟出IIC通信信号的时许与对应电平 void MPU_IIC_Start(void);//产生IIC起始信号 void MPU_IIC_Stop(void);//产生IIC停止型号 u8 MPU_IIC_Wait_Ack(void);//等待响应 void MPU_IIC_Ack(void);//产生IIC响应信号 void MPU_IIC_NAck(void);//不响应 void MPU_IIC_Send_Byte(u8 txd);//发送数据 u8 MPU_IIC_Read_Byte(unsigned char ack);//读取数据 IIC模块都有其地址,MPU6050的地址时通过模块上AD0引脚设置的,AD0接地或者悬空,芯片地址为0x68,接3.3V时,芯片地址为0x69。 通过IIC读取MPU6050寄存器 读寄存器 1.发送起始信号 2.发送设备地址(写模式) 3.发送内部寄存器地址 4.写入寄存器数据(8 位数据宽度) 5.发送结束信号 写寄存器 1.发送起始信号 2.发送设备地址(写模式) 3.发送内部寄存器地址 4.发送重复起始信号 5.发送设备地址(读模式) 6.读取寄存器数据(8 位数据宽度) 7.发送结束信号 内部传感器的地址可以通过手册查询。 实现传感器功能 传感器初始化 u8 MPU_Init(void)//采用带返回值的函数,是因为采用杜邦线连接,干扰比较大,容易初始化失败,所以根据返回值判断是否初始化成功 { u8 res; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); MPU_AD0_CTRL=0;//AD0为低电平,地址为0x68 MPU_IIC_Init(); MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); delay_ms(100); MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00); MPU_Set_Gyro_Fsr(3); //设置陀螺仪量程 MPU_Set_Accel_Fsr(0); //设置加速度计量程 MPU_Set_Rate(50); MPU_Write_Byte(MPU_INT_EN_REG,0X00); //关中断 MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); //IIC主模式关闭 MPU_Write_Byte(MPU_FIFO_EN_REG,0X00)/; //清空FIFO MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80); //INT低有效 MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); res=MPU_Read_Byte(MPU_DEVICE_ID_REG);//都工作加速度计与陀螺仪都工作 MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); MPU_Set_Rate(50); MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); MPU_Set_Rate(50); if(res==MPU_ADDR)//判断模块地址正确(0x68) { MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //再次使能加速度计与陀螺仪 MPU_Set_Rate(50); }else return 1; return 0; 传感器初始化之后就可以读取数据了。 u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf) { MPU_IIC_Start(); MPU_IIC_Send_Byte((addr<<1)|0);//发送地址+写命令 if(MPU_IIC_Wait_Ack()) //等待应答 { MPU_IIC_Stop(); return 1; } MPU_IIC_Send_Byte(reg); //写寄存器地址 MPU_IIC_Wait_Ack(); //等待应答 MPU_IIC_Start(); MPU_IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令 MPU_IIC_Wait_Ack(); //等待应答 while(len) { if(len==1)*buf=MPU_IIC_Read_Byte(0);//读数据 else *buf=MPU_IIC_Read_Byte(1); //发送应答信号 len--; buf++; } MPU_IIC_Stop(); //发送停止信号 return 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;; } 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;; } 到此我们就读出了MPU6050的加速度计和陀螺仪的原始数据,可以对他做解算了,这个留到下一篇文章讲。 一些问题以及解决 DMP 我们没有用MPU6050内置的dmp功能。它内置的dmp功能非常强大,但是由于少了一个z轴的观测,所以不是特别好用,在后面的文章中将介绍如何用四元数融合算法,结合hmc5883,来解算出欧拉角。 零偏问题 每块芯片都有一定的零点漂移,要在放平时对芯片进行校准。在放平时,gx,gy,gz都是0;ax,ay为0,az应该为32768/2=16384。 初始化失败问题 用杜邦线连接的MPU6050很容易初始化失败,所以要编写一个while函数来判断,如果没有初始化成功,就继续初始化。如果模块直接插入焊好的IIC接口中,情况会好很多。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1907 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1678 浏览 1 评论
1171 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
770 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1730 浏览 2 评论
1970浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
806浏览 4评论
stm32f4下spi+dma读取数据不对是什么原因导致的?
254浏览 3评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
623浏览 3评论
634浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-23 06:18 , Processed in 0.725114 second(s), Total 44, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号