I2C通讯协议详解:SDA/SCL时序与数据传输机制
创作时间:
作者:
@小白创作中心
I2C通讯协议详解:SDA/SCL时序与数据传输机制
引用
CSDN
1.
https://blog.csdn.net/weixin_44006573/article/details/105674761
I2C(Inter-Integrated Circuit)总线是一种两线式串行通信总线,广泛应用于微控制器(MCU)与外围设备之间的数据传输。它采用一主多从的总线结构,通过SDA(串行数据线)和SCL(串行时钟线)实现数据的发送和接收。本文将详细介绍I2C总线的基本概念、时序规则以及具体实现方式。
一、基础介绍
I2C总线的主要功能是实现主机和从机之间的数据传输,其核心机制包括起始信号、终止信号、应答信号、读字节、写字节、数据读取和数据写入等。I2C总线的基本架构如下:
Start_I2C
Stop_I2C
readack 读取应答信号
sendack and sendnack 输出应答或非应答
sendbyte
readbyte
write_I2C
read_I2C
二、I2C通信协议详解
1. 空闲状态
SDA和SCL通过上拉电阻保持高电平,表示总线处于空闲状态。
2. 主从设备
- 主设备负责控制通信,通过初始化/终止化数据传输,发送数据并产生同步时钟脉冲。
- 从设备等待主设备的命令并响应,同步时钟信号只能由主设备产生。
3. 起始信号和结束信号
(1) I2C的起始位
void I2C_sendStart() //开始位
{
SDA=1; /*发送起始条件的数据信号*/
SCL=1;
SDA=0; /*发送起始信号*/
Delay_us(1);
SCL=0;
}
(2)I2C的结束位
Void sendstop()
{
SCL=0;
SDA=0; /*发送结束条件的数据信号*/
SCL=1;
while(SCL!=1) { };
Delay_us(1);
SDA=1; Delay_us(1);
}
4. 数据有效性
I2C总线在SCL的每个时钟脉冲期间传输一个数据位。数据线SDA上的数据必须在SCL为高电平时保持稳定,只有在SCL为低电平时,SDA的状态才能发生变化。从机地址发送完成后,可能会发送一些指令,然后开始传输数据,每个数据为8位,数据的字节数没有限制。
5. 应答信号
- 当SDA是低电平表示有效应答(ACK),表示接收成功。
- 当SDA是高电平表示无效应答(NACK),表示接收失败。
(1)接收数据需向发送方发送应答:
void IIC_ack(u8 ack)
{
// 数据线设置为输出
SCL = 0;
delay_us(5);
if(ack)
SDA = 1; // 无效应答
else
SDA = 0; // 有效应答
delay_us(5);
SCL = 1;
// 保持数据稳定
delay_us(5);
// 拉低SCL开始传输数据
SCL = 0;
}
(2)发送数据需等待接收方的应答:
// 等待ACK 1-无效 0-有效
u8 IIC_wait_ack(void)
{
u8 ack = 0;
// 数据线设置为输入
// 拉高时钟线
SCL = 1;
delay_us(5);
// 获取数据线的电平
if(SDA)
{ // 无效应答
ack = 1;
IIC_stop();
}
else
{ // 有效应答
ack = 0;
// 拉低SCL开始传输数据
SCL = 0;
delay_us(5);
}
return ack;
}
三、I2C通信实现方式
1. 硬件I2C
使用芯片上的I2C外设,有专用的I2C引脚,通过调用I2C的控制函数实现通信,无需手动控制SCL、SDA的电平变化。
2. 模拟I2C
通过软件控制任意IO口模拟I2C协议的时序,实现I2C信号和数据传输。
3. 数据读取和写入的示例
- Write_I2C:start->slave address+0+ACK+数据包(byte+ack+…+byten+Nack)+stop
- Read_I2C:start->slave address+1+ACK+数据包(byte+ack+…+byten+Nack)+stop
注意:slave address是7位的一个字节,write是0位,read是1位。
示例:
- slave address为50H(1010000)
- 写地址:10100000(A0)
- 读地址:10100001(A1)
具体流程:
- 发送开始条件
- 发送从机地址和读写控制位
- 传输数据及数据传输结束时
- 发送停止条件
4. 应用示例
(1)读取I2C的应答标志位
Unsigned char readACK() //读取应答信号
{
SCL=0;
SDA=1; /*此处为释放SDA 总线,由从从机发出低电平应答*/
_nop_();
SCL=1;
_nop_();
if(SDA)
return 1; //no ACK
else
return 0; //ACK
}
(2)主控端送出应答信号
void sendACK() //输出应答信号
{
SCL=0;
SDA=0;
_nop_();
SCL=1;
}
void sendNOACK() //输出无应答信号
{
SCL=0;
SDA=1;
_nop_();
SCL=1;
}
(3)主控端写入一个字节到从机
void sendByte(uchar dat) //写一个字节
{
uchar i;
for(i=0;i<8;i++)
{
SCL=0; /*钳住I2C 总线,准备发送数据 */
if(dat&0x80)
SDA=1;
else
SDA=0;
_nop_();
_nop_();
SCL=1;
dat<<=1;
}
}
(4)主控端对从机读取一个字节
uchar readByte() //读一个字节
{
uchar i, dat=0;
for(i=0;i<8;i++)
{
SCL=0;
SDA=1;
_nop_();
dat<<=1;
SCL=1;
if(SDA==1)
dat|=0x01;
}
return dat;
}
(5)主控端数据写入
bit writeIIC(uchar addrW, uchar *writeData, uchar length)
{
uchar i;
bit ACK;
sendStart();
sendByte(addrW); //传送地址与写入标记
ACK = readACK();
if (ACK)
{
sendStop(); //地址不正确或装置未连接,送出停止信号
return ACK;
}
for(i = 0; i<length; i++)
{
sendByte(writeData[i]);
ACK = readACK();
if (ACK)
{
sendStop(); //未接收到ACK,送出停止信号
return ACK;
}
}
sendStop(); //资料写入完成,送出停止信号
return ACK;
}
(6)主控端对从机数据读取
bit readIIC(uchar addrR, uchar *readData, uchar length)
{
uchar i;
bit ACK;
sendStart();
sendByte(addrR); //传送地址与读取标记
ACK = readACK();
if (ACK)
{
sendStop(); //地址不正确或装置未连接,送出停止信号
return ACK;
}
for(i = 0; i<length; i++)
{
readData[i] = readByte();
if(i<length-1)
sendACK();
else
sendNOACK(); //读取最后一笔资料,送出No ACK
}
sendStop(); //资料读取完成,送出停止信号
return ACK;
}
(7)调用数据写入和读取
writeIIC(address_W, &Write_Buffer,4);
readIIC(address_R, &Read_Buffer, 5);
热门推荐
可变数据软件是干什么的,探索可变数据软件:定义与应用
新能源车的三电系统,用到哪些特种工程塑料?一文看懂!
如何申诉医患纠纷:从纠纷申诉到医疗事故调解的完整指南
电脑键盘背光灯为何关机后还亮?
衡阳河边蓼花:一种常见的水边植物
中日俄离婚率对比断崖,日本 33%,俄罗斯 73%,中国呢?
马桶排水阀故障的处理方法 马桶排水阀的工作原理
坐便器冲水方式大揭秘:直冲式 vs 虹吸式,哪种更适合你?
增值税进项税额的会计处理
心肾不交的中医治疗方法有哪些
小区物业管理范围有哪些
什么是PD门?什么是PT门?不懂的就来看看
孕晚期因腰疼导致失眠如何处理
绝对值编码器如何接线及常见问题汇总
整流桥并联均流难题:多器件协同工作的黄金法则
碳青霉烯耐药细菌感染的挑战、策略和未来
甲鱼苗种的选择和投放有哪些注意事项
CDN如何处理动态请求
年利率的计算方法及其实际应用要点
陶瓷釉的原料及特性
计算机网络鉴别技术详解:原理、应用与发展趋势
超声心动图在左心室辅助装置中的应用
Vue.js生命周期详解:从创建到销毁的全过程
骨折手术后如何消肿散瘀?专业医生给出5个护理要点
滑动窗口:TCP的经典算法
《我独自升级 起立》背景故事介绍
集线器的作用与使用方法详解
胡雪岩后人现状揭秘:散落全球,各领风骚
如何理解除权价格的计算和意义?除权价格对股票投资的影响有哪些?
医院定点怎么定