STM32学习(5)IIC

1.IIC的作用

 芯片间总线(Inter Interface Circuit,IIC,现在基本采用荷兰飞利浦的IIC总线的技术规范。 

  带有IIC总线的接口的单片机都可直接与具有IIC总线接口的各种扩展器件(如存储器、I/O芯片、A/D、D/A、键盘、显示器)连接。这样就大大的简化了总线的数量。并且IIC通讯支持多主多从

总线上的任意模块都可以跳出来当主机,让IIC协议仲裁。

该通讯协议通过两根通讯线:双向的串行数据线SDA串行时钟线SCL

特点:同步,半双工,带数据应答机制

2.IIC的硬件电路

所有I2C设备的SCL连在一起,SDA连在一起

设备的SCL和SDA均要配置成开漏输出模式(在一主多从的模式下也可以是推挽输出)

SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右(弱上拉杜绝电路短路现象)

任何时候,SCL时钟线都由主机掌握,SDA在主机接收字节和接受应答才由从机控制

3.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)

4.IIC完整时序

1.指定地址写

步骤:起始条件->主机发送一个字节时序(从机地址+读写位(1读,0写))->从机接收应答->指定设备内部寄存器地址->从机接收应答->主机发送内容->从机接收应答->结束条件。

2.当前地址读

步骤:起始条件->主机发送一个字节时序(从机地址+读写位(1读,0写))->从机接收应答->读取从机内容->从机发送应答->结束条件。

读取的数据被放在一个线性指针区域,每读取一位,指针往后移一字节(地址是没有指向性,很少用这种读取方式)

3.指定地址读

步骤:起始条件->主机发送一个字节时序(从机地址+读写位(1读,0写))->从机接收应答->指定设备内部寄存器地址->从机接收应答->SR(重复起始条件,前面相当于指定地址写,但还没写,因此后面加上读取内容,就是指定地址读)->主机发送(从机地址+1读)->从机接收应答->读取从机内容->从机发送应答->结束条件。

5.mpu6050的基本信息

1.简介

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

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

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

扩展:3轴磁力计和气压计(用于无人机的高度确定)

2.基本参数

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

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

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

可配置的数字低通滤波器 可配置的时钟源

可配置的采样分频 I2C从机地址:1101000(AD0=0)     1101001(AD0=1)

6.IIC读取mpu6050(软件读取)

1.对IIC通讯引脚的封装:函数封装和宏定义

(为了更好移植和修改程序)

void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)BitValue);
	Delay_us(10);
}
uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9);
	Delay_us(10);
	return BitValue;
}
//库函数定义,方便改动引脚和延迟时间
#define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
#define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))
//宏定义方式
2.IIC时序基本单元的编写
void MyI2C_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_8 | GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_8 | GPIO_Pin_9);
}
//对GPIO口的初始化,用开漏输出

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)
{
	uint8_t i;
	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)
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);
	for (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;
}
//从机接收应答
3.根据需求初始化mpu6050

以及建立mpu6050地址库

4.通过指定地址读取数据
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_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;
}//通过指针的形式返回多组数据

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值