MPU6500驱动调试笔记(STM32F407+SPI)

发布者:幸福家园最新更新时间:2020-07-09 来源: eefocus关键字:MPU6500  驱动调试  STM32F407  SPI 手机看文章 扫描二维码
随时随地手机看文章

一、问题背景

本来最开始实验室使用MPU6050芯片,采集陀螺仪原始数据做生理信号采集,但算法发现用IIC接口采样率(200hz)达不到要求。故寻找同类型支持SPI协议的芯片去替代,发现了这块MPU6500,还便宜,就用起来。在读写寄存器费了些周折(每读一次数据寄存器需要短暂延时,不能spi连续读。写寄存器有100ms延时要求),算是记录下吧


二、注意事项

NOTE: 1、由datasheet P16页SPI时序图得:CPOL=1,CPHA=1;(多谢网友指正页码)


     2、采样频率200hz,陀螺仪量程正负250dps,加速度量程正负2g,16bit输出;


三、源代码

/*

******************************************************************

**  Filename :  mpu6500.C

**  Abstract :  mpu6500的spi驱动程序

**  Device   :  stm32f4xx

**  Compiler :  keil 5

**  By       :  yulong

**  Date     :  2017-09-21 17:25:39

**  Changelog:1.首次创建

*******************************************************************

*/

#include "mpu6500.h"

#include "stm32f4xx_exti.h"

#include "stdio.h"

#include "exti.h"

#include "Show_Scope.h"

#include "sys.h"

#include "delay.h"

#include "usart.h"   

#include "led.h"

 

 

 

/**初始化mpu6500端口**/

void mpu6500_Init(void) 

{

    GPIO_InitTypeDef    GPIO_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

EXTI_InitTypeDef EXTI_InitStructure;

    

    //mpu6500 CS脚g11

    GPIO_InitStructure.GPIO_Pin = mpu6500_CS;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

  GPIO_Init(mpu6500_CS_G, &GPIO_InitStructure);

    GPIO_SetBits(mpu6500_CS_G, mpu6500_CS);//CS 高电平,先不选中

    //其他公用SPI的器件,将片选拉高

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PG15 //flash_cs

    GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化

    GPIO_SetBits(GPIOG, GPIO_Pin_15);//PG15输出1,防止NRF干扰SPI FLASH的通信 

    

    //mpu6500 DRDY脚

    GPIO_InitStructure.GPIO_Pin = mpu6500_DRDY;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100M

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

  GPIO_Init(mpu6500_DRDY_G, &GPIO_InitStructure);   

    

    SPI3_Init();     //初始化SPI 模式3

    SPI3_SetSpeed(SPI_BaudRatePrescaler_256); //设置为42M时钟,高速模式 

 

    //DRDY中断接收初始化

    //EXTIX_Init();

}

 

 

//初始化MPU6500

//返回值:0,成功

//    其他,错误代码

u8 MPU6500_Init(void)

u8 res, t=5;

mpu6500_Init();//初始化spi总线.exit外部中断

mpu6500_Write_Byte(MPU_PWR_MGMT1_REG,0X80); //复位mpu6500

    delay_ms(100); //see 《register map》page 42 - delay 100ms

mpu6500_Write_Byte(MPU_SIGPATH_RST_REG,0X07); //reset GYR+ACC+TEMP

delay_ms(100); //page 42 - delay 100ms

mpu6500_Write_Byte(MPU_USER_CTRL_REG, 0x11); //SET spi mode+Reset all gyro digital signal path, accel digital signal path, and temp

delay_ms(1000);

res=mpu6500_Read_Byte(MPU_DEVICE_ID_REG);

if(res == 0x70)//器件ID正确

