STM32 软件IIC接口,支持虚拟多个IIC接口

STM32 软件IIC接口,支持虚拟多个IIC接口,需要自己对底层进行移植,比如IO口时钟使能,初始化,写1,写0,读取进行移植,移植到自己的硬件平台。

//2020-02-19:更新,增加寄存器读写操作

//SoftwareIIC.c

/*************************************************************************************************************
 * 文件名:			SoftwareIIC.c
 * 功能:			STM32 软件IIC接口
 * 作者:			cp1300@139.com
 * 创建时间:		2017-07-10
 * 最后修改时间:	2017-11-20
 * 详细:			软件IIC接口
					2017-11-20:移植到STM32F4
					2020-02-09:增加更多的IO口支持
					2020-02-16:修改输出为开漏输出,用于兼容WM8994(必须开漏输出);增加通用的寄存器读写函数支持;
*************************************************************************************************************/
#include "system.h"
#include "SoftwareIIC.h"

//调试宏开关
#define SIIC_DBUG	1
#if SIIC_DBUG
	#include "system.h"
	#define SIIC_Debug(format,...)	uart_printf(format,##__VA_ARGS__)
#else
	#define SIIC_Debug(format,...)	/\
/
#endif	//SIIC_DBUG



//相关底层操作接口
#define SIIC_DelayUS(x)				Delay_US(x)									//延时US
#define SDA_OUT_MODE(GPIOx,bit)		SYS_GPIOx_OneInit(GPIOx,bit,OUT_OD_OPU,SPEED_25M)	//SDA输出模式
#define SDA_IN_MODE(GPIOx,bit)		SYS_GPIOx_OneInit(GPIOx,bit,IN_IPU,IN_NONE)		//SDA输入模式
#define SCL_OUT_MODE(GPIOx,bit)		SYS_GPIOx_OneInit(GPIOx,bit,OUT_OD_OPU,SPEED_25M)	//SCL输出模式
#define SDA_OUT_H(GPIOx,bit)		(GPIOx->ODR|=(1<<bit))						//SDA输出高电平
#define SDA_OUT_L(GPIOx,bit)		(GPIOx->ODR&=~(1<<bit))						//SDA输出低电平
#define SCL_OUT_H(GPIOx,bit)		(GPIOx->ODR|=(1<<bit))						//SCL输出高电平
#define SCL_OUT_L(GPIOx,bit)		(GPIOx->ODR&=~(1<<bit))						//SCL输出低电平
#define SDA_IN(GPIOx,bit)			((GPIOx->IDR&(1<<bit))?1:0)					//SDA输入





