datasheet

STM32驱动MPU6050(二)——软件实现

2019-01-09来源: eefocus 关键字:STM32  驱动MPU6050  软件实现

软件实现将从下面三个部分来介绍:IIC通信;MPU6050数据读取;数据融合。


1. IIC通信

为了移植的方便,这里的 IIC 采用软件模拟的方式实现。关于 IIC 的基础知识介绍,可参考IIC专题(一)——基础知识准备。


下面以程序的实现过程,梳理一下 IIC 的通信时序。注:这里就采用正点原子的 mpu6050 的学习教程进行学习。


1.1 SDA 和SCL初始化


//初始化IIC

void MPU_IIC_Init(void)

{      

  GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//先使能外设IO PORTC时钟 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11; // 端口配置

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz

  GPIO_Init(GPIOC, &GPIO_InitStructure); //根据设定参数初始化GPIO 

  GPIO_SetBits(GPIOC,GPIO_Pin_12|GPIO_Pin_11); //PB10,PB11 输出高

 

}


对于 SDA 输入输出的方向切换,这里直接通过配置寄存器实现:

//IO方向设置

#define MPU_SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}

#define MPU_SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}


也可通过配置库函数配置来实现:


void MPU_SDA_OUT(void)

{

GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11;

GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}

void MPU_SDA_IN(void)

{

GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11;

GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}



1.2 IIC时序模拟实现

程序需要根据 IIC 的时序要求进行书写。注意:SDA和SCL需要接上拉电阻。


void MPU_IIC_Start(void)

{

MPU_SDA_OUT();     //sda线输出

MPU_IIC_SDA=1;     

MPU_IIC_SCL=1;

MPU_IIC_Delay();

  MPU_IIC_SDA=0;//START:when CLK is high,DATA change form high to low 

MPU_IIC_Delay();

MPU_IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 

}   

//产生IIC停止信号

void MPU_IIC_Stop(void)

{

MPU_SDA_OUT();//sda线输出

MPU_IIC_SCL=0;

MPU_IIC_SDA=0;//STOP:when CLK is high DATA change form low to high

  MPU_IIC_Delay();

MPU_IIC_SCL=1;  

MPU_IIC_SDA=1;//发送I2C总线结束信号

MPU_IIC_Delay();    

}



//IIC发送一个字节

//返回从机有无应答

//1,有应答

//0,无应答   

void MPU_IIC_Send_Byte(u8 txd)

{                        

    u8 t;   

MPU_SDA_OUT();     

    MPU_IIC_SCL=0;//拉低时钟开始数据传输

    for(t=0;t<8;t++)

    {              

        MPU_IIC_SDA=(txd&0x80)>>7;

        txd<<=1;   

MPU_IIC_SCL=1;

MPU_IIC_Delay(); 

MPU_IIC_SCL=0;

MPU_IIC_Delay();

    }  

}     

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   

u8 MPU_IIC_Read_Byte(unsigned char ack)

{

unsigned char i,receive=0;

MPU_SDA_IN();//SDA设置为输入

    for(i=0;i<8;i++ )

{

        MPU_IIC_SCL=0; 

        MPU_IIC_Delay();

MPU_IIC_SCL=1;

        receive<<=1;

        if(MPU_READ_SDA)

receive++;   

MPU_IIC_Delay(); 

    }  

    if (!ack)

        MPU_IIC_NAck();//发送nACK

    else

        MPU_IIC_Ack(); //发送ACK   

    return receive;

}


//等待应答信号到来

//返回值:1,接收应答失败

//        0,接收应答成功

u8 MPU_IIC_Wait_Ack(void)

{

u8 ucErrTime=0;

MPU_SDA_IN();      //SDA设置为输入  

MPU_IIC_SDA=1;

MPU_IIC_Delay();    

MPU_IIC_SCL=1;

MPU_IIC_Delay();  

while(MPU_READ_SDA)

{

ucErrTime++;

if(ucErrTime>250)

{

MPU_IIC_Stop();

return 1;

}

}

MPU_IIC_SCL=0;//时钟输出0    

return 0;  

//产生ACK应答

void MPU_IIC_Ack(void)

{

MPU_IIC_SCL=0;

MPU_SDA_OUT();

MPU_IIC_SDA=0;

MPU_IIC_Delay();

MPU_IIC_SCL=1;

MPU_IIC_Delay();

MPU_IIC_SCL=0;

}

//不产生ACK应答     

void MPU_IIC_NAck(void)

{

MPU_IIC_SCL=0;

MPU_SDA_OUT();

MPU_IIC_SDA=1;

MPU_IIC_Delay();

MPU_IIC_SCL=1;

MPU_IIC_Delay();

MPU_IIC_SCL=0;

}


1.3 IIC 通信写入读取数据

//IIC写一个字节 

//reg:寄存器地址

//data:数据

//返回值:0,正常

//    其他,错误代码

u8 MPU_Write_Byte(u8 reg,u8 data)  

    MPU_IIC_Start(); 

MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令

if(MPU_IIC_Wait_Ack()) //等待应答

{

MPU_IIC_Stop();  

return 1;

}

    MPU_IIC_Send_Byte(reg); //写寄存器地址

    MPU_IIC_Wait_Ack(); //等待应答 

MPU_IIC_Send_Byte(data);//发送数据

if(MPU_IIC_Wait_Ack()) //等待ACK

{

MPU_IIC_Stop();  

return 1;  

}  

    MPU_IIC_Stop();  

return 0;

}


