F401RE裸机下驱动GY-86

一、GY-86

GY-86是MPU6050(3轴陀螺仪和3轴加速度计)HMC5883L(3轴磁力传感器MS5611-01BA01(气压计三个模块集合而成的十轴姿态传感器。

二、I2C代码配置

主要涉及SDA、SCL的高低电平配置I2C通信开始和终止条件发送字节和接收字节

  • 通过标准库来实现配置
#include "stm32f4xx.h"                
#include "Delay.h"

void MyI2C_W_SCL(uint8_t BitValue) //配置SCL的高低电平
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)BitValue);//通过查看手册得知SCL对应GPIO的第8引脚
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)//配置SDA高低电平
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)BitValue);//与上同理
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)//读取SDA的电平信息
{
	Delay_us(10);
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9);
}

void MyI2C_Init(void)//I2C初始化
{
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//时钟源初始化
	//我们通过GPIO来模拟I2C输入输出
	GPIO_InitTypeDef GPIO_InitStructure;//创建GPIO配置结构体
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//设置GPIO为输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//设置输出模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//设置输出频率
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_8 | GPIO_Pin_9);
}

void MyI2C_Start(void)//通信起始
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)//通信结束
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)//发送字节
{
	for (uint8_t i = 0; i < 8; i ++)//通过与运算,保证发送8位,即一个字节
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t Byte = 0x00;
	MyI2C_W_SDA(1);
	for (uint8_t i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA() == 1)
			{
				Byte |= (0x80 >> i);
			}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)//发送应答
{
	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void)//接收应答
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return AckBit;
}

三、MPU6050

  • MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景

  • 3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度

  • 3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度

  • 机头俯仰角–pitch,机身侧翻角–roll,机体转弯角–yaw

  • 地址:1101 000 或 1101 001。其中转化为16进制有两种,第一种就是直接转换,高三位第四位, 0x68 之类的。第二种要融入读写位,就是 0xD0 或者 0xD1。

    MPU6050框图

    MPU6050.png

I.代码配置

  • 通过查手册,找到对应的寄存器进行配置
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	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);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);
	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)
{
	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 MPU6050_EnableBypass()
{
    uint8_t reg_value;

    reg_value = MPU6050_ReadReg(MPU6050_INT_PIN_CFG);

    reg_value |= MPU6050_I2C_BYPASS_EN;

    MPU6050_WriteReg(MPU6050_INT_PIN_CFG, reg_value);
}

void MPU6050_DisableBypass()
{
    uint8_t reg_value;

    reg_value = MPU6050_ReadReg(MPU6050_INT_PIN_CFG);

    reg_value |= MPU6050_I2C_BYPASS_DIS;

    MPU6050_WriteReg(MPU6050_INT_PIN_CFG, reg_value);
}

四、HMC5883L

I.工作原理

  1. 霍尔效应:

    • 当电流通过一个导体或半导体并置于磁场中时,磁场会导致载流子(如电子)受到洛 伦兹力的作用,出现横向电压,这种现象被称为霍尔效应。

    • HMC5883L利用这种效应来感知周围的磁场强度和方向。

  2. 磁场传感器阵列:

    • 该传感器内部有三个方向的霍尔传感器,分别测量X、Y、Z三个方向的磁场分量。

    • 通过对这三个方向的测量,可以计算出空间中磁场的强度和方向。

  3. 数字输出:

    • 测量到的模拟信号经过内部的模数转换(ADC)处理,转化为数字信号。

    • 通过I²C接口将数据传输给微控制器或其他外部设备,方便进行进一步处理。

  4. 配置与补偿:

    • HMC5883L允许用户配置增益、数据速率和偏置设置,以适应不同的环境条件。

    • 可以通过校准和补偿技术来修正因环境因素(如温度变化)引起的误差。

总结来说,HMC5883L通过霍尔效应感知磁场,并将测量结果以数字信号的形式输出,结合配置参 数和补偿技术,可以实现高精度的磁场测量。

II.代码配置

#define HMC5883L_ADDR	0x3C

void HMC5883L_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(HMC5883L_ADDR);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

uint8_t HMC5883L_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();
	MyI2C_SendByte(HMC5883L_ADDR);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(HMC5883L_ADDR | 0x01);
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	MyI2C_Stop();
	
	return Data;
}

void HMC5883L_Init(void)
{
	MyI2C_Init();
	HMC5883L_WriteReg(HMC5883L_REG_CONFIGA, 0x70);
	HMC5883L_WriteReg(HMC5883L_REG_CONFIGB, 0x20);
	HMC5883L_WriteReg(HMC5883L_REG_MODE, 0x00);
}

uint8_t HMC5883L_GetID(void)
{
	return HMC5883L_ReadReg(HMC5883L_REG_IDA);
}

void HMC5883L_GetData(int16_t *GauX, int16_t *GauY, int16_t *GauZ)
{
	uint8_t DataH, DataL;
	
	DataH = HMC5883L_ReadReg(HMC5883L_REG_X_MSB);
	DataL = HMC5883L_ReadReg(HMC5883L_REG_X_LSB);
	*GauX = (DataH << 8) | DataL;
	
	DataH = HMC5883L_ReadReg(HMC5883L_REG_Y_MSB);
	DataL = HMC5883L_ReadReg(HMC5883L_REG_Y_LSB);
	*GauY = (DataH << 8) | DataL;
	
	DataH = HMC5883L_ReadReg(HMC5883L_REG_Z_MSB);
	DataL = HMC5883L_ReadReg(HMC5883L_REG_Z_LSB);
	*GauZ = (DataH << 8) | DataL;
}