/*************************************************************************************************************************
*函数        	:	bool SIIC_Init(SIIC_HANDLE *pHandle, GPIO_TypeDef *SDA_GPIOx, GPIO_TypeDef *SCL_GPIOx,u8 SDA_GPIO_BITx, u8 SCL_GPIO_BITx,u8 DelayUS)
*功能        	:	软件IIC初始化
*参数        	:	pHandle:句柄;SDA_GPIOx:SDA IO;SCL_GPIOx:SCL GPIO;SDA_GPIO_BITx:SDA IO位数;SCL_GPIO_BITx:SCL IO位数;DelayUS:通信延时,单位us(1-100us)
*返回        	:	TRUE:初始化成功;FALSE:初始化失败
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2017-07-10
*说明        	:	2020-02-09:增加更多的IO口支持
*************************************************************************************************************************/
bool SIIC_Init(SIIC_HANDLE *pHandle, GPIO_TypeDef *SDA_GPIOx, GPIO_TypeDef *SCL_GPIOx,u8 SDA_GPIO_BITx, u8 SCL_GPIO_BITx,u8 DelayUS)
{
	SYS_DEV_CLOCK DEV_GPION;
	
	if(pHandle == NULL) 
	{
		SIIC_Debug("初始化软件IIC失败,pHandle句柄为空\r\n");
		return FALSE;
	}
	if(DelayUS < 1) DelayUS = 1;
	if(DelayUS > 100) DelayUS = 100;
	pHandle->DelayUS = DelayUS;
	pHandle->SDA_GPIOx = SDA_GPIOx;				//SDA数据线IO
	pHandle->SCL_GPIOx = SCL_GPIOx;				//SCL时钟线IO
	if(SDA_GPIO_BITx > 15) 
	{
		SIIC_Debug("初始化软件IIC失败,SDA_GPIO_BITx不能超过15\r\n");
		return FALSE;
	}
	pHandle->SDA_GPIO_BITx = SDA_GPIO_BITx;		//SDA数据线位,0-15
	if(SCL_GPIO_BITx > 15) 
	{
		SIIC_Debug("初始化软件IIC失败,SCL_GPIO_BITx不能超过15\r\n");
		return FALSE;
	}
	pHandle->SCL_GPIO_BITx = SCL_GPIO_BITx;		//SCL时钟线位,0-15
	//判断SDA IO组,进行时钟初始化
	switch((u32)SDA_GPIOx)
	{
		case (u32)GPIOA:
		{
			DEV_GPION = DEV_GPIOA;
		}break;
		case (u32)GPIOB:
		{
			DEV_GPION = DEV_GPIOB;
		}break;
		case (u32)GPIOC:
		{
			DEV_GPION = DEV_GPIOC;
		}break;
		case (u32)GPIOD:
		{
			DEV_GPION = DEV_GPIOD;
		}break;
		case (u32)GPIOE:
		{
			DEV_GPION = DEV_GPIOE;
		}break;
		case (u32)GPIOF:
		{
			DEV_GPION = DEV_GPIOF;
		}break;
		case (u32)GPIOG:
		{
			DEV_GPION = DEV_GPIOG;
		}break;
		case (u32)GPIOH:
		{
			DEV_GPION = DEV_GPIOH;
		}break;
		case (u32)GPIOI:
		{
			DEV_GPION = DEV_GPIOI;
		}break;
		case (u32)GPIOJ:
		{
			DEV_GPION = DEV_GPIOJ;
		}break;
		case (u32)GPIOK:
		{
			DEV_GPION = DEV_GPIOK;
		}break;
		default: 
		{
			SIIC_Debug("初始化软件IIC失败,SDA_GPIOx无效\r\n");
			return FALSE;
		}
	}
	SYS_DeviceClockEnable(DEV_GPION, TRUE);	//使能SDA IO时钟
	//判断SCL IO组,进行时钟初始化
	switch((u32)SCL_GPIOx)
	{
		case (u32)GPIOA:
		{
			DEV_GPION = DEV_GPIOA;
		}break;
		case (u32)GPIOB:
		{
			DEV_GPION = DEV_GPIOB;
		}break;
		case (u32)GPIOC:
		{
			DEV_GPION = DEV_GPIOC;
		}break;
		case (u32)GPIOD:
		{
			DEV_GPION = DEV_GPIOD;
		}break;
		case (u32)GPIOE:
		{
			DEV_GPION = DEV_GPIOE;
		}break;
		case (u32)GPIOF:
		{
			DEV_GPION = DEV_GPIOF;
		}break;
		case (u32)GPIOG:
		{
			DEV_GPION = DEV_GPIOG;
		}break;
		case (u32)GPIOH:
		{
			DEV_GPION = DEV_GPIOH;
		}break;
		case (u32)GPIOI:
		{
			DEV_GPION = DEV_GPIOI;
		}break;
		case (u32)GPIOJ:
		{
			DEV_GPION = DEV_GPIOJ;
		}break;
		case (u32)GPIOK:
		{
			DEV_GPION = DEV_GPIOK;
		}break;
		default:
		{
			
			SIIC_Debug("初始化软件IIC失败,SCL_GPIOx无效\r\n");
			return FALSE;
		
		}
	}
	SYS_DeviceClockEnable(DEV_GPION, TRUE);						//使能SCL IO时钟
	SDA_OUT_MODE(SDA_GPIOx,SDA_GPIO_BITx);						//SDA输出模式
	SCL_OUT_MODE(SCL_GPIOx,SCL_GPIO_BITx);						//SCL输出模式
	SDA_OUT_H(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=1
	SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
	//接口函数初始化
	pHandle->Start = (void (*)(void *))SIIC_Start;				//产生IIC起始信号
	pHandle->Stop  = (void (*)(void *))SIIC_Stop;				//产生IIC停止信号
	pHandle->SendByte  = (bool (*)(void *,u8))SIIC_SendByte;	//SIIC发送一个字节
	pHandle->ReadByte  = (u8 (*)(void *, bool))SIIC_ReadByte;	//SIIC读取一个字节

	return TRUE;
}




/*************************************************************************************************************************
*函数        	:	void SIIC_Start(SIIC_HANDLE *pHandle)
*功能        	:	产生IIC起始信号
*参数        	:	pHandle:句柄
*返回        	:	无
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2020-02-16
*说明        	:	结果:SDA输出模式,SDA=0,SCL=0
*************************************************************************************************************************/
void SIIC_Start(SIIC_HANDLE *pHandle)
{
	SDA_OUT_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);	//SDA设置为输出
	SDA_OUT_H(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=1
	SIIC_DelayUS(1);
	SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
	SIIC_DelayUS(pHandle->DelayUS);								//延时
 	SDA_OUT_L(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=0 START:when CLK is high,DATA change form high to low 
	SIIC_DelayUS(pHandle->DelayUS);								//延时
	SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0,钳住I2C总线,准备发送或接收数据 
}	


/*************************************************************************************************************************
*函数        	:	void SIIC_Stop(SIIC_HANDLE *pHandle)
*功能        	:	产生IIC停止信号
*参数        	:	pHandle:句柄
*返回        	:	无
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2020-02-16
*说明        	:	结果:SDA输出模式,SDA=1,SCL=1
*************************************************************************************************************************/
void SIIC_Stop(SIIC_HANDLE *pHandle)
{
	SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0
	SIIC_DelayUS(1);
	SDA_OUT_L(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=0 //STOP:when CLK is high DATA change form low to high
	SIIC_DelayUS(pHandle->DelayUS);								//延时
	SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
	SIIC_DelayUS(pHandle->DelayUS);								//延时
	SDA_OUT_H(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=1	
	SIIC_DelayUS(1);											//延时					   	
}


/*************************************************************************************************************************
*函数        	:	bool SIIC_WaitAck(SIIC_HANDLE *pHandle)
*功能        	:	IIC等待应答信号到来
*参数        	:	pHandle:句柄
*返回        	:	TRUE:应答成功;FALSE:应答失败
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2020-02-16
*说明        	:	结果:SDA输出模式,SDA=X,SCL=0
*************************************************************************************************************************/
bool SIIC_WaitAck(SIIC_HANDLE *pHandle)
{
	u8 ucErrTime=0;
	
	SDA_IN_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);	//SDA设置为输入
	SIIC_DelayUS(pHandle->DelayUS);								//延时
	SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
	SIIC_DelayUS(pHandle->DelayUS);								//延时	 
	
	while(SDA_IN(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx))	//等待低电平
	{
		ucErrTime++;
		if(ucErrTime>50)
		{
			SIIC_Stop(pHandle);
			return FALSE;
		}
		SIIC_DelayUS(1);
	}	
	SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0	  
	Delay_US(1);
	SDA_OUT_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);	//SDA设置为输出
	
	return TRUE;  
} 


/*************************************************************************************************************************
*函数        	:	void SIIC_Ack(SIIC_HANDLE *pHandle)
*功能        	:	IIC产生ACK应答
*参数        	:	pHandle:句柄
*返回        	:	无
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2020-02-16
*说明        	:	结果:SDA输出模式,SDA=0,SCL=0
*************************************************************************************************************************/
void SIIC_Ack(SIIC_HANDLE *pHandle)
{
	SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0	   
	SDA_OUT_L(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=0
	SIIC_DelayUS(pHandle->DelayUS);								//延时	 
	SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
	SIIC_DelayUS(pHandle->DelayUS);								//延时	
	SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0	 
}

/*************************************************************************************************************************
*函数        	:	void SIIC_NAck(SIIC_HANDLE *pHandle)
*功能        	:	SIIC产生NACK应答
*参数        	:	pHandle:句柄
*返回        	:	无
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2020-02-16
*说明        	:	结果:SDA输出模式,SDA=1,SCL=0
*************************************************************************************************************************/	    
void SIIC_NAck(SIIC_HANDLE *pHandle)
{
	SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0	   
	SDA_OUT_H(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=1
	SIIC_DelayUS(pHandle->DelayUS);								//延时	
	SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
	SIIC_DelayUS(pHandle->DelayUS);								//延时	
	SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0	  
}	





/*************************************************************************************************************************
*函数        	:	bool SIIC_SendByte(SIIC_HANDLE *pHandle, u8 data)
*功能        	:	SIIC发送一个字节
*参数        	:	pHandle:句柄;data:要发送的数据
*返回        	:	TRUE:有应答;FALSE:无应答
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2020-02-16
*说明        	:	结果:SDA输出模式,SDA=X,SCL=0
*************************************************************************************************************************/	    
bool SIIC_SendByte(SIIC_HANDLE *pHandle, u8 data)
{                        
    u8 t; 
	
    for(t=0;t<8;t++)
    {         
		if(data & 0X80)
		{
			SDA_OUT_H(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=1
		}
		else
		{
			SDA_OUT_L(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA=0
		}
        data <<= 1; 
		SIIC_DelayUS(pHandle->DelayUS);								//延时	
		SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
		SIIC_DelayUS(pHandle->DelayUS);								//延时	
		SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0	
    }	
	return SIIC_WaitAck(pHandle);									//等待应答
} 	



/*************************************************************************************************************************
*函数        	:	u8 SIIC_ReadByte(SIIC_HANDLE *pHandle,bool isAck)
*功能        	:	SIIC读取一个字节
*参数        	:	pHandle:句柄;isAck:是否发送ACK
*返回        	:	读取到的数据
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2017-07-10
*最后修改时间	:	2020-02-16
*说明        	:	结果:SDA输出模式,SDA=X,SCL=0
*************************************************************************************************************************/ 
u8 SIIC_ReadByte(SIIC_HANDLE *pHandle,bool isAck)
{
	u8 i,receive=0;
	
	SDA_IN_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);		//SDA设置为输入
    for(i=0;i<8;i++ )
	{
		receive<<=1;
		//产生时钟
		SIIC_DelayUS(pHandle->DelayUS);								//延时	
		SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=1
		SIIC_DelayUS(pHandle->DelayUS);								//延时	
		if(SDA_IN(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx))
		{
			receive++;
		}
		nop;
        SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx);		//SCL=0	
    }
	nop;nop;nop;
	SDA_OUT_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx);	//SDA设置为输出	
    if (!isAck)
        SIIC_NAck(pHandle);//发送nACK
    else
        SIIC_Ack(pHandle); //发送ACK  
	
    return receive;
}


/*************************************************************************************************************************
* 函数	:			bool SIIC_ReadReg(SIIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
* 功能	:			软件IIC读取寄存器(可以读取1个或者多个寄存器)
* 参数	:			pHandle:软件IIC句柄;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
						pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;
* 返回	:			IIC_ERROR
* 依赖	:			底层宏定义
* 作者	:			cp1300@139.com
* 时间	:			2020-02-15
* 最后修改时间 : 	2020-02-15
* 说明	: 			读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据					
*************************************************************************************************************************/
bool SIIC_ReadReg(SIIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
{
	u16 i;
	
	SIIC_Start(pHandle);									//产生IIC起始信号
	if(SIIC_SendByte(pHandle, SlaveAddr) == FALSE)			//发送设备地址+写信号
	{
		DEBUG("[SIIC ERROR]:地址(写)响应NACK\r\n");
		return FALSE;
	}
	if(is8bitRegAddr == FALSE)								//16bit寄存器地址
	{
		if(SIIC_SendByte(pHandle, RegAddr>>8) == FALSE)		//发送寄存器地址高位
		{
			DEBUG("[SIIC ERROR]:寄存器地址MSB发送响应NACK\r\n");
			return FALSE;
		}
	}
	if(SIIC_SendByte(pHandle, RegAddr) == FALSE)			//发送寄存器地址低位
	{
		DEBUG("[SIIC ERROR]:寄存器地址LSB发送响应NACK\r\n");
		return FALSE;
	}
	//发送读取
	SIIC_Start(pHandle);									//产生IIC起始信号
	if(SIIC_SendByte(pHandle, SlaveAddr|BIT0) == FALSE)		//发送设备地址+读信号
	{
		DEBUG("[SIIC ERROR]:地址(读)响应NACK\r\n");
		return FALSE;
	}
	//循环读取
	for(i = 0;i < ReadByteNum;i ++)
	{
		if(i == (ReadByteNum-1))							//最后一字节不响应ACK
		{
			pDataBuff[i] = SIIC_ReadByte(pHandle, FALSE);	//SIIC读取一个字节-NAK
		}
		else
		{
			pDataBuff[i] = SIIC_ReadByte(pHandle, TRUE);	//SIIC读取一个字节-ACK
		}	
	}
	SIIC_Stop(pHandle);										//产生IIC停止信号
	
	return TRUE;
}



/*************************************************************************************************************************
* 函数	:			bool SIIC_WriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 
						u8 *pDataBuff, u16 WriteByteNum)
* 功能	:			软件IIC写寄存器(可以写1个或者多个寄存器)
* 参数	:			ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
						pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;
* 返回	:			IIC_ERROR
* 依赖	:			底层宏定义
* 作者	:			cp1300@139.com
* 时间	:			2020-02-16
* 最后修改时间 : 	2020-02-16
* 说明	: 			写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff				
*************************************************************************************************************************/
bool SIIC_WriteReg(SIIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
{
	u16 i;
	
	SIIC_Start(pHandle);									//产生IIC起始信号
	if(SIIC_SendByte(pHandle, SlaveAddr) == FALSE)			//发送设备地址+写信号
	{
		DEBUG("[SIIC ERROR]:地址(写)响应NACK\r\n");
		return FALSE;
	}
	if(is8bitRegAddr == FALSE)								//16bit寄存器地址
	{
		if(SIIC_SendByte(pHandle, RegAddr>>8) == FALSE)		//发送寄存器地址高位
		{
			DEBUG("[SIIC ERROR]:寄存器地址MSB发送响应NACK\r\n");
			return FALSE;
		}
	}
	if(SIIC_SendByte(pHandle, RegAddr) == FALSE)			//发送寄存器地址低位
	{
		DEBUG("[SIIC ERROR]:寄存器地址LSB发送响应NACK\r\n");
		return FALSE;
	}
	//循环写入
	for(i = 0;i < WriteByteNum;i ++)
	{
		if(SIIC_SendByte(pHandle, pDataBuff[i]) == FALSE)	//发送数据
		{
			DEBUG("[SIIC ERROR]:寄存器地址LSB发送响应NACK\r\n");
			return FALSE;
		}
	}
	SIIC_Stop(pHandle);										//产生IIC停止信号
	
	return TRUE;
}


 
//SoftwareIIC.H
/*************************************************************************************************************
 * 文件名:			SoftwareIIC.c
 * 功能:			STM32 软件IIC接口
 * 作者:			cp1300@139.com
 * 创建时间:		2017-07-10
 * 最后修改时间:	2017-07-10
 * 详细:			软件IIC接口
*************************************************************************************************************/
#ifndef _SOFTWARE_IIC_H_
#define _SOFTWARE_IIC_H_
#include "system.h"



//软件IIC接口句柄结构
typedef struct 
{
	GPIO_TypeDef	*SDA_GPIOx;			//SDA数据线IO
	GPIO_TypeDef	*SCL_GPIOx;			//SCL时钟线IO
	u8				SDA_GPIO_BITx;		//SDA数据线位,0-15
	u8				SCL_GPIO_BITx;		//SCL时钟线位,0-15
	u8 				DelayUS;			//通信延时US
	//接口函数
	void (*Start)(void *pHandle);				//产生IIC起始信号
	void (*Stop)(void *pHandle);				//产生IIC停止信号
	bool (*SendByte)(void *pHandle, u8 data);	//SIIC发送一个字节
	u8 (*ReadByte)(void *pHandle,bool isAck);	//SIIC读取一个字节
}SIIC_HANDLE;


bool SIIC_Init(SIIC_HANDLE *pHandle, GPIO_TypeDef *SDA_GPIOx, GPIO_TypeDef *SCL_GPIOx,u8 SDA_GPIO_BITx, u8 SCL_GPIO_BITx,u8 DelayUS);	//软件IIC初始化

void SIIC_Start(SIIC_HANDLE *pHandle);				//产生IIC起始信号
void SIIC_Stop(SIIC_HANDLE *pHandle);				//产生IIC停止信号
bool SIIC_WaitAck(SIIC_HANDLE *pHandle);			//IIC等待应答信号到来
void SIIC_Ack(SIIC_HANDLE *pHandle);				//IIC产生ACK应答
void SIIC_NAck(SIIC_HANDLE *pHandle);				//SIIC产生NACK应答
bool SIIC_SendByte(SIIC_HANDLE *pHandle, u8 data);	//SIIC发送一个字节
u8 SIIC_ReadByte(SIIC_HANDLE *pHandle,bool isAck);	//SIIC读取一个字节
bool SIIC_ReadReg(SIIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);	//软件IIC读取寄存器(可以读取1个或者多个寄存器)
bool SIIC_WriteReg(SIIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);	//软件IIC写寄存器(可以写1个或者多个寄存器)

#endif /*_SOFTWARE_IIC_H_*/

//初始化测试

static SIIC_HANDLE IIC_Handel;

#define PCF8563_SDA_GPIOx 	GPIOB
#define PCF8563_SCL_GPIOx 	GPIOB
#define PCF8563_SDA_Bit 	9
#define PCF8563_SCL_Bit	 	8

if(SIIC_Init(&IIC_Handel,PCF8563_SDA_GPIOx, PCF8563_SCL_GPIOx, PCF8563_SDA_Bit, PCF8563_SCL_Bit, 1) == FALSE)
	{
		PCF8563_Debug("**********************PCF8563 初始化失败,IIC接口初始化失败!\r\n");
		return FALSE;
	}


//读写测试

 

SIIC_Start(&IIC_Handel);									//发送起始信号
	if(SIIC_SendByte(&IIC_Handel, PCF8563_IIC_W_ADDR)==FALSE)	//发送写地址
	{
		PCF8563_Debug("PCF8563 发送写地址 ACK错误\r\n");
		return FALSE;
	}
	
	if(SIIC_SendByte(&IIC_Handel, RegIndex)==FALSE)				//发送要读取的寄存器地址
	{
		PCF8563_Debug("PCF8563 发送要读取的寄存器地址2 ACK错误\r\n");
		return FALSE;
	}
	
	SIIC_Start(&IIC_Handel);									//发送起始信号	

 

//寄存器读写demo



//触摸屏IIC读取寄存器接口-8bit地址与8bit寄存器
bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
{
	if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

//触摸屏IIC写寄存器接口-8bit地址与8bit寄存器
bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
{
	if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

//WM8994IIC读取寄存器接口-16bit地址与16bit寄存器
bool WM8994_IIC_ReadReg(u16 SlaveAddr, u16 RegAddr, u16 *pDataBuff, u16 RegNum)
{
	u8 i;

	if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, FALSE, (u8 *)pDataBuff, RegNum*2) == IIC_OK)
	{
		for(i = 0;i < RegNum;i ++)	//进行高低位对调
		{
			pDataBuff[i] = SWAP16(pDataBuff[i]);
		}
		
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

//WM8994 IIC写寄存器接口-16bit地址与16bit寄存器
bool WM8994_IIC_WriteReg(u16 SlaveAddr, u16 RegAddr, u16 *pDataBuff, u16 RegNum)
{
	u8 i;
	
	for(i = 0;i < RegNum;i ++)	//进行高低位对调
	{
		pDataBuff[i] = SWAP16(pDataBuff[i]);
	}
	if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, FALSE, (u8 *)pDataBuff, RegNum*2) == IIC_OK)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cp1300

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值