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);
热门推荐
国产车与合资车对比:传统燃油车存差距,新能源领域现突破
绩效考核的5个指标
虚假宣传导致买卖合同纠纷:消费者权益受损如何维权?
三文鱼能否生食?须看准“可生食”和GB10136标签
命局两个禄神代表什么
全球各地红茶口感对比:哪个地区的红茶最美味?
鞋类知识:用什么材料做鞋垫缓冲缓震性能比较好?
探索光耦:光耦在开关电源中的应用——保障高效、安全的电源控制
探索“銮”字的读音、用法及其背后深厚的文化内涵与历史意义
【康复科普】中枢性面瘫 VS 周围性面瘫
《最后纪元》物品系统详解:从基础词缀到传奇装备
Git 基本操作入门指南
【高等数学(上)】期末3小时通关!考点公式全面梳理+考试锦囊(上集)
如何提高孩子的阅读理解能力?这5个核心技巧,家长请收好!
抖音疯狂刷屏的“奶龙”,给我整不会了
为什么国产纯电动汽车的保值率较低
城乡居民养老保险参保指南:条件、缴费标准及转移接续政策详解
北京十大特色早餐:从豆汁儿到驴打滚,品味最地道的京城味道
低空经济探索,无人机春季研学活动详解
用Excel计算树木二元材积的完整指南
如何借助别人的团队做事
八字命盘:中国传统命理学中的命运预测工具
美味可口的家常蹄花做法大揭秘
高频功能大盘点!交管12123"网上办"快快用起来 | 便民服务
严防小火酿大祸!清明前后怎么严防森林火灾?
《黄石溪组诗》赏析
如何衡量两个「任意数据集」间的相似度
提高自信表达能力之六——呼吸技巧
吃生姜要不要去皮?原来还分这几种情况,好处出乎意料
建筑企业的市场营销策略有哪些独特之处?