51单片机——I2C总线

单片机——I2C


宗旨:技术的学习是有限的,分享的精神是无限的。


        UART 属于异步通信,比如电脑发送给单片机,电脑只负责把数据通过TXD 发送出来即可,接收数据是单片机自己的事情。而 I2C 属于同步通信, SCL 时钟线负责收发双方的时钟节拍, SDA 数据线负责传输数据。 I2C 的发送方和接收方都以 SCL 这个时钟节拍为基准进行数据的发送和接收。

        I2C总线包括SCL,SDA 两根信号线,其中SCL是时钟线,SDA是数据线。


1、起始信号

        UART 通信是从一直持续的高电平出现一个低电平标志起始位;而 I2C 通信的起始信号的定义是 SCL 为高电平期间, SDA 由高电平向低电平变化产生一个下降沿,表示起始信号。

 

2、数据传输

       UART 是低位在前,高位在后;而 I2C 通信是高位在前,低位在后。UART 通信数据位是固定长度,波特率分之一,一位一位固定时间发送完毕就可以了。而 I2C 没有固定波特率,但是有时序的要求,要求当 SCL 在低电平的时候, SDA 允许变化。

 

3、停止信号

        UART 通信的停止位是一位固定的高电平信号; 而 I2C 通信停止信号的定义是 SCL 为高电平期间, SDA 由低电平向高电平变化产生一个上升沿,表示结束信号。

 

4、写完从器件之后等待从器件的应答

         在主器件完成对从器件的写操作时候(每次会有一个字节的数据),主器件会等待从器件发送指示信号,这个指示信号是说从器件已经接受到了主器件的数据,这是由从器件的硬件来完成的,不需要主器件来软件操作,只需要等待;

 

5、主器件读完数据后向从器件发送应答信号

         这其实包括两种情况,一种是主器件读完后还要继续读就要发送一个继续读的信号(其实就是发送0),另一种就是不再继续读了,就要发送停止读信号(其实就是发送1)。

 

6I2C寻址模式

        I2C 通信的起始信号(Start)后,首先要发送一个从机的地址,这个地址一共有 7位,紧跟着的第 8 位是数据方向位(R/W),“ 0”表示接下来要发送数据(写),‘“ 1”表示接下来是请求数据(读)。第九位 ACK应答。 

#include<reg52.h>
#include<intrins.h>

#define I2CDelay()  {_nop_();_nop_();_nop_();_nop_();}
sbit I2C_SCL = P3 ^ 7;
sbit I2C_SDA = P3 ^ 6;

/* 产生总线起始信号 */
void I2CStart()
{
  I2C_SDA = 1; //首先确保SDA、SCL都是高电平
  I2C_SCL = 1;
  I2CDelay();
  I2C_SDA = 0; //先拉低SDA
  I2CDelay();
  I2C_SCL = 0; //再拉低SCL
}
/* 产生总线停止信号 */
void I2CStop()
{
  I2C_SCL = 0; //首先确保SDA、SCL都是低电平
  I2C_SDA = 0;
  I2CDelay();
  I2C_SCL = 1; //先拉高SCL
  I2CDelay();
  I2C_SDA = 1; //再拉高SDA
  I2CDelay();
}
/* I2C总线写操作,dat-待写入字节,返回值-从机应答位的值 */
bit I2CWrite(unsigned char dat)
{
  bit ack; //用于暂存应答位的值
  unsigned char mask;  //用于探测字节内某一位值的掩码变量

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

  return (~ack); //应答值取反以符合通常的逻辑:
  //0=不存在或忙或写入失败,1=存在且空闲或写入成功
}
/* I2C总线读操作,并发送非应答信号,返回值-读到的字节 */
unsigned char I2CReadNAK()
{
  unsigned char mask;
  unsigned char dat;

  I2C_SDA = 1;  //首先确保主机释放SDA
  for (mask = 0x80; mask != 0; mask >>= 1) //从高位到低位依次进行
  {
    I2CDelay();
    I2C_SCL = 1;      //拉高SCL
    if(I2C_SDA == 0)  //读取SDA的值
    {
      dat &= ~mask;  //为0时,dat中对应位清零
    }
    else
    {
      dat |= mask;  //为1时,dat中对应位置1
    }
    I2CDelay();
    I2C_SCL = 0;      //再拉低SCL,以使从机发送出下一位
  }
  I2C_SDA = 1;   //8位数据发送完后,拉高SDA,发送非应答信号
  I2CDelay();
  I2C_SCL = 1;   //拉高SCL
  I2CDelay();
  I2C_SCL = 0;   //再拉低SCL完成非应答位,并保持住总线

  return dat;
}
/* I2C总线读操作,并发送应答信号,返回值-读到的字节 */
unsigned char I2CReadACK()
{
  unsigned char mask;
  unsigned char dat;

  I2C_SDA = 1;  //首先确保主机释放SDA
  for (mask = 0x80; mask != 0; mask >>= 1) //从高位到低位依次进行
  {
    I2CDelay();
    I2C_SCL = 1;      //拉高SCL
    if(I2C_SDA == 0)  //读取SDA的值
    {
      dat &= ~mask;  //为0时,dat中对应位清零
    }
    else
    {
      dat |= mask;  //为1时,dat中对应位置1
    }
    I2CDelay();
    I2C_SCL = 0;      //再拉低SCL,以使从机发送出下一位
  }
  I2C_SDA = 0;   //8位数据发送完后,拉低SDA,发送应答信号
  I2CDelay();
  I2C_SCL = 1;   //拉高SCL
  I2CDelay();
  I2C_SCL = 0;   //再拉低SCL完成应答位,并保持住总线

  return dat;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值