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 #include #include #include #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"); }
上一篇:【PIC32MZ】USB HID通信
下一篇:【dsPIC33E】内部Flash读写
推荐阅读最新更新时间:2024-11-10 18:51
- 热门资源推荐
- 热门放大器推荐
设计资源 培训 开发板 精华推荐
- AM1G-0512SH30Z 12V 1 瓦 DC/DC 转换器的典型应用
- NSVC2030JBT3G 恒流单灯串典型应用
- 【立创开发板】基于梁山派的NES游戏机拓展板
- USB自定义按键 键盘鼠标游戏杆脚本
- LTC3897EUHF 高效两相 48V 升压转换器的典型应用电路,具有浪涌电流控制、输入电压浪涌保护和过流保护
- LT6654BHLS8-5、16 位 ADC 电压基准的典型应用
- 使用 NXP Semiconductors 的 MC9S08LL64CL 的参考设计
- 使用 Cypress Semiconductor 的 CY8C27143-24PI 的参考设计
- 具有 400mA 突发钳位、fSW = 1MHz 同步降压型稳压器的 LTC3621EDCB-3.3 2.5V Vout 的典型应用
- stm32点阵时钟控制板