STM32 软件IIC通信篇:IIC读取MPU6050

IIC介绍

        I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线

  • 两根通信线:SCLSerial Clock)、SDASerial Data
  • 同步,半双工
  • 带数据应答
  • 支持总线挂载多设备(一主多从、多主多从)

 硬件电路

  • 所有I2C设备的SCL连在一起,SDA连在一起
  • 设备的SCLSDA均要配置成开漏输出模式
  • SCLSDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

        IIC禁止所有设备输出强上拉的高电平,采用外置弱上拉电阻+开漏输出的电路结构

IIC时序基本单元

  • 起始条件:SCL高电平期间,SDA从高电平切换到低电平

  • 终止条件:SCL高电平期间,SDA从低电平切换到高电平

  • 发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

  • 接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA

  • 发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答

  • 接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA

IIC时序

指定地址写

对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data

起始位 + 高7位地址位1101000(MPU6050地址)+ 读写位0(写入)+ 接收从机的应答位0

+再一次 主机发送一字节(MPU6050内部寄存器地址)+从机应答:0

+再一次 主机发送一字节(写入的数据)+从机非应答:1+停止位

当前地址读

对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data

起始位 + 高7位地址位1101000(MPU6050地址)+ 读写位1(读出)+ 接收从机的应答位0

+再一次 主机接收一字节:从机在SCL低电平期间写入,主机在SCL高电平时读取+停止位

指定地址读

对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data

起始位 + 高7位地址位1101000(MPU6050地址)+ 读写位0(写入)+ 接收从机的应答位0

+再一次 主机发送一字节(MPU6050内部寄存器地址,寄存器指针指到此处)+从机应答

+Sr(Start Repeat)重复起始条件,用于重置读写位

+ 高7位地址位1101000(MPU6050地址)+ 读写位1(读出)+ 接收从机的应答位0

+再一次 主机接收一字节:从机在SCL低电平期间写入,主机在SCL高电平时读取+停止位

MPU6050简单介绍

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

  • 3轴加速度计(Accelerometer):测量XYZ轴的加速度
  • 3轴陀螺仪传感器(Gyroscope):测量XYZ轴的角速度

        加速度计具有静态稳定性,不具有动态稳定性;陀螺仪具有动态稳定性,不具有静态稳定性;二者进行互补滤波,则可得到静态和动态都相对稳定的姿态角

  • 16ADC采集传感器的模拟信号,量化范围:-32768~32767

  • 加速度计满量程选择:±2±4±8±16g

  • 陀螺仪满量程选择: ±250±500±1000±2000°/sec

  • 可配置的数字低通滤波器

  • 可配置的时钟源

  • 可配置的采样分频

  • I2C从机地址:1101000AD0=0           1101001AD0=1

        七位地址里的最低位取决于模块上AD0引脚接高电平或低电平,当AD0=0时,地址为1101000,当AD0=1时,地址为1101001

        (16位表示时,有两种方式,①是把1101000转成16进制0x68,但是因为还有一位读写位,一般使用((0x68<<1)| 读写位)。②把0x68左移一位后的数据当作从机地址,也就是0xD0,再或上读写位。写就发送0xD0,读就发送0xD1。)

软件IIC实现代码

IIC.c

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


void MyIIC_Init(void)
{
	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 MyIIC_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
	delay_us(10);
}

void MyIIC_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	delay_us(10);
}

uint8_t MyIIC_R_SDA(void)//读取当前位
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	delay_us(10);
	return BitValue;
}




void MyIIC_Start(void)//起始信号
{
	MyIIC_W_SDA(1);
	MyIIC_W_SCL(1);
	
	MyIIC_W_SDA(0);
	MyIIC_W_SCL(0);
}

void MyIIC_Stop(void)//终止条件
{
	MyIIC_W_SDA(0);
	MyIIC_W_SCL(1);
	MyIIC_W_SDA(1);
}

void MyIIC_SendByte(uint8_t Byte)//发送一字节
{
	uint8_t i;
	for(i=0; i<8; i++)
	{
		MyIIC_W_SDA(Byte & (0x80 >> i));
		MyIIC_W_SCL(1);
		MyIIC_W_SCL(0);
	}
}

uint8_t MyIIC_ReceiveByte(void)//接收一字节
{
	uint8_t i, Byte = 0x00;
	MyIIC_W_SDA(1);
	for(i=0; i<8; i++)
	{
		MyIIC_W_SCL(1);
		if(MyIIC_R_SDA() == 1)//当SDA为1时,写入1;为0时,写入0
			Byte |= (0x80 >> i);
		MyIIC_W_SCL(0);
	}
	return Byte;
}

void MyIIC_SendAck(uint8_t AckBit)
{
	MyIIC_W_SDA(AckBit);
	MyIIC_W_SCL(1);
	MyIIC_W_SCL(0);
}

uint8_t MyIIC_ReceiveAck(void)
{
	uint8_t AckBit;
	MyIIC_W_SDA(1);
	MyIIC_W_SCL(1);
	AckBit = MyIIC_R_SDA();//主机释放SDA后,从机发送应答
	MyIIC_W_SCL(0);
	return AckBit;
}


MPU6050.c

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

#define MPU_6050_ADDRESS 0xD0

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyIIC_Start();
	MyIIC_SendByte(MPU_6050_ADDRESS);
	MyIIC_ReceiveAck();
	MyIIC_SendByte(RegAddress);
	MyIIC_ReceiveAck();
	MyIIC_SendByte(Data);
	MyIIC_ReceiveAck();
	MyIIC_Stop();
}

uint8_t MPU_6050_ReadReg(uint8_t RegAddress)//指定地址读
{
	uint8_t Data;
	
	MyIIC_Start();
	MyIIC_SendByte(MPU_6050_ADDRESS);
	MyIIC_ReceiveAck();
	MyIIC_SendByte(RegAddress);
	MyIIC_ReceiveAck();
	
	MyIIC_Start();
	MyIIC_SendByte(MPU_6050_ADDRESS | 0x01);
	MyIIC_ReceiveAck();
	Data = MyIIC_ReceiveByte();
	MyIIC_SendAck(1);
	MyIIC_Stop();
	
	return Data;
}

void MPU6050_Init(void)
{
	MyIIC_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);
	
}

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 = MPU_6050_ReadReg(MPU6050_ACCEL_XOUT_H);//分别读取高位和低位,并利用移位拼接到16位数据中
	DataL = MPU_6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU_6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU_6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;

}

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//加速度寄存器X轴的高8位
#define	MPU6050_ACCEL_XOUT_L	0x3C//加速度寄存器X轴的低8位
#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//陀螺仪的x轴
#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//电源管理寄存器1,地址是0x6B
#define	MPU6050_PWR_MGMT_2		0x6C//电源管理寄存器2,地址是0x6B
#define	MPU6050_WHO_AM_I		0x75

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
#include "MPU6050.h"


int main(void)
{
	delay_init();
	OLED_Init();
	MPU6050_Init();

	int16_t AX, AY, AZ, GX, GY, GZ;
	
	while(1)
	{
		MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);

		OLED_ShowSignedNum(1, 1, AX, 5);
		OLED_ShowSignedNum(2, 1, AY, 5);
		OLED_ShowSignedNum(3, 1, AZ, 5);
		OLED_ShowSignedNum(1, 8, GX, 5);
		OLED_ShowSignedNum(2, 8, GY, 5);
		OLED_ShowSignedNum(3, 8, GZ, 5);

		
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值