(通信协议)PB00005-DFRobot I2C模块协议V1.0
来自DFRobot Product Wiki
目录 |
简述
为规范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; }