简述
为规范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位有效位的奇校验位,以实现本字节自身校验。
- 数据域(DATA):凡是从主设备到从设备的数据,称为输出数据,反之,则称为输入数据。
- 校验域(CHECK):将数据域中的所有数据相加,取其低8位。
包
- 寄存器写操作包:
- 寄存器读操作包(虚线框中的停止域可有可无,目前编者还不知如何在Arduino平台上实现不放弃总线控制权的前提下发送重复起始条件)
- 握手包:
- 异常反馈�
事务
- 一次完整的系统主设备对系统从设备进行写寄存器事务
寄存器写操作包 | + |
- 一次完整的系统主设备对系统从设备进行读寄存器事务
寄存器读操作包 | + |
- 一次完整的系统从设备异常反馈事务
(异常反馈包) |
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;
}