五、MS5611

I.工作原理

MS5611-01BA01是一种高精度气压传感器,广泛用于气压和高度测量。它的工作原理主要基于压阻
效应和温度补偿技术。以下是它的基本原理和特性:

  1. 压阻效应:

    • 传感器内部使用了一种压阻元件,能够在施加压力时产生电阻变化。
    • 这种变化与施加的压力成正比,使得可以通过测量电阻变化来确定气压。
  2. 温度补偿:

    • 由于温度变化会影响传感器的读数,MS5611内置有温度传感器,可以实时监测环境温度并进行补偿,以提高测量精度。
  3. 数字输出:

    • MS5611使用I2C或SPI通信协议,将处理后的气压和温度数据以数字形式输出,便于与微控制器等设备进行数据交换。
  4. 高度计算:

    • 根据气压变化,可以通过气压公式计算出高度,常用于无人机、气象仪器和航天器等应用。

II.框图

MS5611.png

III.代码配置

#define MS5611_ADDRESS	0xEE

extern uint16_t Prom[7];
extern int32_t dt, temperature;
extern int64_t OFF, SENS;
extern int32_t P;
extern int32_t T2;
extern int64_t OFF2, SENS2;

void MS5611_Write(uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(MS5611_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

uint8_t MS5611_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();
	MyI2C_SendByte(MS5611_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(MS5611_ADDRESS | 0x01);//1 是读信号
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	MyI2C_Stop();
	
	return Data;
}

uint16_t MS5611_ReadRegs(uint8_t RegAddress)  //read 2 bytes
{
	uint16_t Data=0;
	
	uint16_t temp1, temp2;
	
	MyI2C_Start();
	MyI2C_SendByte(MS5611_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(MS5611_ADDRESS | 0x01);
	MyI2C_ReceiveAck();
	
	temp1 = MyI2C_ReceiveByte();
	MyI2C_SendAck(0);
	
	temp2 = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	MyI2C_Stop();
	
	Data = (temp1 << 8) + temp2;
	
	return Data;
}

uint32_t MS5611_ReadADC(void)  // read 3 bytes
{
	uint32_t Data =0;
	
	uint16_t temp1, temp2, temp3;
	
	MyI2C_Start();
	MyI2C_SendByte(MS5611_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(MS5611_READADC);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(MS5611_ADDRESS | 0x01);
	MyI2C_ReceiveAck();
	
	temp1 = MyI2C_ReceiveByte();
	MyI2C_SendAck(0); // 发送 ACK 表示接收完第一个字节

	temp2 = MyI2C_ReceiveByte();
	MyI2C_SendAck(0); // 发送 ACK 表示接收完第二个字节

	temp3 = MyI2C_ReceiveByte();
	
	MyI2C_SendAck(1); // 最后一个字节发送 NACK 表示结束
	MyI2C_Stop();

	Data = (temp1 << 16) + (temp2 << 8) + temp3;
	
	return Data;
}

void MS5611_ReadPROM(uint16_t *Prom)//从 prom 中读取出厂校准数据
{
	for(uint8_t i = 0; i <= MS5611_PROMNUM; i++)//MS5611-01BA 包含 128-Bit 的 PROM 存储器。存储器中有一个 4 bit 的 CRC 数据检测位。所以要循环7次
	{
		Prom[i] = MS5611_ReadRegs(MS5611_PROMREAD + (i * 2));
	}
}


void MS5611_Init(void)
{
	MyI2C_Init();
	MS5611_Write(MS5611_RESET);
	Delay_ms(100);
	MS5611_ReadPROM(Prom);
	Delay_ms(100);
}

uint32_t MS561101BA_DO_CONVERSION(uint8_t command)
{
	uint32_t conversion;

	MS5611_Write(command);
	 
	Delay_ms(300);
 
	conversion = MS5611_ReadADC();

   return conversion;

}

void MS5611_Get_Temperature(void)
{
	uint32_t D2 = MS561101BA_DO_CONVERSION(MS5611_CONVERT_D2);
	Delay_ms(10);
	dt = D2 - (Prom[5] << 8);//dt = D2 - prom[5] * 2 ^ 8
	temperature = 2000 + ((dt * Prom[6])>>23);  // 温度值的 100 倍
}

void MS5611_Get_Pressure(void)
{
	uint32_t D1 = MS561101BA_DO_CONVERSION(MS5611_CONVERT_D1);
	Delay_ms(10);
	OFF = (Prom[2] << 16) + ((Prom[4] * dt) >> 7);
	SENS = (Prom[1] << 15) + ((Prom[3] *dt) >> 8);
	
	
	//温度补偿
	if(temperature < 2000)
	{
		T2 = (dt * dt) >> 31;
		OFF2 = 2.5 * (temperature - 2000) * (temperature - 2000);
		SENS2 = 1.25 * (temperature - 2000) * (temperature - 2000);
		if(temperature < -1500)
		{
			OFF2 = OFF2 + 7 * (temperature + 1500) * (temperature + 1500);
			SENS2 = SENS2 + 5.5*(temperature +1500) * (temperature +1500);
		}
	}else  //(Temperature > 2000)
	{
		T2 = 0;
		OFF2 = 0;
		SENS2 = 0;
	}
	
	temperature -= T2;
	OFF -= OFF2;
	SENS -= SENS2;	

	P = (((D1 * SENS) >> 21) - OFF) >> 15;
}

总结:配置GY86主要以理解I2C通信和阅读手册查找对应寄存器配置为主,本身代码编写并不困难

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