{

printf("mpu6500_ADDR INIT OK!n");

MPU_Set_Gyro_Fsr(0); //陀螺仪传感器,±250dps

delay_ms(10); //每写一个寄存器注意延时!不然会有意想不到的错误lol --yulong

MPU_Set_Accel_Fsr(0); //加速度传感器,±2g

delay_ms(10);

mpu6500_Write_Byte(MPU_CFG_REG,0X03); //gyr Fs=1khz,bandwidth=41hz

delay_ms(10); 

mpu6500_Write_Byte(MPU_ACCEL_CFG2_REG,0X03); //Acc Fs=1khz, bandtidth=41hz

delay_ms(10);

//mpu6500_Write_Byte(MPU_INTBP_CFG_REG,0XA0); //INT引脚低电平有效,推完输出

delay_ms(10);

//mpu6500_Write_Byte(MPU_INT_EN_REG,0X01); //raw data inter open

delay_ms(10);

//mpu6500_Write_Byte(MPU_PWR_MGMT1_REG,0X01); //设置CLKSEL,PLL X轴为参考

delay_ms(10);

mpu6500_Write_Byte(MPU_PWR_MGMT2_REG, 0X00); //加速度与陀螺仪都工作

delay_ms(10);

MPU_Set_Rate(200); //设置采样率为200Hz

delay_ms(10);

  }

else 

{

printf("ERROR! mpu6500_ADDR IS %xn", mpu6500_Read_Byte(MPU_DEVICE_ID_REG));

return 1; //错误退出

}

 

//just for test --yulong 2017/9/20

//loop all the time(send data to com)

while(1)

{

short accx_original=0, accy_original=0, accz_original=0;

u16 ACC_DATA[7];

u8 raw_datas[14]={0}; //acc*6+temp*2+gyr*6

u8 res;

res = mpu6500_Read_Byte(MPU_INT_STA_REG); //默认读此寄存器能够清此标志位.故循环查询此寄存器即可

//printf("int status:%xn", res);

delay_us(10);

if(res == 0x01) //数据ready

{

mpu6500_Read_Len(MPU_ACCEL_XOUTH_REG, 8, &raw_datas[0]);

delay_us(10);

mpu6500_Read_Len(MPU_GYRO_XOUTH_REG, 6, &raw_datas[8]);

delay_us(10);

 

ACC_DATA[0]=((u16)raw_datas[0]<<8)|raw_datas[1];//三轴加速度

ACC_DATA[1]=((u16)raw_datas[2]<<8)|raw_datas[3];

ACC_DATA[2]=((u16)raw_datas[4]<<8)|raw_datas[5];

ACC_DATA[3]=((u16)raw_datas[8]<<8)|raw_datas[9];//三轴角速度

ACC_DATA[4]=((u16)raw_datas[10]<<8)|raw_datas[11];

ACC_DATA[5]=((u16)raw_datas[12]<<8)|raw_datas[13];

ACC_DATA[6]=((u16)raw_datas[6]<<8)|raw_datas[7]; //温度数据

Data_Send_Status(ACC_DATA, 0XF1, 7); //7通道数据,发送给匿名上位机波形显示

LED3_ON(); //open red led

}

}

return 0;

}

//设置MPU6050陀螺仪传感器满量程范围

//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps

//返回值:0,设置成功

//    其他,设置失败 

u8 MPU_Set_Gyro_Fsr(u8 fsr)

{

return mpu6500_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 mpu6500_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 mpu6500_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; //最大1khz采样率

if(rate<4)rate=4;

data=1000/rate-1; //根据公式算出得

data=mpu6500_Write_Byte(MPU_SAMPLE_RATE_REG,data); //设置采样率

  //return MPU_Set_LPF(rate/2); //自动设置LPF为采样率的一半

}

 

//

//同时读多个寄存器

//reg:起始寄存器地址

//len:读寄存器的总个数

//*buf:存储内存起始指针

// 

// NOTE:经论坛网友反馈,这里连续读可能存在问题。看了下手册,每个字节循环读低效,而且MCU差异导致

// 延时可能造成时序问题。建议修改为CS拉低后,SPI 连续读出多个字节,全部读完后再拉高CS。由于现在

// 手里没6500硬件,不能做测试。如有网友验证ok,欢迎补充,告诉我一下。多谢!--2020.3.23

// 未测试代码:

/*

u8 mpu6500_Read_Len(u8 reg, u8 len,u8 *buf)

  u8 tmp=0;

mpu6500_CS_L;

SPI3_ReadWriteByte(reg|0x80);//r 最高位为1

while(len)

{

*buf=SPI3_ReadWriteByte(0x00);

len--;

buf++;

}

mpu6500_CS_H;

return tmp;

}

*/

 

u8 mpu6500_Read_Len(u8 reg, u8 len,u8 *buf)

  u8 tmp=0;

while(len)

{

mpu6500_CS_L;

SPI3_ReadWriteByte(reg|0x80);//r 最高位为1

*buf=SPI3_ReadWriteByte(0x00);

len--;

buf++;

reg++;

mpu6500_CS_H;

delay_us(5); //每读一个寄存器必须延迟一段时间。不能马上读下一个寄存器--yulong

}

return tmp;

}

 

 

 

//spi write a byte

u8 mpu6500_Write_Byte(u8 reg,u8 data)  

mpu6500_CS_L;

SPI3_ReadWriteByte(reg); //w 最高位为0

SPI3_ReadWriteByte(data);

mpu6500_CS_H;

}

 

//spi read a byte

u8 mpu6500_Read_Byte(u8 reg)

{

u8 tmp=0;

mpu6500_CS_L;

SPI3_ReadWriteByte(reg|0x80);//r 最高位为1

tmp=SPI3_ReadWriteByte(0xff);

mpu6500_CS_H;

return tmp;

}


四、测试验证

最后调试完成,用匿名上位机绘制原始波形如下图:

关键字:MPU6500  驱动调试  STM32F407  SPI 引用地址:MPU6500驱动调试笔记(STM32F407+SPI)

上一篇:STM32F1笔记(十三)SPI
下一篇:STM32串口发送数据和接收数据方式总结

推荐阅读最新更新时间:2024-11-17 00:45