//IIC读一个字节 

//reg:寄存器地址 

//返回值:读到的数据

u8 MPU_Read_Byte(u8 reg)

{

u8 res;

    MPU_IIC_Start(); 

MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令

MPU_IIC_Wait_Ack(); //等待应答 

    MPU_IIC_Send_Byte(reg); //写寄存器地址

    MPU_IIC_Wait_Ack(); //等待应答

    MPU_IIC_Start();

MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);//发送器件地址+读命令

    MPU_IIC_Wait_Ack(); //等待应答 

res=MPU_IIC_Read_Byte(0);//读取数据,发送nACK 

    MPU_IIC_Stop(); //产生一个停止条件 

return res;

}


//IIC连续写

//addr:器件地址 

//reg:寄存器地址

//len:写入长度

//buf:数据区

//返回值:0,正常

//    其他,错误代码

u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)

{

u8 i; 

    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(); //等待应答

for(i=0;i

{

MPU_IIC_Send_Byte(buf[i]); //发送数据

if(MPU_IIC_Wait_Ack()) //等待ACK

{

MPU_IIC_Stop();  

return 1;  

}

}    

    MPU_IIC_Stop();  

return 0;

//IIC连续读

//addr:器件地址

//reg:要读取的寄存器地址

//len:要读取的长度

//buf:读取到的数据存储区

//返回值: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);//读数据,发送nACK 

else 

*buf=MPU_IIC_Read_Byte(1); //读数据,发送ACK  

len--;

buf++; 

}    

    MPU_IIC_Stop(); //产生一个停止条件 

return 0;

}

至此,与 IIC 相关的代码已经实现了,上面的程序只要是 IIC 通信的设备,均可以使用。


2. MPU6050读取数据

首先需要进行设备初始化,为数据通信做好准备。


2.1 分为以下几个步骤:

(来自原子教程)


(1) 初始化 IIC 接口


MPU6050 采用 IIC 与 STM32F1 通信,需要先初始化与 MPU6050 连接的 SDA和 SCL 数据线。


(2)复位 MPU6050


这一步让 MPU6050 内部所有寄存器恢复默认值,通过对电源管理寄存器 1(0X6B)的bit7 写 1 实现。 复位后, 电源管理寄存器 1 恢复默认值(0X40),然后必须设置该寄存器为0X00,以唤醒 MPU6050,进入正常工作状态。


(3)设置角速度传感器(陀螺仪)和加速度传感器的满量程范围


这一步设置两个传感器的满量程范围(FSR),分别通过陀螺仪配置寄存器(0X1B)和加速度传感器配置寄存器(0X1C)设置。一般设置陀螺仪的满量程范围为±2000dps,加速度传感器的满量程范围为±2g。


(4)其他参数设置


需要配置的参数有:关闭中断、关闭 AUX IIC 接口、禁止 FIFO、设置陀

螺仪采样率和设置数字低通滤波器(DLPF)等。


这里不用中断方式读取数据,关闭中断即可,也没用到 AUX IIC 接口外接其他传感器,同样的关闭这些接口。分别通过中断使能寄存器(0X38)和用户控制寄存器(0X6A)控制。 MPU6050 可以使用 FIFO 存储传感器数据,此处没有用到,关闭所有 FIFO 通道,这个通过 FIFO 使能寄存器(0X23)控制,默认都是 0(即禁止 FIFO),所以用默认值就可以了。陀螺仪采样率通过采样率分频寄存器(0X19)控制,这个采样率一般设置为 50 。数字低通滤波器(DLPF)则通过配置寄存器(0X1A)设置,一般设置 DLPF 为带宽的 1/2 。


(5)配置系统时钟源并使能角速度传感器和加速度传感器


