(通信协议)PB00005-DFRobot I2C模块协议V1.0

简述

  • 为规范DFRobot I2C产品线的通信方式,将I2C总线中的主控制器称为系统主设备,其余均称为系统从设备,注意与I2C通信时主从的区别。
  • 不论在I2C通讯中,以什么身份出现在总线上,从系统主设备到系统从设备的数据传输,均称为输出,反之,则称为输入。
  • 本文将一个完整的I2C通讯称为一个事务,事务由一个或多个包构成,而每个包又由域构成。

约定

  • S : I2C起始信号
  • P : I2C停止信号
  • A : I2C确认信号
  • NA : I2C非确认信号
  • W : I2C写控制位
  • R : I2C读控制位
  • SSA : 系统从设备地址(1-126)
  • SMA :系统主设备地址(固定为127)
  • RSA : 寄存器起始地址(0-99)
  • ODD : 奇校验位
  • DI_x : 输入数据
  • DO_x : 输出数据
  • MCSDO : 系统主设备对输出数据的校验和
  • SCSDO : 系统从设备对输出数据的校验和
  • SCSDI : 系统从设备对输入数据的校验和
  • SH : 系统从设备状态高字节(每个模块最多可定义16个状态)
  • SL : 系统从设备状态低字节

协议内容

  • 起始域 :I2C 起始信号
  • 应答域 :ACK或NACK
  • 停止域 :I2C停止信号
  • 地址域(SSA+W/R) :7位从设备地址加上读或写控制位。所有I2C的有效通讯事务,皆由地址域开始。
  • 标识域(PID) :标识域中高7位为有效位,最低位为7位有效位的奇校验位,以实现本字节自身校验。

DFI2C-V10-1.jpg

  • 数据域(DATA):凡是从主设备到从设备的数据,称为输出数据,反之,则称为输入数据。
  • 校验域(CHECK):将数据域中的所有数据相加,取其低8位。

  • 寄存器写操作包:

DFI2C-V10-Write.jpg

  • 寄存器读操作包(虚线框中的停止域可有可无,目前编者还不知如何在Arduino平台上实现不放弃总线控制权的前提下发送重复起始条件)

DFI2C-V10-Read.jpg

  • 握手包:

DFI2C-V10-Hand.jpg

  • 异常反馈包

DFI2C-V10-Error.jpg

事务

  • 一次完整的系统主设备对系统从设备进行写寄存器事务
寄存器写操作包 + 握手包
  • 一次完整的系统主设备对系统从设备进行读寄存器事务
寄存器读操作包 + 握手包
  • 一次完整的系统从设备异常反馈事务
(异常反馈包)

Arduino 库
简述

使用该库,只需在实例化对象时,指定数据缓冲区的首地址和大小,注意缓冲区的大小应比实际寄存器数多1。

  • 写寄存器过程

只要将待发送的数据写入用户定义的数据缓冲区中,然后调用Write方法,指定系统从设备地址、用户寄存器起始地址和连续操作的寄存器数,即可。若调用该方法返回0,说明写操作成功,反之,操作失败。

  • 读寄存器过程

调用Read方法,指定系统从设备地址、用户寄存器起始地址和连续操作的寄存器数,即可。若调用该方法返回0,说明读操作成功,反之,操作失败。当操作成功时,用户即可从自己定义的缓冲区中,从首地址开始读取相应字节数的数据。

DFI2C_V10.h
#ifndef _DFI2C_V10_H
#define _DFI2C_V10_H

#define DFI2C_PID_HAND    0x7e
#define DFI2C_PID_ERROR   0x7f
#define DFI2C_SYS_MASTER  127

class DFI2CV10
{
  private:
    unsigned char *BufStartAddr;
    unsigned char BufSize;
    unsigned char Front;
    unsigned char Rear; 
    unsigned char GeneratePID(unsigned char PID);
    unsigned char CheckPID(unsigned char PID);
   
  public:
    DFI2CV10(unsigned char *BufAddr,unsigned char Num);
    unsigned char Write(unsigned char SSA,unsigned char RegAddr,unsigned char Num);
    unsigned char Read(unsigned char SSA,unsigned char RegAddr,unsigned char Num);
    unsigned char DetectError(void);
};

