通讯协议2-IIC通讯协议
注意:本文章需要配合无际单片机编程-硬件基础2.0教程视频学习。
注意:本文章需要配合无际单片机编程-硬件基础2.0教程视频学习。
用途:在单片机电路中,IIC一般用于同一个电路板上,不同芯片之间的数据交互,或不同线路板之间的数据交互(短距离,1-2米内),是最常用的协议之一;
一、硬件接口
1.硬件接口1:
IIC硬件接口一般有2两根信号线,一根是数据线SDA,另一根是时钟线SCL。
SDA: 数据线,负责数据的发送或接收
SCL: 时钟线,提供数据交互的时钟
GND: 2芯片通讯需要共地
2.硬件连接2:
IIC总线支持,一个总线上挂多个IIC通讯设备(或芯片),所有接到I2C总线上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上
3.IIC通讯说明
- IIC硬件支持在由多个IIC芯片串联连接,其中的一个是主机,其他的都是从机(和RS485比较类似)。
- 主机: 启动数据的发送和接收。
- 从机:被主机寻访操作的设备称为从机,为了进行通讯,每个从设备要有唯一的设备地址,以便于主机寻访
- 为了避免总线信号的混乱,连接到总线的输出端必须是开漏输出(和IO口的开漏模式一样),所以在IIC电路中,我们必须设计外部上拉电阻;
- SDA数据线 连接的IO口必须支持双向通讯,(数据的发送和接收)
- 通讯的时钟由主机的SCL脚 提供
- 同一时刻,主机只能和某一个从机通讯
二、通讯协议
1. IIC通讯协议格式
IIC通讯由 空闲状态+起始位+有效数据帧+应答(非应答)+停止位 组成
① 空闲状态:SDA SCL 高电平
② 起始位:
③ 有效数据帧
时钟线SCL 低电平的时候,SDA的数据可以更改,SCL是高电平的时候,是数据检测状态,SDA的电平不能更改; 高位在前
④ 应答位
⑤ 没有应答
⑥ 停止位
2. 数据通讯举例:
①假如主机发送数据0x65(有应答); 0110 0101
空闲状态+起始位+有效数据帧+应答(非应答)+停止位
②假如主机发送数据0x65(无应答)
3. IIC通讯时间:
这里以AT24C128芯片为例(下图截自芯片规格书)。
三、举例:IO模拟实现IIC通讯(以24C128为例)
1. 硬件电路
2. AT24C128从机地址&读写操作
①AT24C128从机地址
②AT24C128写操作
设备地址(含写操作指令)+内存地址(2Bytes)+ 数据
例如对AT24C128芯片内部的地址0x01 写数据0x03:
设备地址(含写操作指令): 0xA0 1010 0000b
内存地址: 0x00 0x01
数据: 0x03
③AT24C128读操作
设备地址(含写操作指令)+内存地址(2Bytes)+ 设备地址(含读操作指令)+返回数据
例如对AT24C128芯片内部的地址0x01 :
设备地址(含写操作指令): 0xA0 1010 0000b
内存地址: 0x00 0x01
设备地址(含读操作指令): 0xA1 1010 0001b
返回数据: 返回24C128保存的数据
3. 程序:
注意:这里主要的任务是结合代码来进一步理解IIC通讯,没有提供完整的代码(包括:GPIO口的初始化 等)
①起始位
static void I2C_Start(void)
{
hal_I2C_SDA(1);
I2C_delay(1);
hal_I2C_SCL(1);
I2C_delay(1);
hal_I2C_SDA(0);
I2C_delay(1);
}
②停止位
static void I2C_Stop(void)
{
hal_I2C_SDA(0);
I2C_delay(1);
hal_I2C_SCL(1);
I2C_delay(1);
hal_I2C_SDA(1);
I2C_delay(1);
}
③应答信号
static void I2C_Ack(void)
{
hal_I2C_SCL(0);
I2C_delay(1);
hal_I2C_SDA(0);
I2C_delay(1);
hal_I2C_SCL(1);
I2C_delay(1);
hal_I2C_SCL(0);
I2C_delay(1);
}
④无应答
static void I2C_NoAck(void)
{
hal_I2C_SCL(0);
I2C_delay(1);
hal_I2C_SDA(1);
I2C_delay(1);
hal_I2C_SCL(1);
I2C_delay(1);
hal_I2C_SCL(0);
I2C_delay(1);
}
⑤等待应答
static unsigned char I2C_WaitAck(void)
{
hal_I2C_SDA(1);
hal_I2C_SDA_IO_Set(1); ///配置为输入模式
hal_I2C_SCL(1);
I2C_delay(1);
if(hal_I2C_SDA_INPUT())
{//读到的是高电平
return 0; //没有收到应答信号
}
hal_I2C_SCL(0);
hal_I2C_SDA_IO_Set(0);
I2C_delay(1);
return 1; ///表示收到了应答信号
}
⑥数据发送
static void I2C_SendByte(unsigned char SendByte)
{
unsigned char i=0;
unsigned char temp;
temp = SendByte;
for(i=0;i<8;i++)
{
hal_I2C_SCL(0);
I2C_delay(1);
if(temp&0x80)
{
hal_I2C_SDA(1);
}
else
{
hal_I2C_SDA(0);
}
I2C_delay(1);
hal_I2C_SCL(1);
I2C_delay(1);
temp<<=1;
}
hal_I2C_SCL(0);
I2C_delay(1);
hal_I2C_SDA(1);
I2C_delay(1);
}
⑦数据接收
static unsigned char I2C_ReceiveByte(void)
{
unsigned char i;
unsigned char ReceiveByte=0;
hal_I2C_SCL(0);
I2C_delay(1);
hal_I2C_SDA(1);
hal_I2C_SDA_IO_Set(1); //SDA设置成输入
/// 1010 0111
for(i=0; i<8; i++)
{ /// 0000 0000
ReceiveByte <<= 1;
I2C_delay(1);
hal_I2C_SCL(1);
I2C_delay(1);
if(hal_I2C_SDA_INPUT())
{ /// 00000100 |=0x01 1010 0111
ReceiveByte|=0x01;
}
hal_I2C_SCL(0);
}
hal_I2C_SDA_IO_Set(0); //SDA设置成输出
I2C_delay(1);
return ReceiveByte;
}
⑧读操作函数:
- AT24C128读操作时序图:
- 对应函数
//unsigned short address 读操作地址
//unsigned char *pBuffer 读取的数据通过指针保存获取
//unsigned short len 读取数据的长度
void I2C_Read(unsigned short address,unsigned char *pBuffer, unsigned short len)
{
unsigned short length;
length = len;
I2C_Start();
I2C_SendByte(0xA0);
I2C_WaitAck();
/// AT24C128的地址长度是2个字节;
I2C_SendByte((address>>8)&0xFF);
I2C_WaitAck();
I2C_SendByte(address&0xFF);
I2C_WaitAck();
I2C_Start();
I2C_SendByte(0xA1);
I2C_WaitAck();
//dat = I2C_ReceiveByte();
while(length)
{
*pBuffer = I2C_ReceiveByte();
if(length == 1)
I2C_NoAck();
else
I2C_Ack();
pBuffer++;
length–;
}
I2C_Stop();
}
关于EEPROM的写程序比较复杂,在这里就给大家不介绍了。本节课的任务是大家要能理解EEPROM的底层通讯协议,关于程序代码,大家需要通过实际的项目来实践;