目录
一、mpu6050简介
1)16位ADC采集传感器的模拟信号,量化范围:-32768~32767。
2)加速度计满量程范围选择:±2、±4、±8、±16(g) g表示重力加速度1g=9.8m/s²
3)陀螺仪满量程选择:±250、±500、±1000、±2000(°/sec) 每秒钟旋转了多少度(如果测量的物体运动非常剧烈,可以把满量程选择大一些,如果运动比较平缓,可以选择更小的量程,这样分辨率会更大。)可配置的数字低通滤波器在这个芯片可以配置寄存器来选择对输出的数据进行低通滤波)可配置的时钟源和可配置的采样分频(为AD转换和芯片内部其他电路提供时钟,控制分频系数,可以控制AD转化的快慢。)
4)I2C从机地址:当AD0=0时,地址为0xD0,当AD0=1时,地址为0xD1,AD0是板子引出来的引脚,可以调节I2C从机地址的最低位。
5)(16位表示时,有两种方式,①是把1101000转成16进制0x68,但是因为还有一位读写位,一般使用(0x68<<1)|读写位。读1写0。②把0x68左移一位后的数据当作从机地址,也就是0xD0,再或上读写位。
二、IIC协议底层如下
1,myiic.c代码:
#include "myiic.h"
#include "main.h"
#include "Delay.h"
static void iic_delay(void)
{
Delay_us(10);
}
/* 起始信号 */
void iic_start(void)
{
/* SCL为高电平期间, SDA从高电平往低电平跳变*/
IIC_SDA ( 1 );
IIC_SCL ( 1 );
iic_delay( );
IIC_SDA ( 0 );
iic_delay( );
IIC_SCL ( 0 );
iic_delay( ); /* 钳住总线, 准备发送/接收数据 */
}
/* 停止信号 */
void iic_stop(void)
{
/* SCL为高电平期间, SDA从低电平往高电平跳变*/
IIC_SDA ( 0 );
iic_delay( );
IIC_SCL ( 1 );
iic_delay( );
IIC_SDA ( 1 ); /* 发送总线停止信号*/
iic_delay( );
}
/* 等待应答信号 */
uint8_t iic_wait_ack (void) /* return 1:fail 0:succeed*/
{
uint8_t AckBit;
IIC_SDA (1); /* 主机释放SDA线 */
iic_delay( );
IIC_SCL (1); /* 从机返回ACK*/
iic_delay( );
AckBit = IIC_READ_SDA; /* SCL高电平读取SDA状态*/
IIC_SCL(0); /* SCL低电平表示结束ACK检查 */
iic_delay( );
return AckBit;
}
//发送应答位
void iic_SendAck(uint8_t AckBit)
{
IIC_SDA(AckBit);
iic_delay();
IIC_SCL(1);
IIC_SCL(0);
}
/* 发送一个字节数据 */
void iic_send_byte(uint8_t data)
{
for (uint8_t t = 0; t < 8; t++)
{
/* 高位先发 */
IIC_SDA(data & (0x80 >> t));
iic_delay( );
IIC_SCL ( 1 );
iic_delay( );
IIC_SCL ( 0 );
}
}
/* 读取1字节数据 */
uint8_t iic_read_byte (void)
{
uint8_t receive = 0 ;
for (uint8_t t = 0; t < 8; t++)
{
/* 高位先输出,先收到的数据位要左移 */
IIC_SCL ( 1 );
iic_delay( );
if ( IIC_READ_SDA == 1 ) { receive |= (0x80 >> t);}
IIC_SCL ( 0 );
iic_delay( );
}
return receive;
}
2,myiic.h文件:
#ifndef __MYIIC_H
#define __MYIIC_H
#include "stm32f1xx_hal.h"
/******************************************************************************************/
/* 引脚 定义 */
#define IIC_SCL_GPIO_PORT GPIOB
#define IIC_SCL_GPIO_PIN GPIO_PIN_10
#define IIC_SCL_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
#define IIC_SDA_GPIO_PORT GPIOB
#define IIC_SDA_GPIO_PIN GPIO_PIN_11
#define IIC_SDA_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
/******************************************************************************************/
/* IO操作 */
#define IIC_SCL(x) do{ x ? \
HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
}while(0) /* SCL */
#define IIC_SDA(x) do{ x ? \
HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
}while(0) /* SDA */
#define IIC_READ_SDA HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA */
void iic_start(void);
void iic_stop(void);
uint8_t iic_wait_ack(void);
void iic_send_byte(uint8_t data);
uint8_t iic_read_byte (void);
void iic_SendAck(uint8_t AckBit);
#endif
3,mpu6050.c
#include "main.h"
#include "myiic.h"
#include "mpu6050_reg.h"
#include "Delay.h"
#include "mpu6050.h"
#define MPU6050_ADDRESS 0xD0
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
iic_start();
iic_send_byte(MPU6050_ADDRESS);
iic_wait_ack();
iic_send_byte(RegAddress);
iic_wait_ack();
iic_send_byte(Data);
iic_wait_ack();
iic_stop();
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
uint8_t Data;
iic_start();
iic_send_byte(MPU6050_ADDRESS);
iic_wait_ack();
iic_send_byte(RegAddress);
iic_wait_ack();
iic_stop();
iic_start();
iic_send_byte(MPU6050_ADDRESS | 0x01);
iic_wait_ack();
Data = iic_read_byte();
iic_SendAck(1);
iic_stop();
return Data;
}
void MPU6050_Init(void)
{
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)
{
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;
}
void MY_MPU6050_GetData(mpu6050_data *date)
{
uint8_t DataH, DataL;
DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
date->AccX = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
date->AccY = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
date->AccZ = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
date->GyroX = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
date->GyroY = (DataH << 8) | DataL;
DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
date->GyroZ = (DataH << 8) | DataL;
}
4,mpu6050.h
#ifndef __Mpu6050_H__
#define __Mpu6050_H__
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);
void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
typedef struct mpu6050{
int16_t AccX;
int16_t AccY;
int16_t AccZ;
int16_t GyroX;
int16_t GyroY;
int16_t GyroZ;
}mpu6050_data;
void MY_MPU6050_GetData(mpu6050_data *date);
#endif
5,mpu6050地址映射定义
#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
6.主函数获取三轴加速度和三轴角速度
mpu6050_data mydate_mpu6050;//获取数据结构体
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t ID;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
Delay_Init();
OLED_Init();
MPU6050_Init();
ID = MPU6050_GetID();
OLED_ShowHexNum(1,1,ID,3,OLED_8X16);
OLED_Update();
while (1)
{
MY_MPU6050_GetData(&mydate_mpu6050);
OLED_ShowSignedNum(1,17,mydate_mpu6050.AccX,5,OLED_8X16);
OLED_ShowSignedNum(1,33,mydate_mpu6050.AccY,5,OLED_8X16);
OLED_ShowSignedNum(1,49,mydate_mpu6050.AccZ,5,OLED_8X16);
OLED_ShowSignedNum(60,17,mydate_mpu6050.GyroX,5,OLED_8X16);
OLED_ShowSignedNum(60,33,mydate_mpu6050.GyroY,5,OLED_8X16);
OLED_ShowSignedNum(60,49,mydate_mpu6050.GyroZ,5,OLED_8X16);
OLED_Update();
}