版权声明:本文为博主原创文章,转载注明出处 https://blog.csdn.net/u010875635/article/details/70170186
I2C跟串口一样,仅需2根线通讯即可,在某些引脚紧张的应用中非常有用,不过I2C相比于串口,通讯协议更简单一点,距离也更短一些,仅限于板间通信。大多数IC都支持I2C协议。
I2C的时序图为:
I2C数据传输是在起始条件和停止条件之间。
起始条件和停止条件都是SCL为高一段时间产生。起始条件为SDA从高变为低,停止条件为SDA从低变为高。
I2C数据传输规则为,第一字节必须为地址,一般器件地址都是7位(也有10位的),放在高7位,最后一位时读写标识,所以,读写地址是不相同的,并且很多IC都可以配置多个地址选择,这是为了在一组I2C上接多个IC,因为I2C是通过地址来识别从机的。
每传输一个字节,从机都要回复一个ACK来表示是否完成接受,回复0继续接受,回复1停止接受。
I2C写操作很简单,传输从机地址以及数据即可。
I2C读也是一样,传输从机地址即可。
写操作:
一般而言,写操作要配合DataSheet,有写命令的操作,写数据的操作。
例如一般的OLED就有写命令和写数据两种操作,做法是,写地址命令/数据
标识 一个字节或多个字节命令信息。
标识 一个字节或多个字节命令信息。
一般EEPROM的写操作为:写地址需要写入的EEPROM内部起始地址(1字节或多字节) 1字节或多字节信息(从起始地址开始写入1个字节或者多个字节信息)
读操作:
以读EEPROM为例,需要两步:一是写入需要读的地址,写地址需要读的EEPROM内部起始地址(1字节或多字节);二是读地址。读取长度由主机ASK信号来控制,当主机不想继续读取时,ACK回复1。
使用流程如下:
1、配置驱动
2、配置引脚
3、生成代码,使用I2C
以下为实际封装的函数文件,在app.c或者其它文件中包含再调用即可。
首先要initial(open一个客户端),然后才能读写。
delay函数
#ifndef _DELAY_H
#define _DELAY_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "system_config.h"
#include "system_definitions.h"
void delay_ms(uint32_t milliSeconds)
{
uint32_t frequencyHz = milliSeconds * (SYS_CLK_SystemFrequencyGet()/2000); //while occupy 2 period
while(frequencyHz--);
}
void delay_us(uint32_t microSeconds)
{
uint32_t frequencyHz = microSeconds * (SYS_CLK_SystemFrequencyGet()/2000000); //while occupy 2 period
while(frequencyHz--);
}
#endif
I2C-Hardware.h
#ifndef _I2C_HARDWARE_H
#define _I2C_HARDWARE_H
#include "delay.h"
typedef struct
{
DRV_HANDLE i2c_drvHandle;
DRV_I2C_BUFFER_HANDLE i2c_bufferHandle;
}IIC_DATA;
IIC_DATA i2cData;
bool IIC_Initial(void);
bool IIC_WriteByte(uint8_t slaveAddr, uint8_t IIC_Byte);
bool IIC_WriteBytes(uint8_t slaveAddr, uint8_t *IIC_Bytes, uint8_t length);
bool IIC_ReadBytes(uint8_t slaveAddr, uint8_t *IIC_Bytes, uint8_t readLength);
#endif
i2c-Hardware.c
#include "i2c-hardware.h"
bool IIC_Initial(void)
{
i2cData.i2c_drvHandle = DRV_I2C_Open(0,DRV_IO_INTENT_READWRITE);
if(i2cData.i2c_drvHandle==NULL)
return false;
else
return true;
}
DRV_I2C_BUFFER_EVENT IIC_Check_Transfer_Status(DRV_HANDLE drvOpenHandle, DRV_I2C_BUFFER_HANDLE drvBufferHandle)
{
return (DRV_I2C_TransferStatusGet (drvOpenHandle, drvBufferHandle));
}
bool IIC_WriteByte(uint8_t slaveAddr, uint8_t IIC_Byte)
{
uint8_t tmp[] = {IIC_Byte};
if ( (i2cData.i2c_bufferHandle == (DRV_I2C_BUFFER_HANDLE) NULL) ||
(IIC_Check_Transfer_Status(i2cData.i2c_drvHandle, i2cData.i2c_bufferHandle) == DRV_I2C_BUFFER_EVENT_COMPLETE) ||
(IIC_Check_Transfer_Status(i2cData.i2c_drvHandle, i2cData.i2c_bufferHandle) == DRV_I2C_BUFFER_EVENT_ERROR) )
{
i2cData.i2c_bufferHandle = DRV_I2C_Transmit(i2cData.i2c_drvHandle,slaveAddr,tmp,1,NULL);
delay_ms(1);
return true;
}
else
return false;
}
bool IIC_WriteBytes(uint8_t slaveAddr, uint8_t *IIC_Bytes, uint8_t length)
{
if ( (i2cData.i2c_bufferHandle == (DRV_I2C_BUFFER_HANDLE) NULL) ||
(IIC_Check_Transfer_Status(i2cData.i2c_drvHandle, i2cData.i2c_bufferHandle) == DRV_I2C_BUFFER_EVENT_COMPLETE) ||
(IIC_Check_Transfer_Status(i2cData.i2c_drvHandle, i2cData.i2c_bufferHandle) == DRV_I2C_BUFFER_EVENT_ERROR) )
{
i2cData.i2c_bufferHandle = DRV_I2C_Transmit(i2cData.i2c_drvHandle,slaveAddr,IIC_Bytes,length,NULL);
delay_ms(1);
return true;
}
else
return false;
}
bool IIC_ReadBytes(uint8_t slaveAddr, uint8_t *IIC_Bytes, uint8_t readLength)
{
if ( (i2cData.i2c_bufferHandle == (DRV_I2C_BUFFER_HANDLE) NULL) ||
(IIC_Check_Transfer_Status(i2cData.i2c_drvHandle, i2cData.i2c_bufferHandle) == DRV_I2C_BUFFER_EVENT_COMPLETE) ||
(IIC_Check_Transfer_Status(i2cData.i2c_drvHandle, i2cData.i2c_bufferHandle) == DRV_I2C_BUFFER_EVENT_ERROR) )
{
i2cData.i2c_bufferHandle = DRV_I2C_Receive(i2cData.i2c_drvHandle,
slaveAddr,
IIC_Bytes, readLength, NULL);
delay_ms(1);
return true;
}
else
return false;
}
注意:
I2C不连接Device时,会导致没收到回应而卡死在system_interrupt.c的error_instancex里面,这是到2.03版本harmony的bug,可以自行仿照下面方式添加函数来避免,注意intance与i2c通路的对应,这里是intance0-instance4对应i2c1-i2c5
void __ISR(_I2C1_MASTER_VECTOR, ipl1AUTO) _IntHandlerDrvI2CMasterInstance0(void)
{
DRV_I2C_Tasks(sysObj.drvI2C0);
}
void __ISR(_I2C1_BUS_VECTOR, ipl1AUTO) _IntHandlerDrvI2CErrorInstance0(void)
{
PLIB_INT_SourceFlagClear( INT_ID_0, INT_VECTOR_I2C1_BUS );
PLIB_I2C_Disable (I2C_ID_1);
PLIB_I2C_Enable (I2C_ID_1);
SYS_ASSERT(false, "I2C Driver Instance 0 Error");
}
void __ISR(_I2C2_MASTER_VECTOR, ipl1AUTO) _IntHandlerDrvI2CMasterInstance1(void)
{
DRV_I2C_Tasks(sysObj.drvI2C1);
}
void __ISR(_I2C2_BUS_VECTOR, ipl1AUTO) _IntHandlerDrvI2CErrorInstance1(void)
{
PLIB_INT_SourceFlagClear( INT_ID_0, INT_VECTOR_I2C2_BUS );
PLIB_I2C_Disable (I2C_ID_2);
PLIB_I2C_Enable (I2C_ID_2);
SYS_ASSERT(false, "I2C Driver Instance 1 Error");
}
void __ISR(_I2C3_MASTER_VECTOR, ipl1AUTO) _IntHandlerDrvI2CMasterInstance2(void)
{
DRV_I2C_Tasks(sysObj.drvI2C2);
}
void __ISR(_I2C3_BUS_VECTOR, ipl1AUTO) _IntHandlerDrvI2CErrorInstance2(void)
{
PLIB_INT_SourceFlagClear( INT_ID_0, INT_VECTOR_I2C3_BUS );
PLIB_I2C_Disable (I2C_ID_3);
PLIB_I2C_Enable (I2C_ID_3);
SYS_ASSERT(false, "I2C Driver Instance 2 Error");
}
void __ISR(_I2C4_MASTER_VECTOR, ipl1AUTO) _IntHandlerDrvI2CMasterInstance3(void)
{
DRV_I2C_Tasks(sysObj.drvI2C3);
}
void __ISR(_I2C4_BUS_VECTOR, ipl1AUTO) _IntHandlerDrvI2CErrorInstance3(void)
{
PLIB_INT_SourceFlagClear( INT_ID_0, INT_VECTOR_I2C4_BUS );
PLIB_I2C_Disable (I2C_ID_4);
PLIB_I2C_Enable (I2C_ID_4);
SYS_ASSERT(false, "I2C Driver Instance 3 Error");
}
void __ISR(_I2C5_MASTER_VECTOR, ipl1AUTO) _IntHandlerDrvI2CMasterInstance4(void)
{
DRV_I2C_Tasks(sysObj.drvI2C4);
}
void __ISR(_I2C5_BUS_VECTOR, ipl1AUTO) _IntHandlerDrvI2CErrorInstance4(void)
{
PLIB_INT_SourceFlagClear( INT_ID_0, INT_VECTOR_I2C5_BUS );
PLIB_I2C_Disable (I2C_ID_5);
PLIB_I2C_Enable (I2C_ID_5);
SYS_ASSERT(false, "I2C Driver Instance 4 Error");
}