STM32学习笔记之SPI_DMA寄存器级操作
一、实验目标 学会配置STM32的SPI寄存器和DMA寄存器,实现STM32的SPI1与SPI2通信功能,每次发送一字节数据,并可多次发送,如果接收的数据正确,则点亮LED灯。 二、实验目的 加入DMA的SPI通信相对于普通SPI通信有什么好处?ST给SPI加了DMA功能出于什么目的?我觉得这是很重要的一个问题,一直边学习边想。以下是我的看法: 减少CPU负荷?我想这应该是DMA最主要的功能,可是对于SPI通信来说,其实大部分时候我们需要根据发送的指令- 目标器件的应答来决定下一个指令,所以此时CPU还是需要一直等待每次通信的结束。而且像SD卡的操作,是一个顺序流的指令操作过程,用中断也不容易控制。那到底加入了DMA有什么
[单片机]
STM32学习笔记之<font color='red'>SPI</font>_DMA寄存器级操作
STC15W通过SPI方式读取RM3100数据
近日接手一个项目,要求在STC单片机上面读取RM3100的数据,淘宝看了下,还真不便宜。 这个东西本身难度不是很大,麻烦的是没有什么参考资料,就官网那点东西。 程序思路很简单,调SPI通信,调初始化设置。 查看数据手册,这些寄存器都是可以被设置的,还好,不算太多。 也没必要全都设置一遍,只需要把需要的设置一下就行,我的话主要是设置了连续测量和转换周期。 /** * @brief Sets cycle count and updates gain and max_data_rate values * @param desire value PNI recomends values between 3
[单片机]
STC15W通过<font color='red'>SPI</font>方式读取RM3100数据
STM32有关SPI实现DMA程序应用小记
特别针对SPI-DMA的发送和接收做了一次对比实验, 实验发现:当STM作为主设备向其它设备传送SPI数据时,DMA传送完成时中断,可进入中断程序,并在此时对SPI返回数据处理。SPI的返回数据在DMA-SPI-RX缓存中。 值得注意的是:返回数据的处理必须是DMA-SPI-TX传输完成中断后执行,不能在DMA-SPI-RX传输完成中断后执行,否则会出错。 以上是STM作为SPI主设备时的一些发现,当时就是在返回处理数据在DMA-SPI-RX完成中断后处理发生了问题。
[单片机]
MAX350 串行控制的多路开关,扩充SPI片选
多路开关电路指在多路数据传送过程中,能够根据需要将其中任意一路选出来的电路.
[模拟电子]
6 通道逻辑 / SPI / I2C μModule 隔离器
加利福尼亚州米尔皮塔斯 (MILPITAS, CA) – 2016 年 12 月 12 日 – 凌力尔特公司 (Linear Technology Corporation) 推出 6 通道 SPI / 数字或 I2C μModule® 隔离器 LTM2887,该器件面向低电压组件,包括较新的 DSP 和微处理器。两个经过良好稳压的可调电源轨 (高达 5V) 越过隔离势垒提供大于 100mA 的负载电流,并具有高达 62% 的效率。对于辅助电源,电压可调节到低至 0.6V,而对于 SPI 接口,隔离型逻辑电源则可低至 1.8V。每个电源提供一个精准的电流限值调整引脚,并能使用外部电阻器来调节电压。 在工业系统应用中,接地电位
[模拟电子]
6 通道逻辑 / <font color='red'>SPI</font> / I2C μModule 隔离器
基于S3C2410的串行外围设备接口SPI及Linux下嵌入式驱动的实现
串行外围设备接口SPI(serial peripheral interface)总线技术是Motorola公司推出的一种同步串行接口,它允许CPU与TTL移位寄存器、A/D或D/A转换器、实时时钟 (RTO)、存储器以及LCD和LED显示驱动器等外围接口器件以串行方式进行通讯。 SPI总线只需3~4根数据线和控制线即可扩展具有SPI接口的各种I/O器件,其硬件功能很强,实现软件相当简单。串行A/D转换器具有电路简单、工作可靠的特点,而ARM芯片被设计用于手持设备以及普通的嵌人式应用的集成系统,将上述两种实用的芯片和SPI总线技术相结合以实现数据采集十分有效。 1 AD7888的功能与使用 AD7888是美国模
[单片机]
基于S3C2410的串行外围设备接口<font color='red'>SPI</font>及Linux下嵌入式<font color='red'>驱动</font>的实现
STM32F407-基于AD7606进行多路数据采集
1.原理图 2.管脚定义 2.1 OS2,OS1,OS0 查阅数据手册 这三个管脚组合控制过采样模式。 000 表示无过采样,最大 200Ksps 采样速率。 001 表示 2 倍过采样, 也就是硬件内部采集 2 个样本求平均。 010 表示 4 倍过采样, 也就是硬件内部采集 4 个样本求平均。 011 表示 8 倍过采样, 也就是硬件内部采集 8 个样本求平均。 100 表示 16 倍过采样, 也就是硬件内部采集 16 个样本求平均。 101 表示 32 倍过采样, 也就是硬件内部采集 32 个样本求平均。 110 表示 64 倍过采样, 也就是硬件内部采集 64 个样本求平均。 过采样倍率越高,ADC 转换时间越
[单片机]
STM32F407-基于AD7606进行多路数据采集
基于Stm32F407的步进电机的速度控制方案------初步
这里跟大家分享一下我的步进电机的速度控制思路(最终初步解决了问题) 这里我选择的是 Stm32F407 作为主控芯片,我的大致速度控制思路就是通过调整PSC 和ARR的值来实现对速度的控制。对应于我的代码的定时器框图如下(我用的是TIM14) 为了实现修改定时器的频率我们需要修改对应的PSC和ARR的值、 这里的定时器模式我选择是PWM模式 对应的定时器部分的初始化代码如下 以上代码完成了定时器的IO复用和对应的时钟的初始化,这里我们不在赘述! 我们接下来就是需要通过修改 定时器对应的PSC和ARR值来实现对定时器输出的脉冲的频率进行调整 所以我考虑的是 我们写一个数组,将不同的转速下对应的PSC和ARR值都分
[单片机]
基于<font color='red'>Stm32F407</font>的步进电机的速度控制方案------初步
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved