I2C 接口控制器理论讲解

IIC系列文章:
(1)I2C 接口控制器理论讲解
(2)I2C接口控制设计与实现
(3)I2C连续读写实现
(4) 使用IIC进行多数据读取测试


一、 IIC协议

I2C(Inter-Integrated Circuit BUS) 集成电路总线,它是一种串行通信总线,使用多主从架构,由 Philips 公司开发的一种简单、双向二线制同步串行总线,只需要两根线即可在连接于总线上的器件之间传送信息。 I2C 通讯协议和通信接口在很多工程中有广泛的应用,如数据采集领域的串行 AD,图像处理领域的摄像头配置,工业控制领域的 X 射线管配置等等。除此之外,由于 I2C 协议占用引脚特别少,硬件实现简单,可扩展型强,现在被广泛地使用在系统内多个集成电路 (IC)间的通讯。IIC数据传输速率有标准模式(100 kbps)、快速模式(400 kbps)和高速模式(3.4 Mbps),另外一些变种实现了低速模式(10 kbps)和快速+模式(1 Mbps)。

下图是一个基于FPGA的主机仅通过2根线的IIC总线控制多个IIC外设的典型应用图:
在这里插入图片描述

二、IIC协议解析

1.特点

1、它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。
2、一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线 (SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
3、每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。
4、总线通过上拉电阻接到电源。当 I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
5、多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线

2.规定

在时钟(SCL)为高电平的时候,数据总线(SDA)必须保持稳定,所以数据总线(SDA)
在时钟(SCL)为低电平的时候才能改变。
在这里插入图片描述

 在时钟(SCL)为高电平的时候,数据总线(SDA)由高到低的跳变为总线起始信号,在时钟(SCL)为高电平的时候,数据总线(SDA)由低到高的跳变为总线停止信号。

在这里插入图片描述

 应答,当 IIC 主机(不一定是发送端还是接受端)将 8 位数据或命令传出后,会将数据总线(SDA)释放,即设置为输入,然后等待从机应答(低电平 0 表示应答,1 表示非应答),此时的时钟仍然是主机提供的。

在这里插入图片描述
数据帧格式,I2C 器件通讯的时候首先是要发送“起始信号”,紧跟着就是七位器件地址,第八位是数据传送方向位(0:代表写,1:代表读),再后面就是等待从机的应答。当然传送结束后,“终止信号”也是由主机来产生的。发送数据的时候是高位先发送。

3.器件地址

每个 I2C 器件都有一个器件地址,有的器件地址在出厂时地址就设置好了,用户不可以更改(例如 OV7670 器件地址为固定的 0x42),有的确定了几位,剩下几位由硬件确定(比如常见的 I2C 接口的 EEPROM 存储器,留有 3 个控地址的引脚,由用户自己在硬件设计时确定)。严格讲,主机不是直接向从机发送地址,而是主机往总线上发送地址,所有的从机都能接收到主机发出的地址,然后每个从机都将主机发出的地址与自己的地址比较,如果匹配上了,这个从机就会向总线发出一个响应信号。主机收到响应信号后,开始向总线上发送数据,与这个从机的通讯就建立起来了。如果主机没有收到响应信号,则表示寻址失败。通常情况下,主从器件的角色是确定的,也就是说从机一直工作在从机模式。不同器件定义地址的方式是不同的,有的是软件定义,有的是硬件定义。

I2C 协议在进行数据传输时,主机需要首先向总线上发出控制命令,其中控制命令就包含了从机器件地址和读写控制,然后等待从机响应。如图所示为 I2C 控制命令传输的数据格式。

在这里插入图片描述
I2C 传输时,按照从高到低的位序进行传输。控制字节的最低位为读写控制位,当该位为 0 时表示主机对从机进行写操作,当该位为 1 时表示主机对从机进行读操作。

4.存储地址

每个支持 I2C 协议的器件,内部总会有一些可供读写的寄存器或存储器,例如,EEPROM 存储器,内部就是顺序编址的一系列存储单元;型号为 OV7670 的 CMOS 摄像头(OV7670 的该接口叫 SCCB 接口,其实质也是一种特殊的 I2C 协议,可以直接兼容 I2C 协议),其内部就是一系列编址的可供读写的寄存器。因此,我们要对一个器件中的存储单元(寄存器和存储器,以下简称存储单元)进行读写,就必须要能够指定存储单元的地址。I2C 协议设计了有从机存储单元寻址地址段,该地址段为一个字节或两个字节长度,在主机确认收到从机返回的控制字节响应后由主机发出。地址段长度视不同的器件类型,长度不同,具体是一个字节还是两个字节,与器件的存储单元数量有关。下方图 1 和图2 分别为 1 字节地址和 2 字节地址器件的地址分布图
在这里插入图片描述

在这里插入图片描述

5.EEPROM 芯片 24LC64

5.1 24LC64 简介

EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。24LC64 作为 EEPROM 芯片,是一种 64k 存储大小的两线制串行读/写非易失性 I2C 存储器设备,支持低功率和低电压操作。该芯片的器件地址通过 A2,A1,A0 三位设置,因此一个 I2C 总线最多可以连接 8 个从设备。

5.2 器件地址

笔者使用的芯片的器件地址的高四位为固定值 1010,A2、A1、A0三个引脚通过物理接地或者上拉控制器件地址。 开发板和拓展板上 EEPROM芯片的电路如图 所示:

在这里插入图片描述

可以看到,A2、A1、A0 引脚物理接地,所以 ACZ702 开发板上 EEPROM芯片的器件地址为七位的 1010000,即 0X50。由于这部分描述并不统一,有的手册中习惯加上 1 位传输方向位 0,即用 8 位的 0XA0 表示器件地址。

三、IIC写时序

1.单字节写时序

不同器件,I2C 器件地址字节不同,这样对于 I2C 单字节写时序就会有所差别,下图 1 和下图 2 分别为 1 字节地址段器件和 2 字节地址段器件单字节写时序图。

在这里插入图片描述

根据时序图,从主机角度来描述一次写入单字节数据过程如下:
单字节地址写单字节数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输 1 字节地址数据;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机设置 SDA 为输出,传输待写入的数据;
8、设置 SDA 为三态门输入,读取从机应答信号;
9、读取应答信号成功,主机产生 STOP 位,终止传输。
双字节地址写单字节数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输地址数据高字节;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机设置 SDA 为输出,传输地址数据低字节;
8、设置 SDA 为三态门输入,读取从机应答信号;
9、读取应答信号成功,主机设置 SDA 为输出,传输待写入的数据;
10、设置 SDA 为三态门输入,读取从机应答信号;
11、读取应答信号成功,主机产生 STOP 位,终止传输。

2.连续写时序(页写时序)

注:I2C 连续写时序仅部分器件支持。
连续写(也称页写,需要注意的是 I2C 连续写时序仅部分器件支持)是主机连续写多个字节数据到从机,这个和单字节写操作类似,连续多字节写操作也是分为 1 字节地址段器件和 2 字节地址段器件的写操作,下图 1 和下图 2 分别为 1 字节地址段器件和 2 字节地址段器件连续多字节写时序图。

在这里插入图片描述

根据时序图,从主机角度来描述一次写入多字节数据过程如下:
单字节地址器件连续多字节写数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输 1 字节地址数据;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机设置 SDA 为输出,传输待写入的第 1 个数据;
8、设置 SDA 为三态门输入,读取从机应答信号;
9、读取应答信号成功后,主机设置 SDA 为输出,传输待写入的下一个数据;
10、设置 SDA 为三态门输入,读取从机应答信号;n 个数据被写完,转到步骤 11,若数据未被写完,转到步骤 9;
11、读取应答信号成功,主机产生 STOP 位,终止传输。

双字节地址器件连续多字节写数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输地址数据高字节;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机设置 SDA 为输出,传输地址数据低字节;
8、设置 SDA 为三态门输入,读取从机应答信号;
9、读取应答信号成功,主机设置 SDA 为输出,传输待写入的第 1 个数据;
10、设置 SDA 为三态门输入,读取从机应答信号;
11、读取应答信号成功后,主机设置 SDA 为输出,传输待写入的下一个数据;
12、设置 SDA 为三态门输入,读取从机应答信号;n 个数据被写完,转到步骤 13,若数据未被写完,转到步骤 11;
13、读取应答信号成功,主机产生 STOP 位,终止传输。
注:对于 AT24Cxx 系列的 EEPROM 存储器,一次可写入的最大长度为 32 字节。

四、IIC读时序

1.单字节读时序

同样的,I2C 读操作时序根据不同 I2C 器件具有不同的器件地址字节数,单字节读操作分为 1 字节地址段器件单字节数据读操作和 2 字节地址段器件单字节数据读操作。下图 1和下图 2 分别为不同情况的时序图。

在这里插入图片描述
根据时序图,从主机角度来描述一次读取单字节数据过程如下:
单字节地址读取单字节数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输 1 字节地址数据;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机发起起始信号;
8、主机传输器件地址字节,其中最低位为 1,表明为读操作;
8、设置 SDA 为三态门输入,读取从机应答信号;
9、读取应答信号成功,主机设置 SDA 为三态门输入,读取 SDA 总线上的一个字节的数据;
10、产生无应答信号(高电平)(无需设置为输出高电平,因为总线会被自动拉高);
11、主机产生 STOP 位,终止传输。
双字节地址读取单字节数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输地址数据高字节;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机设置 SDA 为输出,传输地址数据低字节;
8、设置 SDA 为三态门输入,读取从机应答信号;
9、读取应答信号成功,主机发起起始信号;
10、主机传输器件地址字节,其中最低位为 1,表明为读操作;
11、设置 SDA 为三态门输入,读取从机应答信号;
12、读取应答信号成功,主机设置 SDA 为三态门输入,读取 SDA 总线上的一个字节的数据;
13、主机设置 SDA 输出,产生无应答信号(高电平)(无需设置为输出高电平,因为总线会被自动拉高);
14、主机产生 STOP 位,终止传输。

2.连续读时序(页读取)

连续读是主机连续从从机读取多个字节数据,这个和单字节读操作类似,连续多字节读操作也是分为 1 字节地址段器件和 2 字节地址段器件的读操作,下图 1 和下图 2 分别为字节地址段器件和 2 字节地址段器件连续多字节读时序图。
在这里插入图片描述
在这里插入图片描述

根据时序图,从主机角度来描述一次读取多字节数据过程如下:
单字节地址器件连续多字节读取数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输 1 字节地址数据;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机发起起始信号;
8、主机传输器件地址字节,其中最低位为 1,表明为读操作;
9、设置 SDA 为三态门输入,读取从机应答信号;
10、读取应答信号成功,主机设置 SDA 为三态门输入,读取 SDA 总线上的第 1 个字节
的数据;
11、主机设置 SDA 输出,发送一位应答信号;
12、设置 SDA 为三态门输入,读取 SDA 总线上的下一个字节的数据;若 n 个字节数据
读完成,跳转到步骤 13,若数据未读完,跳转到步骤 11;(对于 AT24Cxx,一次读
取长度最大为 32 字节,即 n 不大于 32)
13、主机设置 SDA 输出,产生无应答信号(高电平)(无需设置为输出高电平,因为总
线会被自动拉高);
14、主机产生 STOP 位,终止传输。
双字节地址器件连续多字节读取数据过程:
1、主机设置 SDA 为输出;
2、主机发起起始信号;
3、主机传输器件地址字节,其中最低位为 0,表明为写操作;
4、主机设置 SDA 为三态门输入,读取从机应答信号;
5、读取应答信号成功,主机设置 SDA 为输出,传输地址数据高字节;
6、主机设置 SDA 为三态门输入,读取从机应答信号;
7、读取应答信号成功,主机设置 SDA 为输出,传输地址数据低字节;
8、设置 SDA 为三态门输入,读取从机应答信号;
9、读取应答信号成功,主机发起起始信号;
10、主机传输器件地址字节,其中最低位为 1,表明为读操作;
11、设置 SDA 为三态门输入,读取从机应答信号;
12、读取应答信号成功,主机设置 SDA 为三态门输入,读取 SDA 总线上的第 1 个字节的数据;
13、主机设置 SDA 输出,发送一位应答信号;
14、设置 SDA 为三态门输入,读取 SDA 总线上的下一个字节的数据;若 n 个字节数据读完成,跳转到步骤 15,若数据未读完,跳转到步骤 13;(对于 AT24Cxx,一次读取长度最大为 32 字节,即 n 不大于 32)
15、主机设置 SDA 输出,产生无应答信号(高电平)(无需设置为输出高电平,因为总线会被自动拉高);
16、主机产生 STOP 位,终止传输。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
好的,以下是一个基于MS32006马达驱动芯片,使用I2C接口控制的四相五线步进电机的C语言驱动程序: ```c #include "stm32f10x.h" #include "stm32f10x_i2c.h" #define PHASE_A 0x01 #define PHASE_B 0x02 #define PHASE_C 0x04 #define PHASE_D 0x08 #define DELAY 1 void I2C_Configuration(void) { I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); I2C_DeInit(I2C1); I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x30; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 100000; I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); } void I2C_WriteByte(uint8_t addr, uint8_t data) { while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, data); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = PHASE_A | PHASE_B | PHASE_C | PHASE_D; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); I2C_Configuration(); while (1) { I2C_WriteByte(0x30, PHASE_A); delay(DELAY); I2C_WriteByte(0x30, 0x00); I2C_WriteByte(0x30, PHASE_B); delay(DELAY); I2C_WriteByte(0x30, 0x00); I2C_WriteByte(0x30, PHASE_C); delay(DELAY); I2C_WriteByte(0x30, 0x00); I2C_WriteByte(0x30, PHASE_D); delay(DELAY); I2C_WriteByte(0x30, 0x00); } } ``` 这个程序使用GPIOA的四个引脚来控制五线四相步进电机。通过I2C_WriteByte函数向MS32006芯片写入命令,控制电机转动。需要注意的是,MS32006马达驱动芯片的I2C地址可能并不是0x30,需要根据实际情况进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C.V-Pupil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值