Loading

【STM32开发-基于标准库】学习笔记-02-I2C协议

本文档基于STM32F103C8T6 - I2C一主多从模式
本文档基于 bilibili江协科技 https://www.bilibili.com/video/BV1th411z7sn

I2C协议概述

I2C通讯具有两条数据线(SCL、SDA):SCL用来时序协调,SDA用来传输数据。
其优点有数据线占用少,节约系统资源,可一主多从、多主多从,但缺点就是速度慢。

I2C协议硬件电路图

image
主机可通过一条I2C总线连接多个设备(从机)。SCL线的控制权由主机完全掌控,而SDA线的控制权只有在设备(从机)发送数据时才会由主机移交。

由于主机和从机会在SDA线上进行反复的输入输出,在极端情况下主从机的协调不一致,导致主从机的端口同时处于输出状态,而当一个输出高电平,一个输出低电平时就会发生短路。
因此,我们将主机、设备的SDA和SCL口均设置为开漏输出模式,同时使用上拉电阻(4.7K左右)。

I2C协议数据格式

I2C的数据传输格式如下:起始位(1位),数据位(8位),应答位(1位),停止位(1位)

  • 在空闲状态,SCL和SDA均处于高电平。
  • 在通信时,SDA处于高电平时,主机或从机读取SCL的电平状态(读取数据位),SDA处于低电平时,主机或从机可以改变SCL的电平状态(修改数据位)。

简单来说,想要发送一个字节,就先让SCL处于低电平,将SDA变成数据位(0|1)。然后拉高SCL,此时读取到的SDA电平状态即为数据中的一位。往复如此,8次后就能将数据位拼接成一个完整的字节。

起始位

SCL处于高电平,同时SDA发送下降沿
image
此时,主机通知从机设备开始通信
之后,拉低SCL,正式开始传输数据位
image

数据位

SCL处于低电平时,
除了起始位和停止位,在整个时序中,SCL均由低电平开始,低电平结束
image

应答位

SCL处于低电平时,SDA放置应答位。SCL拉高后读取到的就是应答位
应答:0
非应答:1
主机接收到了一个字节后,发送数据0表示应答。
主机发送了一个字节后,如果从机收到了,则将接收到从机发送的数据0。

停止位

SCL处于高电平,同时SDA有一个上升沿
image
此时,总线进入空闲状态

ok,通过以上数据的传输格式,就可以组成一个完整的通信了。

I2C协议完整数据帧

image
这是一个完整的主机写入数据给从机的I2C通信图,我们依次分析。

记住,每发送一个字节(8位),后面都要跟着应答位。

0.起始位

image
开始通信

1.指定从机地址

image
在起始位后,后面跟着的7位代表从机地址

2.指定主机读取从机数据还是写入从机数据【决定后续字节】

image
指定从机地址后,第8位数据
如果是0,代表写入,则后续数据都是写入操作,再由主机发送指定地址指定数据
如果是1,代表读取,后续字节都是从机发送的数据
此处为写入从机数据,后续为写入操作
跳转查看详细格式

3.应答位

image
应答位为0,表示从机接收到了数据

4.后续字节

image
后续字节可以由从机自定义用途,一般查阅从机数据手册

此处从机为mpu6050,代表主机需要写入从机的寄存器地址0x19

5.应答位

image
应答位为0,表示从机接收到了数据

6.后续字节

image
同样,后续字节查阅从机数据手册

此处,主机将写入0xAA到从机寄存器0x19

7.应答位

image
应答位为0,表示从机接收到了数据,通信继续
应答位为1,表示主机忙,通信结束
【重要】想结束通信最后一位应答位必须为1

8.停止位

image
结束通信

【其他重要读写寄存器操作如下】:

【核心】2.1当前地址读

从机中所有寄存器地址以指针变量的形式存储,上电默认指向0地址,每一次读写操作成功后指针都会自动指向下一个
image
1.指定从机地址后,紧跟着数据位是1,代表读取从机数据
2.应答位
3.读取到从机发送的数据(0x0f)

【核心】2.1指定地址读

指定地址写+当前地址读
(0.起始位)
1.指定从机地址,数据位0,(代表写数据)
(2.应答位)
3.发送要写入的从机地址 (指定了地址)【该地址为从机当前寄存器地址】
(4.应答位)
【停止写入操作,插入当前地址读】
5.重复起始位
6.重新指定从机地址,数据位1,(代表读数据)
(7.应答位)
8.主机接收到从机发送的数据
(9.应答位)
(10.停止位)

【核心】2.2指定地址写

如上:I2C协议完整数据帧

I2C代码编写

1.数据位读写

要实现I2C通信,我们需要定义最基本的数据位读写函数

#include "stm32f10x.h"
#include "Delay.h"

#define GPIO_Type GPIOB
#define GPIO_Pin_SCL GPIO_Pin_10
#define GPIO_Pin_SDA GPIO_Pin_11

uint8_t MyI2C_R_SCL(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIO_Type, GPIO_Pin_SCL);
	Delay_us(10);
	return BitValue;
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIO_Type, GPIO_Pin_SDA);
	Delay_us(10);
	return BitValue;
}

void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIO_Type, GPIO_Pin_SCL, (BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIO_Type, GPIO_Pin_SDA, (BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_SCL | GPIO_Pin_SDA;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_Type, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIO_Type, GPIO_Pin_SCL | GPIO_Pin_SDA);
}

2.起始位

void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

3.数据位

/*发送一个字节*/
void MyI2C_SendByte(uint8_t Byte)
{
	for(uint8_t n=0; n<8; n++){
		MyI2C_W_SDA(Byte & (0x80 >> n));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}
/*读取一个字节*/
uint8_t MyI2C_ReadByte(void)
{
	uint8_t Byte = 0x00;
	MyI2C_W_SDA(1);//此处为何置1?SDA置1代表交出了总线控制权,其实开漏模式加弱上拉,并不是SDA就是高电平。\
	主机交出总线控制权后,从机会立刻接管并再SDA上放置值,因此之后拉高SCL后读取的就是从机的数据
	for(uint8_t n=0; n<8; n++){
		MyI2C_W_SCL(1);
		if( MyI2C_R_SDA() == 1)
		{
			Byte |= (0x80 >> n);
		}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

4.应答位

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

/*接收应答位*/
uint8_t MyI2C_ReadAck(void)
{
	uint8_t Ack;
	MyI2C_W_SDA(1);//此处为何置1?SDA置1代表交出了总线控制权,其实开漏模式加弱上拉,并不是SDA就是高电平。\
	主机交出总线控制权后,从机会立刻接管并再SDA上放置值,因此之后拉高SCL后读取的就是从机的数据
	MyI2C_W_SCL(1);
	Ack = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return Ack;
}

5.停止位

void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}
posted @ 2025-04-24 20:43  CIOZ  阅读(225)  评论(0)    收藏  举报