找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4689|回复: 2
打印 上一主题 下一主题
收起左侧

单片机IIC通信时序的详细解释

[复制链接]
跳转到指定楼层
楼主
ID:135253 发表于 2018-8-16 17:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*---------------------------------------------------------------------
                         IIC.C文件  
  作者:xzf586                                创建日期:2018.8.16   
----------------------------------------------------------------------*/

#include <reg52.h>
#include <intrins.h>
#include"IIC.H"

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

/***********************************************************************
                                                IIC起始信号
时 序:     1        SDA SCL高电平期间,持续时间>4.7us(实际上是总线空闲)
                2        SDA下降沿后,持续时间>4us(线与,总线占用)
************************************************************************/
void I2CStart()
{
    I2C_SDA = 1;         //首先确保SDA、SCL都是高电平,总线空闲
    I2C_SCL = 1;
    NOP4
    I2C_SDA = 0;         //先拉低SDA
    NOP4                        //起始信号结束
        
    I2C_SCL = 0;         //再拉低SCL,为后续SDA数据变化做准备
}
/***********************************************************************
                                                IIC结束通信信号
时 序:     1        SCL高电平期间,持续时间>4.7us
                2        SDA上升沿后,持续时间>4.7us(总线释放)
************************************************************************/
void I2CStop()
{
    I2C_SDA = 0;
    I2C_SCL = 1; //先拉高SCL
    NOP4
    I2C_SDA = 1; //再拉高SDA,释放总线
    NOP4
}

/***********************************************************************
                                        IIC主机向从机写一个字节
时  序:    1        SCL=0;上面起始信号已准备好
                2        SDA=待传输位的值0或1
                3        等待一段时间,数据稳定
                4        SCL=1,此时SDA上数据不可以变化,因为从机要读取这个SDA值
                5         等待一段时间,从机读取这个SDA值
                6        SCL=0,进行下一次SDA数据变化,再传输出去
返回值        从机应答位的值
************************************************************************/
bit I2CWrite(unsigned char dat)
{
    bit ack;                                  //用于暂存应答位的值
    unsigned char temp;          //用于探测字节内某一位值的掩码变量

    for (temp=0x80; temp!=0; temp>>=1) //从高位到低位依次进行
    {
        if ((temp&dat) == 0) //该位的值输出到SDA上
            I2C_SDA = 0;
        else
            I2C_SDA = 1;
        NOP4
        I2C_SCL = 1;          //拉高SCL
        NOP4
        I2C_SCL = 0;         //再拉低SCL,完成一个位周期
    }                                                //8位数据发送完毕,
        
    I2C_SDA = 1;   //8位数据发送完后,主机释放SDA,以检测从机应答
    NOP4
    I2C_SCL = 1;   //拉高SCL,目的让主机读取应答值
    ack = I2C_SDA; //读取此时的SDA值,即为从机的应答值
    NOP4
    I2C_SCL = 0;   //再拉低SCL完成应答位,并保持住总线

    return (~ack); //应答值取反以符合通常的逻辑:
                   //0=不存在或忙或写入失败,1=存在且空闲或写入成功,注意ack取反
}

/***********************************************************************
                                主机从从机读取最后一个字节,发送非应答信号
时 序:    1        SDA=1;余下SDA信号由从机控制
                2        SCL=1;拉高SCL,此时SDA上已由从机写上一位0或1,主机开始读取
                3        等待一段时间,读取完毕
                4        SCL=0,拉低SCL,以使从机发送出下一位到SDA上
************************************************************************/
unsigned char I2CReadNAK()
{
    unsigned char temp;
    unsigned char dat;

    I2C_SDA = 1;  //首先确保主机释放SDA,即将SDA控制权交由从机
    for (temp=0x80; temp!=0; temp>>=1) //从高位到低位依次进行
    {
        NOP4
        I2C_SCL = 1;      //拉高SCL
        if(I2C_SDA == 0)  //读取SDA的值,此时SDA已由从机写上一位0或1,
            dat &= ~temp; //为0时,dat中对应位清零
        else
            dat |= temp;  //为1时,dat中对应位置1
        NOP4
        I2C_SCL = 0;      //再拉低SCL,以使从机发送出下一位
    }
        
    I2C_SDA = 1;   //从机8位数据发送完后,主机拉高SDA,发送非应答信号,这样从机将SDA控制权转交主机
    NOP4
    I2C_SCL = 1;   //拉高SCL,让从机读到这个1,知道停止向主机发送数据
    NOP4
    I2C_SCL = 0;   //再拉低SCL完成非应答位,并保持住总线,因为停止信号还没有发出,所以要保持总线

    return dat;
}

/***********************************************************************
                        主机从从机读取一个字节(非最后一个字节),发送应答信号
时 序:     1        SDA=1;余下SDA信号由从机控制
                2        SCL=1;拉高SCL,此时SDA上已由从机写上一位0或1,主机开始读取
                3        等待一段时间,读取完毕
                4        SCL=0,拉低SCL,以使从机发送出下一位到SDA上
************************************************************************/
unsigned char I2CReadACK()
{
    unsigned char temp;
    unsigned char dat;

    I2C_SDA = 1;                                                  //首先确保主机释放SDA
    for (temp=0x80; temp!=0; temp>>=1) //从高位到低位依次进行
    {
        NOP4
        I2C_SCL = 1;                                      //拉高SCL
        if(I2C_SDA == 0)                                  //读取SDA的值
            dat &= ~temp;                                 //为0时,dat中对应位清零
        else
            dat |= temp;                                  //为1时,dat中对应位置1
        NOP4
        I2C_SCL = 0;                                      //再拉低SCL,以使从机发送出下一位
    }
        
    I2C_SDA = 0;   //从机8位数据发送完后,主机拉低SDA,发送应答信号,SDA控制权仍然在从机手里
    NOP4
    I2C_SCL = 1;   //拉高SCL,让从机读到这个0,继续向主机发送数据
    NOP4
    I2C_SCL = 0;   //再拉低SCL完成应答位,并保持住总线,SDA由从机确定

    return dat;
}

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:58110 发表于 2018-8-17 06:21 | 只看该作者
谢谢分享!
后面若是有应用示例就更好了
回复

使用道具 举报

板凳
ID:414573 发表于 2020-11-3 07:33 | 只看该作者
从编程上看,是宋师傅的忠实粉丝,一起学了。有应用实例吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表