I2C通信协议理解

前言

  就个人对I2C通信的理解,通过用图文的方式,尽量简洁的记录下此文。希望能对大家理解I2C通信协议有所帮助。

理解I2C

  对于I2C协议的理解,我个人是将完整的I2C时序协议,分成六大块理解。分别是开始条件,结束条件,发送字节,发送字节,发送应答,接收应答。通过对六大块的调用。拼接起来使用即可组成完整的I2C协议通信。

以下约定:"高"指高电平,"低"指低电平

  • 开始条件(1):SDA由高变低,SCL高电平期间。
  • 结束条件(1):SDA由低变高,SCL不变。
  • 发送字节(8):将要发送的数据(0或1)置给SDA,然后SCL由"低"变"高",就完成一次一位数据的发送,循环8次,就是发送一个字节。
  • 发送字节(8):释放SDA,然后SCL由"低"变"高",此时读取SDA的电平,就是从机返回的一位数据,循环8次,就能接收到一个字节。
  • 发送应答(1):当主机发送完一个字节数据后,等待从机的回应。用来为主机判断从机有没有接受到数据做判断。
  • 接收应答(1):当主机接收完一个字节数据后,给予从机的回应。用来为主机判断从机有没有接收到数据做判断。

  上面的六大操作块后都跟(x),x为SDA和SCL操作的次数。(我目前见到的I2C协议是这样,不排除有改变或没见过的)。可能有人对于两个应答有绕,通俗一点来讲就是,一方发送数据发送(或返回)一个字节后,对方都得产生一个位的回应。

图解IIC

  以下是参考江科大的I2C的图形和我个人理解,绘制出来的时序六大块,看着就能明白通信块的电平跳变。

  1. IIC六大块图片解析

    在这里插入图片描述

    图中紫色线条和字眼的,代表输入权转移都从机,主机则在等待状态。

  2. 基础IIC通信

    下图的图示就介绍的模块拼接后,完成一次收发通信的演示。

    在这里插入图片描述

代码演示

下面是我在STM32F1中用的软件模拟I2C,只要理解了,都可以随便搬到其它单片机上,运行的。大家可以参考参考。

MyI2C.h

#ifndef __MyI2C__H__
#define __MyI2C__H__

void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
uint8_t MyI2C_R_SDA(void);

void MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);


#endif

MyI2C.c

#include "gpio.h"
#include "MyI2C.h"

// 使用时,可能还要重定向延时
// 假如是32位单片机,SDA端口,一般要设置为开漏模式,可以读取和设置电平

/* 配置I2C端口和引脚 */
#define MyI2C_SDA_PORT 	GPIOB
#define MyI2C_SDA_PIN 	GPIO_Pin_11
#define MyI2C_SCL_PORT 	GPIOB
#define MyI2C_SCL_PIN 	GPIO_Pin_10

/**
* @描述:写入I2C的SCL引脚数据
* @参数 BitValue: 0(写入低电平) 1(写入高电平)
*/
void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(MyI2C_SCL_PORT,MyI2C_SCL_PIN,(BitAction)BitValue);
	Delay_us(10);
}

/**
 * @描述:写入I2C的SDA引脚数据
 * @参数 BitValue: 0(写入低电平) 1(写入高电平)
 */
void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(MyI2C_SDA_PORT,MyI2C_SDA_PIN,(BitAction)BitValue);
	Delay_us(10);
}

/**
 * @描述:读取I2C的SDA引脚数据
 * @返回值: 0(读取到低电平) 1(读取到高电平)
 */
uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue=GPIO_ReadInputDataBit(MyI2C_SDA_PORT,MyI2C_SDA_PIN);
	Delay_us(10);
	return BitValue;
}

/**
 * @描述:对使用到的I2C的SDA,SCL引脚进行初始化
 */
void MyI2C_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = MyI2C_SDA_PIN | MyI2C_SCL_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, MyI2C_SDA_PIN | MyI2C_SDA_PIN);
}

/**
 * @描述:I2C开始条件
 */
void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
	
}

/**
 * @描述:I2C结束条件
 */
void MyI2C_Stop(void)
{
	//MyI2C_W_SCL(0);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

/**
 * @描述:I2C发送字节
 */
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);
	}
}

/**
 * @描述:I2C接收字节
 */
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()) {Byte |= (0x80 >> i);}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

/**
 * @描述:I2C发送应答
 */
void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

/**
 * @描述:I2C接收应答
 */
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;
}

知识要点

  1. 一般情况下,通信数据高位在前。
  2. I2C器件两条线SDA(数据线),SCL(时钟线)。
  3. SDA,SCL线在I2C协议上是要默认高电平的,必要时是要加上上拉电阻。
  4. I2C协议的通信速度分为三种模式:1.标准模式的传输速率为100Kb/s;2.快速模式为400Kb/s;3.高速模式为3.4Mb/s。
  5. 本文记录中I2C通信时没有强调速率的影响,但是在实际使用时,如果引脚速率太快,就要在软件中,适当的在每个时序块操作中,添加一定的延时。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值