12、STM32F103C8T6 软件IIC读取MPU6050

一、软件IIC的引脚配置及六块时序单元

通过函数来间接设置SCL和SDA总线,方便加延时

//写 scl总线
void myiic_w_scl(uint8_t bitvalue)
{
	//Delay_us();
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)bitvalue);
	Delay_us(10); //方便修改延时
}

//写 sda总线
void myiic_w_sda(uint8_t bitvalue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)bitvalue);
	Delay_us(10); //方便修改延时
}

//读 sda总线
uint8_t myiic_r_sda(void)
{
	uint8_t bitvalue;
	bitvalue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	Delay_us(10); //方便修改延时
	return bitvalue;
}

1、引脚配置

void myiic_init(void)
{
	//开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	//配置GPIO SCL,SDA初始化为开漏输出, 
	// 开漏模式既可以输出,又可以输入。 输入时,先输出1,再直接读取输入寄存器
	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_10MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	//SCL和SDA置为高电平, 释放总线, 此时IIC总线处于空闲状态
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

2、起始信号

//起始信号需要注意:先拉高sda,再拉高scl, 防止和停止信号冲突
void myiic_start(void)
{
	myiic_w_sda(1);
	myiic_w_scl(1);
	myiic_w_sda(0);
	myiic_w_scl(0);	//结束再将时钟线拉低,方便下次使用
}

3、停止信号

//停止信号:先拉低数据线,原理同上
void myiic_stop(void)
{
	myiic_w_sda(0);
	myiic_w_scl(1);
	myiic_w_sda(1);
}

4、发送一个字节

void myiic_sendbyte(uint8_t byte)
{
	uint8_t i;
	for(i = 0; i < 8; i++)
	{
        //设置最高位数据
		myiic_w_sda(byte & (0x80 >> i)); 
        //释放SCL	(释放SCL之后,从机就会立刻将SDA的数据读走)
		myiic_w_scl(1);	
        //拉低SCL	驱动时钟走一个脉冲(可以继续放下一位数据)
		myiic_w_scl(0); 
	}
}

5、接收一个字节

//接收一个字节:SCL低电平,从机需要将数据放到SDA上,为了防止主机干扰从机写入数据,主机需要先释放SDA(切换为输入模式)
uint8_t myiic_ReceiveByte(void)
{
	uint8_t i, byte = 0x00;

	//主机释放SDA 从机使用,将数据放在SDA上
	myiic_w_sda(1);	
	
	for(i = 0; i < 8; i++)
	{
        //主机释放SCL 读取数据
		myiic_w_scl(1);	
        //如果是 1 置1,如果是 0 ,不用管,因为 byte初始化为 0x00;
		if(myiic_r_sda() == 1)	
		{
			byte |= 0x80 >> i;
		}
        //读取一位数据后,拉低SCL,从机放下一位数据
		myiic_w_scl(0); 
	}
	return byte;
}

6、发送应答

void myiic_SendAck(uint8_t ackBit)
{
	//函数进来时SCL低电平,主机将数据放在SDA上
	myiic_w_sda(ackBit);
	//SCL高电平,从机读取应答
	myiic_w_scl(1);
	//SCL低电平,进入下一个时序单元
	myiic_w_scl(0);
}

7、接收应答

uint8_t myiic_ReceiveAck(void)
{
	uint8_t ackBit;
	//函数进入时SCL低电平,主机释放SDA,防止从机干扰,同时从机将应答位放在SDA上
	myiic_w_sda(1);
	//SCL高电平,主机读取应答位
	myiic_w_scl(1);	
	ackBit = myiic_r_sda();
	//SCL低电平,进入下一个时序单元
	myiic_w_scl(0);
	
	return ackBit;
}

二、读写MPU6050

MPU6050命令的宏定义

//0xD0: 1101 0000(1101 000 是MPU6050的从机地址, 最后一位读写位,0 代表写入操作)
#define MPU6050_ADDRESS 0xD0 //写地址 读地址,需要或上 0x01

#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

1、MPU6050初始化

void MPU6050_Init(void)
{
	myiic_init();
	
	//对MPU6050硬件电路进行初始化配置
	//芯片的写寄存器功能,需要解除芯片的睡眠模式,否则写入是无效的
	//睡眠模式 是电源管理寄存器1 的SLEEP控制的,写入0x00,解除睡眠模式,该寄存器地址为 0x6B;
    //解除睡眠,选择陀螺仪时钟
	MPU6050_Write_Reg(MPU6050_PWR_MGMT_1, 0x01); 
    //6 轴均不待机
	MPU6050_Write_Reg(MPU6050_PWR_MGMT_2, 0x00);
    //采样分频为 10	
	MPU6050_Write_Reg(MPU6050_SMPLRT_DIV, 0x09);
    //滤波参数给最大	
	MPU6050_Write_Reg(MPU6050_CONFIG, 0x06);
    //陀螺仪和下面加速度计都选择最大量程		
	MPU6050_Write_Reg(MPU6050_GYRO_CONFIG, 0x18);	
	MPU6050_Write_Reg(MPU6050_ACCEL_CONFIG, 0x18);
}

2、MPU6050指定地址写一个字节

void MPU6050_Write_Reg(uint8_t regAddress, uint8_t data)
{
	myiic_start();
	myiic_sendbyte(MPU6050_ADDRESS);
	myiic_ReceiveAck();

	myiic_sendbyte(regAddress);
	myiic_ReceiveAck();

	myiic_sendbyte(data);
	myiic_ReceiveAck();

	myiic_stop();
}

3、MPU6050指定地址读一个字节

uint8_t MPU6050_Read_Reg(uint8_t regAddress)
{
	uint8_t data;
	myiic_start();
	myiic_sendbyte(MPU6050_ADDRESS);
	myiic_ReceiveAck();

	myiic_sendbyte(regAddress);
	myiic_ReceiveAck();

	myiic_start();
	myiic_sendbyte(MPU6050_ADDRESS | 0x01);
	myiic_ReceiveAck();
	data = myiic_ReceiveByte();
	myiic_SendAck(1);
	myiic_stop();

	return data;
}

4、获取ID号

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

5、获取加速度、陀螺仪

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_Read_Reg(MPU6050_ACCEL_XOUT_H);
	dataL = MPU6050_Read_Reg(MPU6050_ACCEL_XOUT_L);
	*accX = (dataH << 8) | dataL;
	
	dataH = MPU6050_Read_Reg(MPU6050_ACCEL_YOUT_H);
	dataL = MPU6050_Read_Reg(MPU6050_ACCEL_YOUT_L);
	*accY = (dataH << 8) | dataL;
	
	dataH = MPU6050_Read_Reg(MPU6050_ACCEL_ZOUT_H);
	dataL = MPU6050_Read_Reg(MPU6050_ACCEL_ZOUT_L);
	*accZ = (dataH << 8) | dataL;
	
	dataH = MPU6050_Read_Reg(MPU6050_GYRO_XOUT_H);
	dataL = MPU6050_Read_Reg(MPU6050_GYRO_XOUT_L);
	*gyroX = (dataH << 8) | dataL;
	
	dataH = MPU6050_Read_Reg(MPU6050_GYRO_YOUT_H);
	dataL = MPU6050_Read_Reg(MPU6050_GYRO_YOUT_L);
	*gyroY = (dataH << 8) | dataL;

	dataH = MPU6050_Read_Reg(MPU6050_GYRO_ZOUT_H);
	dataL = MPU6050_Read_Reg(MPU6050_GYRO_ZOUT_L);
	*gyroZ = (dataH << 8) | dataL;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要使用HAL库控制MPU6050,需要先初始化I2C总线,然后通过I2C读写寄存器来控制MPU6050。具体步骤如下: 1. 初始化I2C总线,设置时钟速度和地址模式等参数。 2. 通过I2C发送起始信号,并发送MPU6050的地址和要读写的寄存器地址。 3. 发送数据或读取数据。 4. 发送停止信号。 以下是一个简单的示例代码: ``` #include "stm32f1xx_hal.h" #define MPU6050_ADDR 0xD0 I2C_HandleTypeDef hi2c1; void MPU6050_Init(void) { // 初始化I2C总线 hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c1); // 设置MPU6050的时钟源和采样率等参数 uint8_t data[2]; data[0] = 0x6B; // PWR_MGMT_1寄存器地址 data[1] = 0x00; // 设置时钟源为内部8MHz振荡器 HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, data, 2, 1000); data[0] = 0x1B; // GYRO_CONFIG寄存器地址 data[1] = 0x08; // 设置陀螺仪量程为±500°/s HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, data, 2, 1000); data[0] = 0x1C; // ACCEL_CONFIG寄存器地址 data[1] = 0x08; // 设置加速度计量程为±4g HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, data, 2, 1000); } void MPU6050_ReadAccel(int16_t *accel) { uint8_t data[6]; data[0] = 0x3B; // ACCEL_XOUT_H寄存器地址 HAL_I2C_Master_Transmit(&hi2c1, MPU6050_ADDR, data, 1, 1000); HAL_I2C_Master_Receive(&hi2c1, MPU6050_ADDR, data, 6, 1000); accel[0] = (data[0] << 8) | data[1]; accel[1] = (data[2] << 8) | data[3]; accel[2] = (data[4] << 8) | data[5]; } int main(void) { HAL_Init(); MPU6050_Init(); int16_t accel[3]; while (1) { MPU6050_ReadAccel(accel); // 处理加速度计数据 } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值