#endif

DFI2C_V10.c

#include "DFI2C_V10.h"
#include <Wire.h>

unsigned char Error[5];

/*DFI2C系统主设备接收到系统从设备发来的异常包*/
void DFI2CV10_ReceiveEvent(int Num)
{
  unsigned char i;
  for(i=0;i<Num;i++)
  {
    if(Num<=sizeof(Error))
      Error[i]=Wire.read();
  }
}

/*构造函数*/
DFI2CV10::DFI2CV10(unsigned char *BufAddr,unsigned char Num)
{
  Wire.begin(DFI2C_SYS_MASTER); 
  Wire.onReceive(DFI2CV10_ReceiveEvent);
  this->BufStartAddr=BufAddr;
  this->BufSize=Num;
}

/*生成PID*/
unsigned char DFI2CV10::GeneratePID(unsigned char PID)
{
  unsigned char count=0,temp=PID;
  while(temp)
  {
    temp&=(temp-1);
    count++;
  }
  if(count%2)
    return (PID<<1);
  else
    return ((PID<<1)+1);
}

/*校验PID*/
unsigned char DFI2CV10::CheckPID(unsigned char PID)
{
  unsigned char count=0,temp=PID;
  while(temp)
  {
    temp&=(temp-1);
    count++;
  }
  if(count%2)
    return PID;
  else 
    return 0xff;
}

/*写寄存器操作,SSA-模块地址,RegAddr-寄存器起始地址,Num-连续操作的字节数*/
unsigned char DFI2CV10::Write(unsigned char SSA,unsigned char RegAddr,unsigned char Num)
{
  unsigned char i,temp,check=0;
  
  //写寄存器PID+Data+Check
  Wire.beginTransmission(SSA);
  Wire.write(this->GeneratePID(RegAddr));
  for(i=0;i<Num;i++)
  {
    temp=*(this->BufStartAddr+i);
    Wire.write(temp);
    check+=temp;
  }
  Wire.write(check);
  Wire.endTransmission();
  
  //写握手PID   
  Wire.beginTransmission(SSA);
  Wire.write(this->GeneratePID(DFI2C_PID_HAND));
  Wire.endTransmission();
  
  //读校验字节
  Wire.requestFrom((int)SSA,1,true);
  if(Wire.read()==check)
    return 0;
  else
    return 0xff;
} 

/*读寄存器操作,SSA-模块地址,RegAddr-寄存器起始地址,Num-连续操作的字节数*/
unsigned char DFI2CV10::Read(unsigned char SSA,unsigned char RegAddr,unsigned char Num)
{
  unsigned char temp,check=0;
  
  //写寄存器PID
  Wire.beginTransmission(SSA);
  Wire.write(this->GeneratePID(RegAddr));
  Wire.endTransmission();
  
  //读寄存器Data
  Wire.requestFrom((int)SSA,(int)Num,true);
  this->Front=0;
  this->Rear=0;
  while(Wire.available())
  { 
    temp=Wire.read();
    check+=temp;
    //允许覆盖
    *(this->BufStartAddr+this->Rear)=temp;
    this->Rear=(this->Rear+1)%this->BufSize;
  }
  
  //写握手PID   
  Wire.beginTransmission(SSA);
  Wire.write(this->GeneratePID(DFI2C_PID_HAND));
  Wire.endTransmission();
  
  //读校验字节
  Wire.requestFrom((int)SSA,1,true);
  if(Wire.read()==check)
  {
    if((this->Rear+this->BufSize-this->Front)%this->BufSize==Num)
      return 0;
    else 
      return 0xff;
  }
  return 0xff;
}

/*异常检测,若收到正确的异常包,则返回0,否则返回0xff*/
unsigned char DFI2CV10::DetectError(void)
{
  if(Error[0]==this->GeneratePID(DFI2C_PID_ERROR))
  {
    if(Error[1]!=0)
    {
      if(Error[4]=Error[1]+Error[2]+Error[3])
        return 0;
    }
  }
  return 0xff;
}

标签: Arduino传感器