STM32 软件IIC接口,支持虚拟多个IIC接口
扫描二维码
随时随地手机看文章
STM32 软件IIC接口,支持虚拟多个IIC接口,需要自己对底层进行移植,比如IO口时钟使能,初始化,写1,写0,读取进行移植,移植到自己的硬件平台。
//SoftwareIIC.c
/************************************************************************************************************* * 文件名: SoftwareIIC.c * 功能: STM32 软件IIC接口 * 作者: cp1300@139.com * 创建时间: 2017-07-10 * 最后修改时间: 2017-07-10 * 详细: 软件IIC接口 *************************************************************************************************************/ #include "system.h" #include "GPIO_INIT.h" #include "delay.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) GPIOx_OneInit(GPIOx,bit,OUT_PP,SPEED_2M) //SDA输出模式 #define SDA_IN_MODE(GPIOx,bit) GPIOx_OneInit(GPIOx,bit,IN_IPU,IN_IN) //SDA输入模式 #define SCL_OUT_MODE(GPIOx,bit) GPIOx_OneInit(GPIOx,bit,OUT_PP,SPEED_2M) //SCL输出模式 #define SDA_OUT_H(GPIOx,bit) (GPIOx->ODR|=(1<ODR&=~(1<ODR|=(1<ODR&=~(1<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 *说明 : 无 *************************************************************************************************************************/ bool SIIC_Init(SIIC_HANDLE *pHandle, GPIO_TypeDef *SDA_GPIOx, GPIO_TypeDef *SCL_GPIOx,u8 SDA_GPIO_BITx, u8 SCL_GPIO_BITx,u8 DelayUS) { u8 DEV_GPION; if(pHandle == NULL) { SIIC_Debug("初始化软件IIC失败,pHandle句柄为空rn"); 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不能超过15rn"); return FALSE; } pHandle->SDA_GPIO_BITx = SDA_GPIO_BITx; //SDA数据线位,0-15 if(SCL_GPIO_BITx > 15) { SIIC_Debug("初始化软件IIC失败,SCL_GPIO_BITx不能超过15rn"); 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; default: { SIIC_Debug("初始化软件IIC失败,SDA_GPIOx无效rn"); return FALSE; } } DeviceClockEnable(DEV_GPION, ENABLE); //使能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; default: { SIIC_Debug("初始化软件IIC失败,SCL_GPIOx无效rn"); return FALSE; } } DeviceClockEnable(DEV_GPION, ENABLE); //使能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 return TRUE; } /************************************************************************************************************************* *函数 : void SIIC_Start(SIIC_HANDLE *pHandle) *功能 : 产生IIC起始信号 *参数 : pHandle:句柄 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2017-07-10 *最后修改时间 : 2017-07-10 *说明 : 无 *************************************************************************************************************************/ 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 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总线,准备发送或接收数据 SIIC_DelayUS(pHandle->DelayUS); //延时 } /************************************************************************************************************************* *函数 : void SIIC_Stop(SIIC_HANDLE *pHandle) *功能 : 产生IIC停止信号 *参数 : pHandle:句柄 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2017-07-10 *最后修改时间 : 2017-07-10 *说明 : 无 *************************************************************************************************************************/ void SIIC_Stop(SIIC_HANDLE *pHandle) { SDA_OUT_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx); //SDA设置为输出 SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx); //SCL=0 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 SDA_OUT_H(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx); //SDA=1 SIIC_DelayUS(pHandle->DelayUS); //延时 } /************************************************************************************************************************* *函数 : bool SIIC_WaitAck(SIIC_HANDLE *pHandle) *功能 : IIC等待应答信号到来 *参数 : pHandle:句柄 *返回 : TRUE:应答成功;FALSE:应答失败 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2017-07-10 *最后修改时间 : 2017-07-10 *说明 : 无 *************************************************************************************************************************/ bool SIIC_WaitAck(SIIC_HANDLE *pHandle) { u8 ucErrTime=0; SDA_IN_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx); //SDA设置为输入 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); //延时 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 return TRUE; } /************************************************************************************************************************* *函数 : void SIIC_Ack(SIIC_HANDLE *pHandle) *功能 : IIC产生ACK应答 *参数 : pHandle:句柄 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2017-07-10 *最后修改时间 : 2017-07-10 *说明 : 无 *************************************************************************************************************************/ void SIIC_Ack(SIIC_HANDLE *pHandle) { SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx); //SCL=0 SDA_OUT_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx); //SDA设置为输出 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 SIIC_DelayUS(pHandle->DelayUS); //延时 } /************************************************************************************************************************* *函数 : void SIIC_NAck(SIIC_HANDLE *pHandle) *功能 : SIIC产生NACK应答 *参数 : pHandle:句柄 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2017-07-10 *最后修改时间 : 2017-07-10 *说明 : 无 *************************************************************************************************************************/ void SIIC_NAck(SIIC_HANDLE *pHandle) { SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx); //SCL=0 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(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 SIIC_DelayUS(pHandle->DelayUS); //延时 } /************************************************************************************************************************* *函数 : bool SIIC_SendByte(SIIC_HANDLE *pHandle, u8 data) *功能 : SIIC发送一个字节 *参数 : pHandle:句柄;data:要发送的数据 *返回 : TRUE:有应答;FALSE:无应答 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2017-07-10 *最后修改时间 : 2017-07-10 *说明 : 无 *************************************************************************************************************************/ bool SIIC_SendByte(SIIC_HANDLE *pHandle, u8 data) { u8 t; SDA_OUT_MODE(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx); //SDA设置为输出 SCL_OUT_L(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx); //SCL=0 拉低时钟开始数据传输 for(t=0;tSDA_GPIOx, pHandle->SDA_GPIO_BITx); //SDA=1 } else { SDA_OUT_L(pHandle->SDA_GPIOx, pHandle->SDA_GPIO_BITx); //SDA=0 } data <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 SIIC_DelayUS(pHandle->DelayUS); //延时 } return SIIC_WaitAck(pHandle); //等待应答 } /************************************************************************************************************************* *函数 : u8 SIIC_ReadByte(SIIC_HANDLE *pHandle,bool isAck) *功能 : SIIC读取一个字节 *参数 : pHandle:句柄;isAck:是否发送ACK *返回 : 读取到的数据 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2017-07-10 *最后修改时间 : 2017-07-10 *说明 : 无 *************************************************************************************************************************/ 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;iSCL_GPIOx, pHandle->SCL_GPIO_BITx); //SCL=0 SIIC_DelayUS(pHandle->DelayUS); //延时 SCL_OUT_H(pHandle->SCL_GPIOx, pHandle->SCL_GPIO_BITx); //SCL=1 receive<SDA_GPIOx, pHandle->SDA_GPIO_BITx))receive++; SIIC_DelayUS(pHandle->DelayUS); //延时 } if (!isAck) SIIC_NAck(pHandle);//发送nACK else SIIC_Ack(pHandle); //发送ACK return receive; }
//SoftwareIIC.H
/************************************************************************************************************* * 文件名: SoftwareIIC.H * 功能: 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 }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读取一个字节 #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接口初始化失败!rn"); return FALSE; }
//读写测试
SIIC_Start(&IIC_Handel); //发送起始信号 if(SIIC_SendByte(&IIC_Handel, PCF8563_IIC_W_ADDR)==FALSE) //发送写地址 { PCF8563_Debug("PCF8563 发送写地址 ACK错误rn"); return FALSE; } if(SIIC_SendByte(&IIC_Handel, RegIndex)==FALSE) //发送要读取的寄存器地址 { PCF8563_Debug("PCF8563 发送要读取的寄存器地址2 ACK错误rn"); return FALSE; } SIIC_Start(&IIC_Handel); //发送起始信号