系统时钟源同样是通过电源管理寄存器 1(0X1B)来设置,该寄存器的最低三位用于设置系统时钟源选择,默认值是 0(内部 8

[1] [2] [3]

关键字:STM32  驱动MPU6050  软件实现

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/2019/ic-news010942848.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32驱动NRF24L01
下一篇:最后一页

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32程序移植技巧总结

1. 工程更换不同的STM32芯片eg:stm32f103rct6 ---->stm32f103c8t6:1.1. 修改芯片点击魔术棒,在出来的菜单栏里,Device 选项重新选择芯片1.2. 修改启动文件此处举例是 RCT6 修改为 C8T6,因为 flash 容量大小不一样,所以需要对应修改启动文件,如果是 flash 大小相同,此步骤不需要。此处由:startup_stm32f10x_hd.s修改为startup_stm32f10x_md.s1.3. 修改全局宏定义同样先点击魔术棒,在菜单栏选择 C/C++。进而修改全局宏定义。此处:STM32F10X_HD–>STM32F10X_MD1.4. 重新添加FLASH
发表于 2019-01-09
STM32程序移植技巧总结

STM32学习笔记一一FLASH 模拟 EEPROM

1. 简述STM32 本身没有自带 EEPROM,但是 STM32 具有在应用编程(IAP:In Application Programming)功能,可以把它的 FLASH 当成 EEPROM 来使用。不同型号的 STM32,其 FLASH 容量也有所不同,最小的只有 16K 字节,最大的则达到了1024K 字节。MiniSTM32 开发板选择的 STM32F103RCT6 的 FLASH 容量为 256K 字节,属于大容量产品,闪存模块组织如下图:1.1 主存储器:该部分用来存放代码和数据常数(如 const 类型的数据)。对于大容量产品,其被划分为 256 页,每页 2K 字节。**注意:**小容量和中容量产品则每页
发表于 2019-01-09
STM32学习笔记一一FLASH 模拟 EEPROM

STM32学习笔记一一HEX文件和BIN文件格式

1. 引言今天看串口的 IAP ,平时我们通过 JTAG 等工具下载的都是 HEX 文件,都没有思考一下 HEX 的文件组成。而串口 IAP 下载的是 BIN 文件,刚好在这里区分学习一下。我们平时烧写 HEX 文件是不需要设置地址信息的,因为已经包含在文件里面,而使用 BIN 烧写,需要在程序中指定地址。2. 简述Intel hex 文件是记录文本行的 ASCII 文本文件,在 Intel HEX 文件中,每一行是一个 HEX 记录,由十六进制数组成的机器码或者数据常量。Intel HEX 文件经常被用于将程序或数据传输存储到 ROM、EPROM,大多数编程器和模拟器使用Intel HEX文件。2.1 HEX文件HEX 文件是包括
发表于 2019-01-09
STM32学习笔记一一HEX文件和BIN文件格式

STM32学习笔记一一串口 IAP

(Bootloader 程序)必须通过其它手段,如 JTAG 或 ISP 烧入;第二部分代码(APP 程序)可以使用第一部分代码 IAP 功能烧入,也可以和第一部分代码一起烧入,以后需要程序更新时再通过第一部分 IAP代码更新。他们存放在 STM32 FLASH 的不同地址范围,一般从最低地址区开始存放 Bootloader,紧跟其后的就是 APP 程序。2 .STM32程序流程2.1 STM32 正常的程序运行流程下图为 STM32 正常的程序运行流程:STM32 的内部闪存(FLASH)地址起始于 0x08000000,一般情况下,程序文件就从此地址开始写入。此外STM32是基于Cortex-M3内核的微控制器,其内部通过一张
发表于 2019-01-09
STM32学习笔记一一串口 IAP

STM32学习笔记一一待机唤醒

1. 简述1.1 低功耗模式:在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如:等待某个外部事件时,常见的按键唤醒。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。1.2 STM32F10X系列的低功耗模式STM32F10xxx有三种低功耗模式:–模式– –特点—睡眠模式 Cortex-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行停止模式 所有的时钟都已停止待机模式 1.8V电源关闭在这三种低功耗模式中,最低功耗的是待机模式,在此模式下,最低只需 2uA 左右的电流。停机模式
发表于 2019-01-09
STM32学习笔记一一待机唤醒

STM32学习笔记一一红外遥控

}2.2 中断捕获u8 RmtSta=0;u16 Dval;u32 RmtRec=0;u8 RmtCnt=0;void TIM5_IRQHandler(void){ if(TIM_GetITStatus(TIM5,TIM_IT_Update)!= RESET) { if(RmtSta&0x80)//数据接收到标志位 { RmtSta &= ~0x10;//取消上升沿捕获标记 if((RmtSta&0x0F)==0x00) RmtSta |= 1<<6; if((RmtSta&0x0F)<14) RmtSta++; else { RmtSt
发表于 2019-01-09
STM32学习笔记一一红外遥控

小广播

何立民专栏

单片机及嵌入式宝典

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

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2018 EEWORLD.com.cn, Inc. All rights reserved
pt type="text/javascript" src="//v3.jiathis.com/code/jia.js?uid=2113614" charset="utf-8">