I2C的时序图,如下所示:
总线应当时序图:
I2C时序要求:
- 空闲状态
SCL和SDA都是处于高电平。 - 起始信号
在SCL时钟线为高电平期间,SDA输出下降沿。 - 停止信号
在SCL时钟线为高电平期间,SDA输出上升沿。 - 应答信号
发送器每发送一个字节,就在时钟SCL第9个脉冲释放数据线,由接收器反馈一个应答信号,有效电平为低电平,有效应答(ACK应答);为高电平时,无效应答(NACK应答)
模拟I2C总线的代码,如下:
1.初始化总线——空闲状态。
void init(void)
{
sda = 1;
delay();
scl = 1;
delay();
}
2.起始信号
void start(void)
{
sda = 1;
delay();
scl = 1;
delay();
sda = 0;
delay();
}
3.停止信号
void stop(void)
{
sda = 0;
delay();
scl = 1;
delay();
sda = 1;
delay();
}
4.等待应答信号
void ack(void)
{
uint8 time = 0;
scl = 1;
delay();
/* 等待SDA线是否为低 /
while ((sda == 1) && (time < 250))
time++;
sda = 0;
delay();
}
5.写一个字节数据
void write_one_byte(uint8 value)
{
uint8 i = temp = 0;
temp = value;
for (i = 0; i < 8; i++)
{
temp = temp << 1;
scl = 0; / 时钟为低时,允许SDA数据变化 /
delay();
sda = CY;
delay();
scl = 1; / 时钟为高时,SDA数据稳定 /
delay();
}
scl = 0;
delay();
sda = 1;/ 释放sda总线,由从设备应答 /
delay();
}
6.读一个字节数据
uint8 read_one_byte(void)
{
uint8 i = value = 0;
scl = 0;
delay();
sda = 1;
delay();
for (i = 0; i < 8; i++)
{
scl = 1;/ 上升沿时,把数据放在sda数据线上,在高电平期间稳定读取 */
delay();
value = (value << 1) | sda;
scl = 0;
delay();
}
return value;
}
7.向任意地址写一个字节数据
void write_addr_one_byte(uint8 addr, uint8 value)
{
start();//起始信号
write_one_byte(0xa0);//写从设备地址
ack();//等待应答
write_one_byte(addr);//写芯片地址
ack();//等待相应
write_one_byte(value);//写数据
ack();//等待相应
stop();//停止
}
8.向任意地址读一个字节数据
uint8 read_addr_one_byte(uint8 addr)
{
uint8 value = 0;
start();//起始信号
write_one_byte(0xa0);//写从设备地址
ack();//等待应答
write_one_byte(addr);//写芯片地址
ack();//等待相应
start();//起始信号
write_one_byte(0xa1);//写读操作
ack();//等待相应
value = read_one_byte();//读取数据
stop();//停止信号
return value;
}
以上便是I2C时序的代码实现。