您好,欢迎来到纷纭教育。
搜索
您的当前位置:首页【嵌入式裸机开发】软件IIC读取MPU6050原始数据(stm32f103c8t6)

【嵌入式裸机开发】软件IIC读取MPU6050原始数据(stm32f103c8t6)

来源:纷纭教育

最终现象


一、GY-521 MPU6050三维角度传感器简介


二、程序分析

1、mpu6050.c

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS		0xD0  //写

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();//发送起始信号
	MyI2C_SendByte(MPU6050_ADDRESS);//发送mpu6050设备号及读写位(写)
	MyI2C_ReceiveAck();//等待从机响应
	MyI2C_SendByte(RegAddress);//发送要写入数据的寄存器的地址
	MyI2C_ReceiveAck();//等待从机响应
	MyI2C_SendByte(Data);//发送数据
	MyI2C_ReceiveAck();//等待从机响应
	MyI2C_Stop();//发送停止信号
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();//发送起始信号
	MyI2C_SendByte(MPU6050_ADDRESS);//发送mpu6050设备号及读写位(写)
	MyI2C_ReceiveAck();//等待从机响应
	MyI2C_SendByte(RegAddress);//发送要写入数据的寄存器的地址,此时mpu6050内部寄存器指针就会指向这个地址,下面再进行发送起始信号,见下方
	                           //并且发送mpu6050设备号及读写位(读)
	MyI2C_ReceiveAck();//等待从机响应
	MyI2C_Start();//二次起始,为读数据做准备
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//发送mpu6050设备号及读写位(读)
	MyI2C_ReceiveAck();//等待从机响应
	Data = MyI2C_ReceiveByte();//读取八位数据
	MyI2C_SendAck(1);//向从机发送不想再读数据的响应
	MyI2C_Stop();//发送停止信号
	
	return Data;
}

void MPU6050_Init(void)
{
	MyI2C_Init();
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}

uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)//这就是根据MPU6050手册进行读取寄存器值的操作
{
	uint8_t DataH, DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

2、MPU6050_reg.h

#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H

#define	MPU6050_SMPLRT_DIV		0x19
#define	MPU6050_CONFIG			0x1A
#define	MPU6050_GYRO_CONFIG		0x1B
#define	MPU6050_ACCEL_CONFIG	0x1C

#define	MPU6050_ACCEL_XOUT_H	0x3B
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48

#define	MPU6050_PWR_MGMT_1		0x6B
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75

#endif

3、IIC.c

软件IIC顾名思义就是控制IO口的高低电平来模拟产生时钟信号,控制数据通信。这里使用PB10模拟时钟输出,PB11控制数据交互,以此封装:起始位,停止位,发送一个字节,读取一个字节,发送主机响应,接收从机响应。这里代码看不懂的话可以看:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

//PB10、PB11
void MyI2C_W_SCL(uint8_t BitValue)//这三个函数将读写io口封装起来,增强可读性
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}

void MyI2C_Init(void)//软件iic的两个gpio初始化,注意是开漏输出
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

void MyI2C_Start(void)//发送起始信号
{
	MyI2C_W_SDA(1);//确保SCL,SDA都释放,然后先拉低SDA,再拉低SCL
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)//发送停止信号
{
	MyI2C_W_SDA(0);//此时SCL一定为低,所以拉低SDA,然后先释放SCL,再释放SDA
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)//通过SDA发送一个字节
{
	uint8_t i;//进入此函数时SCL为低电平,此时主机向SDA发送数据,然后拉高SCL,从机就会读取数据,循环发送8位
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

uint8_t MyI2C_ReceiveByte(void)//通过SDA读取一个字节,由从机发送
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);//主机释放SDA,让从机掌握SDA控制权
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}//在SCL为高电平期间,主机可以从SDA中读取从机发送的数据,循环接收8位
		MyI2C_W_SCL(0);
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)//发送主机响应信号
{
	MyI2C_W_SDA(AckBit);//进入此函数时,SCL为低电平,此时向SDA写入数据,然后拉高SCL,从机就会读取数据
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void)//接收从机响应
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);//主机释放SDA,让从机掌握SDA控制权
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();//在SCL为高电平期间,主机可以从SDA中读取从机发送的数据
	MyI2C_W_SCL(0);
	return AckBit;
}

主函数中初始化MPU6050之后即可调用MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);将读取的数据存储到定义的全局变量中。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- fenyunshixun.cn 版权所有 湘ICP备2023022495号-9

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务