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); //发送起始信号 




