初学51单片机中的I2C

本文详细解析了I2C通信的时序流程图,包括起始信号、停止信号的发送方法,以及写数据和读操作的代码实现,还涵盖了寻址过程。通过代码示例展示了如何控制SDA和SCL线以完成I2C通信的各个步骤。
摘要由CSDN通过智能技术生成

一、I2C的时序流程图

图1 I2C的时序流程图

二、代码分析

*以下延时,需要头文件 “ #include<intrins.h> ”

#define I2CDelay() {_nop_();_nop_();_nop_();_nop_();}

1、I2C总线_起始信号[ void I2CStart() ]

*起始条件:在SCL线是高电平时,SDA线从高电平向低电平切换,这个情况表示起始条件。

         第一步,确保SDA总线与SCL总线为高电平。         
I2C_SDA = 1;              //确保SDA总线与SCL总线为高电平
I2C_SCl = 1;
        第二步,延时,确保总线稳定后,将SDA线从高电平向低电平切换。
I2CDelay();                //延时
I2C_SDA = 0;               //先拉低SDA
        第三步,延时,确保总线稳定后,将SCL线从高电平向低电平切换(SCL拉低,准备接收信号)。
I2CDelay();                //延时
I2C_SCL = 0;               //拉低SCL

2、I2C总线_停止信号[ void I2CStop() ]

*当SCL线是高电平时,SDA线由低电平向高电平切换,这个情况表示停止条件

        第一步,确保SDA总线与SCL总线为低电平。
I2C_SDA = 0;                //确保SDA与SCL总线为低电平
I2C_SCL = 0;
        第二步,延时,确保总线稳定后,将SCL线由低电平向高电平切换。
I2CDelay();                //延时
I2C_SCL = 1;               //先拉高SCL
        第三步,延时,确保总线稳定,将SDA线由低电平向高电平切换,再延时。
I2CDelay();                //延时
I2C_SCL = 1;               //拉高SDA
I2CDelay();

3、I2C总线_写数据 [ bit I2CWrite(unsigned char dat) ]

bit ack;                //用于暂存应答位的值
unsigned char mask;     //用于探测字节内某一个值的掩码变量
        第一步 ,将数据的值输出到SDA上。
for(mask = 0x80; mask != 0; mask >>= 1)  //mask用于探测字节内某一位值的掩码变量,从高到低进行
{
    if((mask & dat) == 0)                //dat传入的字节,该位的值输出到SDA上
        I2C_SDA = 0;
    else
        I2C_SDA = 1;
    I2CDelay();                          //延时
    I2C_SCL = 1;                         //拉高SCL,等待该位的值传输
    I2CDelay();                          //延时
    I2C_SCL = 0;                         //拉低SCL,完成一个位周期
}
      第二步,主机释放SDA,以检测从机应答。

·       * 有响应的时钟脉冲期间,发送器释放SDA线(高电平)  ——I2C总线规范基础(二、响应) 

I2C_SDA = 1;            //主机释放SDA
    ·第三步,读取从机的应答值。
I2CDelay();                 //延时
I2C_SCL = 1;                //拉高SCL
ack = I2C_SDA;              //读取此时的SDA值,即为从机的应答值
I2CDelay();                 //延时
I2C_SCL = 0;                //再拉低SCL完成应答,并保持信总线
        第四步,返回从机应答值(从机回复应答,ack为‘0’)。
return ask;            //返回从机应答值

4、I2C总线_读操作

unsigned char mask;           //用于探测字节内某一位值的掩码变量
unsigned char dat;            //用于暂存读到的字节
        第一步,确保主机释放SDA。
I2C_SDA = 1;            //确保主机释放SDA
        第二步,读取SDA的值。
for(mask = 0x80; mask != 0; mask >>= 1)    //mask用于探测字节内某一位值的掩码变量,从高到低进行            
{
    I2CDelay();                    //延时
    I2C_SCL = 1;                   //拉高SCL,准备读此时SDA的值
    if(I2C_SDA == 0)               //读取SDA的值
        dat &= ~mask;              //SDA的值为0时,dat中对应位清零
    else
        dat |= mask;               //SDA的值为1时,dat中对应位置1
    I2CDelay();                    //延时
    I2C_SCL = 0;                   //再拉低SCL,以使从机发送出下一位
}

         第三步,应答信号处理
        4.1、并发送非应答信号,返回值为读到的字节[ unsigned char I2CReadNAK() ]。

                *8位数据发送完成后,拉高SDA,发送非应答信号,并保持住总线。      

I2C_SDA = 1;                //8位数据发送完成后,拉高SDA,发送非应答信号
I2CDelay();                 //延时
I2C_SCL = 1;                //拉高SCL
I2CDelay();                 //延时
I2C_SCL = 0;                //再拉低SCL完成非应答位,并保持住总线
        4.2、并发送应答信号,返回值为读到的字节[ unsigned char I2CReadACK() ]。

               * 8位数据发送完成后,拉低SDA,发送应答信号,并保持住总线。

I2C_SDA = 0;                //8位数据发送完成后,拉低SDA,发送应答信号
I2CDelay();                 //延时
I2C_SCL = 1;                //拉高SCL
I2CDelay();                 //延时
I2C_SCL = 0;                //再拉低SCL完成非应答位,并保持住总线
        第四步,返回读到的字节
return dat;                //返回读到的字节

5、I2C寻址[ bit I2CAddressing(unsigned char addr) ]

bit I2CAddressing(unsigned char addr)
{
    bit ack;                             //用于暂存应答位的值   
    
    I2CStart();                          //产生起始信号,即启动一次总线操作
    ack = I2CWrite(addr << 1);           //器件地址需左移一位,因寻址命令的最低位为读写位
    I2CStop();                           //不需要进行后续读写,而直接停止本次总线操作

    return ack;
}

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值