【PIC32MZ】I2C通信

版权声明:本文为博主原创文章,转载注明出处 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");
}


猜你喜欢

转载自blog.csdn.net/u010875635/article/details/70170186