说到I2C很多用过STMF10X硬件I2C方式的工程师,都感觉有点头痛。大部分还是使用软件模拟的方式,I2C由于一般的工作频率是400,100KHz。所以在平凡读取,或所读数据量大时,使用这模拟的方式,还是比较浪费CPU有效工作时间的。

在之前的使用I2C的经历中,主要是I2C死锁问题让我也困扰了一段时间。不过后来经过多方资料,最后还是把这个问题解决了。以下驱动程序已集成了此功能。

什么是死锁,在I2C主设备进行读写操作的过程中.主设备在开始信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平,在这个时候,从设备输出应答信号,将SDA信号拉为低电平。如果这个时候主设备异常复位,SCL就会被释放为高电平。此时,如果从设备没有复位,就会继续I2C的应答,将SDA一直拉为低电平,直到SCL变为低电平,才会结束应答信号。 而对于I2C主设备来说.复位后检测SCL和SDA信号,如果发现SDA信号为低电平,则会认为I2C总线被占用,会一直等待SCL和SDA信号变为高电 平。这样,I2C主设备等待从设备释放SDA信号,而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号,两者相互等待,I2C总线进人一种 死锁状态。同样,当I2C进行读操作,I2C从设备应答后输出数据,如果在这个时刻I2C主设备异常复位而此时I2C从设备输出的数据位正好为0,也会导 致I2C总线进入死锁状态。

解决死锁问题,我主要总结出两点:

1,连接MCU和I2C从机的复位引脚。(保证同时复位)

2,通过图1官方所述进行软件复位。

图1:

如果您所选的芯片符合如下时序,那么就可以使用这个驱动程序。

图2:

这里对本驱动程序进行说明,主驱动程序主要使用中断的方式进行数据发送,官方列程是使用的DMA方式,在大数据量传送时使用DMA还是比较好的,这里使用中断方式,主要是为了方便操作。如果是小数据大量传送时,中断方式要更高效。

打开I2C

void BSP_I2cOpen(uint8_t I2C_x, uint32_t clockSpeed);

关闭I2C

void BSP_I2cClose(uint8_t I2C_x);

向I2C从设备写数据

uint32_t BSP_I2cWrite(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t writeAddress, uint16_t writeLen);

从I2C从设备读数据

uint32_t BSP_I2cRead(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t readAddress, uint16_t readLen);

读取I2C总线空闲状态

uint32_t BSP_I2cIdleState(uint8_t I2C_x);

 /*
********************************************************************************
*
* BSP_I2c.c
*
* File : BSP_I2c.c
* Version : V1.0
* Author : whq
* Mode : Thumb2
* Toolchain :
* Description : STM32F4xx I2C驱动程序
*
* History :
* Date : 2013.07.24
*******************************************************************************/ #include <string.h> #include "misc.h"
#include "stm32f4xx_i2c.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h" #include "BSP_I2c.h" static void _I2cTxIRQ(uint8_t I2C_x, I2C_PARAM_TYPE *pParam);
static void _I2cRxIRQ(uint8_t I2C_x, I2C_PARAM_TYPE *pParam); static I2C_PARAM_TYPE I2C_PARAM[I2Cn] = {}; static I2C_TypeDef* const I2C_NUM[I2Cn] = {
#if I2C_1_EN
BSP_I2C1,
#endif
#if I2C_2_EN
BSP_I2C2,
#endif
#if I2C_3_EN
BSP_I2C3,
#endif
};
static const uint32_t I2C_CLK[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_CLK,
#endif
#if I2C_2_EN
BSP_I2C2_CLK,
#endif
#if I2C_3_EN
BSP_I2C3_CLK,
#endif
}; static const uint32_t I2C_AF_PORT[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_AF_Port,
#endif
#if I2C_2_EN
BSP_I2C2_AF_Port,
#endif
#if I2C_3_EN
BSP_I2C3_AF_Port,
#endif
};
static const uint8_t I2C_SCL_AF_Source[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SCL_AF_Source,
#endif
#if I2C_2_EN
BSP_I2C2_SCL_AF_Source,
#endif
#if I2C_3_EN
BSP_I2C3_SCL_AF_Source,
#endif
};
static const uint8_t I2C_SDA_AF_Source[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SDA_AF_Source,
#endif
#if I2C_2_EN
BSP_I2C2_SDA_AF_Source,
#endif
#if I2C_3_EN
BSP_I2C3_SDA_AF_Source,
#endif
}; static GPIO_TypeDef* const I2C_SCL_PORT[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SCL_GPIO_PORT,
#endif
#if I2C_2_EN
BSP_I2C2_SCL_GPIO_PORT,
#endif
#if I2C_3_EN
BSP_I2C3_SCL_GPIO_PORT,
#endif
};
static const uint32_t I2C_SCL_CLK[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SCL_GPIO_CLK,
#endif
#if I2C_2_EN
BSP_I2C2_SCL_GPIO_CLK,
#endif
#if I2C_3_EN
BSP_I2C3_SCL_GPIO_CLK,
#endif
};
static const uint16_t I2C_SCL_PIN[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SCL_PIN,
#endif
#if I2C_2_EN
BSP_I2C2_SCL_PIN,
#endif
#if I2C_3_EN
BSP_I2C3_SCL_PIN,
#endif
}; static GPIO_TypeDef* const I2C_SDA_PORT[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SDA_GPIO_PORT,
#endif
#if I2C_2_EN
BSP_I2C2_SDA_GPIO_PORT,
#endif
#if I2C_3_EN
BSP_I2C3_SDA_GPIO_PORT,
#endif
};
static const uint32_t I2C_SDA_CLK[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SDA_GPIO_CLK,
#endif
#if I2C_2_EN
BSP_I2C2_SDA_GPIO_CLK,
#endif
#if I2C_3_EN
BSP_I2C3_SDA_GPIO_CLK,
#endif
};
static const uint16_t I2C_SDA_PIN[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_SDA_PIN,
#endif
#if I2C_2_EN
BSP_I2C2_SDA_PIN,
#endif
#if I2C_3_EN
BSP_I2C3_SDA_PIN,
#endif
}; static const uint32_t I2C_IRQn[I2Cn] = {
#if I2C_1_EN
BSP_I2C1_IRQn,
#endif
#if I2C_2_EN
BSP_I2C2_IRQn,
#endif
#if I2C_3_EN
BSP_I2C3_IRQn,
#endif
}; /*******************************************************************************
* Function Name : void BSP_I2cOpen(uint8_t I2C_x, uint32_t clockSpeed)
* Description : 打开I2C口
* Input : I2C_x: I2C_1, I2C_2
clockSpeed: 时钟线频率
* Output :
* Other :
* Date : 2013.07.24
*******************************************************************************/
void BSP_I2cOpen(uint8_t I2C_x, uint32_t clockSpeed)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure; /* Enable peripheral clocks ----------------------------------------------*/
/* Enable I2C clock */
RCC_APB1PeriphClockCmd(I2C_CLK[I2C_x], ENABLE);
/* Enable GPIOB clock */
RCC_AHB1PeriphClockCmd(I2C_SCL_CLK[I2C_x] | I2C_SDA_CLK[I2C_x], ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); I2C_Cmd(I2C_NUM[I2C_x], DISABLE);
I2C_DeInit(I2C_NUM[I2C_x]); /* Connect I2C_SCL*/
GPIO_PinAFConfig(I2C_SCL_PORT[I2C_x], I2C_SCL_AF_Source[I2C_x], I2C_AF_PORT[I2C_x]);
/* Connect I2C_SDA*/
GPIO_PinAFConfig(I2C_SDA_PORT[I2C_x], I2C_SDA_AF_Source[I2C_x], I2C_AF_PORT[I2C_x]); /* Configure I2C pins: SCL and SDA ---------------------------------------*/
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN[I2C_x];
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(I2C_SCL_PORT[I2C_x], &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN[I2C_x];
GPIO_Init(I2C_SDA_PORT[I2C_x], &GPIO_InitStructure); /* DISABLE I2C event and buffer interrupt */
I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_EVT | I2C_IT_BUF, DISABLE); /* I2C configuration -----------------------------------------------------*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = clockSpeed;
I2C_Init(I2C_NUM[I2C_x], &I2C_InitStructure); memset (&I2C_PARAM[I2C_x], , sizeof(I2C_PARAM_TYPE)); /* Configure and enable I2C interrupt ------------------------------------*/
NVIC_InitStructure.NVIC_IRQChannel = I2C_IRQn[I2C_x];
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); /* Enable I2C ------------------------------------------------------------*/
I2C_Cmd(I2C_NUM[I2C_x], ENABLE);
} /*******************************************************************************
* Function Name : void _I2CDelay(volatile uint32_t count)
* Description : 延迟程序
* Input :
* Output :
* Other :
* Date : 2013.08.15
*******************************************************************************/
void _I2CDelay(volatile uint32_t count)
{
for (; count > ; count--);
} /*******************************************************************************
* Function Name : void BSP_I2cClose(uint8_t I2C_x)
* Description : 关闭I2C口 并释放总线
* Input :
* Output :
* Other :
* Date : 2013.07.24
*******************************************************************************/
void BSP_I2cClose(uint8_t I2C_x)
{
GPIO_InitTypeDef GPIO_InitStructure;
uint16_t i = ; I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_EVT | I2C_IT_BUF, DISABLE);
RCC_APB1PeriphClockCmd(I2C_CLK[I2C_x], DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, DISABLE); I2C_Cmd(I2C_NUM[I2C_x], DISABLE);
I2C_DeInit(I2C_NUM[I2C_x]); /* Configure I2C pins: SCL and SDA ---------------------------------------*/
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN[I2C_x];
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(I2C_SCL_PORT[I2C_x], &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN[I2C_x];
GPIO_Init(I2C_SDA_PORT[I2C_x], &GPIO_InitStructure); _I2CDelay();
for (i = ; i > ; i--) //16个时钟 脉冲 释放I2C总线
{
GPIO_ResetBits(I2C_SCL_PORT[I2C_x], I2C_SCL_PIN[I2C_x]);
_I2CDelay();
GPIO_SetBits(I2C_SCL_PORT[I2C_x], I2C_SCL_PIN[I2C_x]);
_I2CDelay();
} GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN[I2C_x];
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(I2C_SCL_PORT[I2C_x], &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN[I2C_x];
GPIO_Init(I2C_SDA_PORT[I2C_x], &GPIO_InitStructure); memset (&I2C_PARAM[I2C_x], , sizeof(I2C_PARAM_TYPE));
} /*******************************************************************************
* Function Name : uint32_t BSP_I2cWrite(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t writeAddress, uint16_t writeLen)
* Description : I2C向从机发送数据
* Input : I2C_x: I2C_1, I2C_2
buff: 要发送的数据
i2cSaleAddress: 从机ID号
writeAddress: 写入的地址
writeLen: 要写入的数据长度
* Output :
* Other : 本函数为非阻塞式 执行完后调用BSP_I2cIdleState 是否执行完毕
* Date : 2013.07.24
*******************************************************************************/
uint32_t BSP_I2cWrite(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t writeAddress, uint16_t writeLen)
{
if (I2C_x >= I2C_MAX)
return ; if (NULL == buff)
return ; if ( == writeLen)
return ; if ( != I2C_PARAM[I2C_x].idle)
return ; I2C_PARAM[I2C_x].idle = ;
I2C_PARAM[I2C_x].id = i2cSaleAddress;
I2C_PARAM[I2C_x].addr = writeAddress;
I2C_PARAM[I2C_x].index = ;
I2C_PARAM[I2C_x].r_w = ;
I2C_PARAM[I2C_x].bufLen = writeLen;
I2C_PARAM[I2C_x].pBuff = buff;
I2C_PARAM[I2C_x].FunCallBack = (void (*)(uint8_t, void *))_I2cTxIRQ; I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_EVT | I2C_IT_BUF, ENABLE);
I2C_AcknowledgeConfig(I2C_NUM[I2C_x], ENABLE);
/* Send I2C START condition */
I2C_GenerateSTART(I2C_NUM[I2C_x], ENABLE);
return writeLen;
} /*******************************************************************************
* Function Name : uint32_t BSP_I2cRead(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t readAddress, uint16_t readLen)
* Description : I2C 读取数据
* Input : I2C_x: I2C_1, I2C_2
buff: 读数缓冲区
i2cSaleAddress: 从机ID号
readAddress: 读取的地址
readLen: 要读取的数据长度
* Output :
* Other : 本函数为非阻塞式 执行完后调用BSP_I2cIdleState 是否执行完毕
* Date : 2013.07.24
*******************************************************************************/
uint32_t BSP_I2cRead(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t readAddress, uint16_t readLen)
{
if (I2C_x >= I2C_MAX)
return ; if (NULL == buff)
return ; if ( == readLen)
return ; if ( != I2C_PARAM[I2C_x].idle)
return ; I2C_PARAM[I2C_x].idle = ;
I2C_PARAM[I2C_x].id = i2cSaleAddress;
I2C_PARAM[I2C_x].addr = readAddress;
I2C_PARAM[I2C_x].index = ;
I2C_PARAM[I2C_x].r_w = ;
I2C_PARAM[I2C_x].bufLen = readLen;
I2C_PARAM[I2C_x].pBuff = buff;
I2C_PARAM[I2C_x].FunCallBack = (void (*)(uint8_t, void *))_I2cTxIRQ; I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_EVT | I2C_IT_BUF, ENABLE);
I2C_AcknowledgeConfig(I2C_NUM[I2C_x], ENABLE);
/* Send I2C START condition */
I2C_GenerateSTART(I2C_NUM[I2C_x], ENABLE);
return readLen;
} /*******************************************************************************
* Function Name : uint32_t BSP_I2cIdleState(uint8_t I2C_x)
* Description : 查询是否总线空闲 如果为空闲则读取参数
* Input : I2C_x: I2C_1, I2C_2
* Output : return: 0)空闲 1)忙碌
* Other :
* Date : 2013.07.24
*******************************************************************************/
uint32_t BSP_I2cIdleState(uint8_t I2C_x)
{
return (I2C_PARAM[I2C_x].idle || I2C_GetFlagStatus(I2C_NUM[I2C_x], I2C_FLAG_BUSY));
} /*******************************************************************************
* Function Name : static void _I2cTxIRQ(uint8_t I2C_x, I2C_PARAM_TYPE *pParam)
* Description : 发送数据中断函数
* Input :
* Output :
* Other :
* Date : 2013.07.24
*******************************************************************************/
static void _I2cTxIRQ(uint8_t I2C_x, I2C_PARAM_TYPE *pParam)
{
switch (I2C_GetLastEvent(I2C_NUM[I2C_x]))
{
/* Test on I2Cx EV5 and clear it */
case I2C_EVENT_MASTER_MODE_SELECT:
I2C_Send7bitAddress(I2C_NUM[I2C_x], pParam->id, I2C_Direction_Transmitter);
break; /* Test on I2Cx EV6 and first EV8 and clear them */
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:
/* Send the first data */
I2C_SendData(I2C_NUM[I2C_x], pParam->addr); /* EV8 just after EV6 */
break; case I2C_EVENT_MASTER_BYTE_TRANSMITTING:
if((pParam->index < pParam->bufLen) && (pParam->r_w == ))
{
/* Transmit buffer data */
I2C_SendData(I2C_NUM[I2C_x], pParam->pBuff[pParam->index++]);
}
else
{
I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_BUF, DISABLE);
}
break; /* Test on I2Cx EV8 and clear it */
case I2C_EVENT_MASTER_BYTE_TRANSMITTED:
if (pParam->r_w != )
{
pParam->FunCallBack = (void (*)(uint8_t, void *))_I2cRxIRQ;
I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_BUF, ENABLE);
I2C_GenerateSTART(I2C_NUM[I2C_x], ENABLE);
}
else
{
I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_EVT | I2C_IT_BUF, DISABLE);
I2C_AcknowledgeConfig(I2C_NUM[I2C_x], DISABLE);
I2C_GenerateSTOP(I2C_NUM[I2C_x], ENABLE);
pParam->idle = ; //接收结束标志
}
break;
}
} /*******************************************************************************
* Function Name : static void _I2cRxIRQ(uint8_t I2C_x, I2C_PARAM_TYPE *pParam)
* Description : 接收数据中断函数
* Input :
* Output :
* Other :
* Date : 2013.07.24
*******************************************************************************/
static void _I2cRxIRQ(uint8_t I2C_x, I2C_PARAM_TYPE *pParam)
{
switch (I2C_GetLastEvent(I2C_NUM[I2C_x]))
{
/* Test on I2Cx EV5 and clear it */
case I2C_EVENT_MASTER_MODE_SELECT:
/* Send I2Cx slave Address for write */
I2C_Send7bitAddress(I2C_NUM[I2C_x], pParam->id, I2C_Direction_Receiver);
break; /* Test on I2Cx EV6 and first EV8 and clear them */
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED:
if (pParam->index == (pParam->bufLen - ))
{
I2C_AcknowledgeConfig(I2C_NUM[I2C_x], DISABLE);
I2C_GenerateSTOP(I2C_NUM[I2C_x], ENABLE);
}
break; /* Test on I2Cx EV2 and clear it */
case I2C_EVENT_MASTER_BYTE_RECEIVED:
pParam->pBuff[pParam->index++] = I2C_ReceiveData(I2C_NUM[I2C_x]); if (pParam->index == (pParam->bufLen - ))
{
I2C_AcknowledgeConfig(I2C_NUM[I2C_x], DISABLE);
I2C_GenerateSTOP(I2C_NUM[I2C_x], ENABLE);
}
else if (pParam->index >= pParam->bufLen)
{
pParam->FunCallBack = (void (*)(uint8_t, void *))_I2cTxIRQ; //默认进接收中断
I2C_ITConfig(I2C_NUM[I2C_x], I2C_IT_EVT | I2C_IT_BUF, DISABLE);
pParam->idle = ;
}
break;
}
} #if I2C_1_EN
/*******************************************************************************
* Function Name : void I2C1_EV_IRQHandler(void)
* Description : I2C1中断函数
* Input :
* Output :
* Other :
* Date : 2013.07.24
*******************************************************************************/
void I2C1_EV_IRQHandler(void)
{
if (I2C_PARAM[I2C_1].FunCallBack)
{
I2C_PARAM[I2C_1].FunCallBack(I2C_1, &I2C_PARAM[I2C_1]);
}
}
#endif #if I2C_2_EN
/*******************************************************************************
* Function Name : void I2C2_EV_IRQHandler(void)
* Description : I2C2中断函数
* Input :
* Output :
* Other :
* Date : 2013.07.24
*******************************************************************************/
void I2C2_EV_IRQHandler(void)
{
if (I2C_PARAM[I2C_2].FunCallBack)
{
I2C_PARAM[I2C_2].FunCallBack(I2C_2, &I2C_PARAM[I2C_2]);
}
}
#endif #if I2C_3_EN
/*******************************************************************************
* Function Name : void I2C3_EV_IRQHandler(void)
* Description : I2C3中断函数
* Input :
* Output :
* Other :
* Date : 2013.07.24
*******************************************************************************/
void I2C3_EV_IRQHandler(void)
{
if (I2C_PARAM[I2C_3].FunCallBack)
{
I2C_PARAM[I2C_3].FunCallBack(I2C_3, &I2C_PARAM[I2C_3]);
}
}
#endif

BSP_I2c.c

 /*
********************************************************************************
*
* BSP_I2c.h
*
* File : BSP_I2c.h
* Version : V1.0
* Author : whq
* Mode : Thumb2
* Toolchain :
* Description : I2C驱动头文件
*
* History :
* Date : 2013.07.24
*******************************************************************************/ #ifndef _BSP_I2C_H_
#define _BSP_I2C_H_ #include <stdint.h> #define I2C_1_EN 1
#define I2C_2_EN 1
#define I2C_3_EN 1 #if !(I2C_1_EN || I2C_2_EN ||I2C_3_EN)
#error "请至少打开一路I2C"
#endif typedef enum {
#if I2C_1_EN
I2C_1,
#endif
#if I2C_2_EN
I2C_2,
#endif
#if I2C_3_EN
I2C_3,
#endif
I2C_MAX
}I2C_ENUM; #define I2Cn I2C_MAX
#define I2C_1_0 //无映射:I2C_1_0,映射1:I2C_1_1
#define I2C_2_0
#define I2C_3_0 //无映射:I2C_3_0,映射1:I2C_3_1 #define I2C_SLAVE_ADDRESS 0x30 //本STM32芯片地址 /******************************类型声明****************************************/ typedef struct {
volatile uint8_t idle; //空闲标志 0)空闲 1)忙碌
uint8_t r_w; //读写标志 0)写 1)读
uint8_t id; //从机设备ID号
uint8_t addr; //要读写的地址
volatile uint16_t index; //当前缓冲区数据长度
uint16_t bufLen; //要发送或接收的数据长度
uint8_t * volatile pBuff; //缓冲区首地址
void (* volatile FunCallBack)(uint8_t, void *);//中断回调函数
}I2C_PARAM_TYPE; /******************************************************************************/ /**
* @brief I2C1 Interface pins
*/
#define BSP_I2C1 I2C1
#define BSP_I2C1_CLK RCC_APB1Periph_I2C1
#define BSP_I2C1_AF_Port GPIO_AF_I2C1
#define BSP_I2C1_IRQn I2C1_EV_IRQn #if defined(I2C_1_2) //自由组合区
#define BSP_I2C1_SCL_AF_Source GPIO_PinSource8
#define BSP_I2C1_SCL_PIN GPIO_Pin_8
#define BSP_I2C1_SCL_GPIO_PORT GPIOB
#define BSP_I2C1_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB #define BSP_I2C1_SDA_AF_Source GPIO_PinSource9
#define BSP_I2C1_SDA_PIN GPIO_Pin_9
#define BSP_I2C1_SDA_GPIO_PORT GPIOB
#define BSP_I2C1_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB #elif defined(I2C_1_1)
#define BSP_I2C1_SCL_AF_Source GPIO_PinSource8
#define BSP_I2C1_SCL_PIN GPIO_Pin_8
#define BSP_I2C1_SCL_GPIO_PORT GPIOB
#define BSP_I2C1_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB #define BSP_I2C1_SDA_AF_Source GPIO_PinSource9
#define BSP_I2C1_SDA_PIN GPIO_Pin_9
#define BSP_I2C1_SDA_GPIO_PORT GPIOB
#define BSP_I2C1_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB #else
#define BSP_I2C1_SCL_AF_Source GPIO_PinSource6
#define BSP_I2C1_SCL_PIN GPIO_Pin_6
#define BSP_I2C1_SCL_GPIO_PORT GPIOB
#define BSP_I2C1_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB #define BSP_I2C1_SDA_AF_Source GPIO_PinSource7
#define BSP_I2C1_SDA_PIN GPIO_Pin_7
#define BSP_I2C1_SDA_GPIO_PORT GPIOB
#define BSP_I2C1_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB
#endif /**
* @brief I2C2 Interface pins
*/
#define BSP_I2C2 I2C2
#define BSP_I2C2_CLK RCC_APB1Periph_I2C2
#define BSP_I2C2_AF_Port GPIO_AF_I2C2
#define BSP_I2C2_IRQn I2C2_EV_IRQn #if defined(I2C_2_3) //自由组合区
#define BSP_I2C2_SCL_AF_Source GPIO_PinSource4
#define BSP_I2C2_SCL_PIN GPIO_Pin_4
#define BSP_I2C2_SCL_GPIO_PORT GPIOH
#define BSP_I2C2_SCL_GPIO_CLK RCC_AHB1Periph_GPIOH #define BSP_I2C2_SDA_AF_Source GPIO_PinSource5
#define BSP_I2C2_SDA_PIN GPIO_Pin_5
#define BSP_I2C2_SDA_GPIO_PORT GPIOH
#define BSP_I2C2_SDA_GPIO_CLK RCC_AHB1Periph_GPIOH #elif defined(I2C_2_2)
#define BSP_I2C2_SCL_AF_Source GPIO_PinSource4
#define BSP_I2C2_SCL_PIN GPIO_Pin_4
#define BSP_I2C2_SCL_GPIO_PORT GPIOH
#define BSP_I2C2_SCL_GPIO_CLK RCC_AHB1Periph_GPIOH #define BSP_I2C2_SDA_AF_Source GPIO_PinSource5
#define BSP_I2C2_SDA_PIN GPIO_Pin_5
#define BSP_I2C2_SDA_GPIO_PORT GPIOH
#define BSP_I2C2_SDA_GPIO_CLK RCC_AHB1Periph_GPIOH #elif defined(I2C_2_1)
#define BSP_I2C2_SCL_AF_Source GPIO_PinSource1
#define BSP_I2C2_SCL_PIN GPIO_Pin_1
#define BSP_I2C2_SCL_GPIO_PORT GPIOF
#define BSP_I2C2_SCL_GPIO_CLK RCC_AHB1Periph_GPIOF #define BSP_I2C2_SDA_AF_Source GPIO_PinSource0
#define BSP_I2C2_SDA_PIN GPIO_Pin_0
#define BSP_I2C2_SDA_GPIO_PORT GPIOF
#define BSP_I2C2_SDA_GPIO_CLK RCC_AHB1Periph_GPIOF #else
#define BSP_I2C2_SCL_AF_Source GPIO_PinSource10
#define BSP_I2C2_SCL_PIN GPIO_Pin_10
#define BSP_I2C2_SCL_GPIO_PORT GPIOB
#define BSP_I2C2_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB #define BSP_I2C2_SDA_AF_Source GPIO_PinSource11
#define BSP_I2C2_SDA_PIN GPIO_Pin_11
#define BSP_I2C2_SDA_GPIO_PORT GPIOB
#define BSP_I2C2_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB
#endif /**
* @brief I2C3 Interface pins
*/
#define BSP_I2C3 I2C3
#define BSP_I2C3_CLK RCC_APB1Periph_I2C3
#define BSP_I2C3_AF_Port GPIO_AF_I2C3
#define BSP_I2C3_IRQn I2C3_EV_IRQn #if defined(I2C_3_2) //自由组合区
#define BSP_I2C3_SCL_AF_Source GPIO_PinSource8
#define BSP_I2C3_SCL_PIN GPIO_Pin_8
#define BSP_I2C3_SCL_GPIO_PORT GPIOA
#define BSP_I2C3_SCL_GPIO_CLK RCC_AHB1Periph_GPIOA #define BSP_I2C3_SDA_AF_Source GPIO_PinSource8
#define BSP_I2C3_SDA_PIN GPIO_Pin_8
#define BSP_I2C3_SDA_GPIO_PORT GPIOH
#define BSP_I2C3_SDA_GPIO_CLK RCC_AHB1Periph_GPIOH #elif defined(I2C_3_1)
#define BSP_I2C3_SCL_AF_Source GPIO_PinSource8
#define BSP_I2C3_SCL_PIN GPIO_Pin_8
#define BSP_I2C3_SCL_GPIO_PORT GPIOA
#define BSP_I2C3_SCL_GPIO_CLK RCC_AHB1Periph_GPIOA #define BSP_I2C3_SDA_AF_Source GPIO_PinSource9
#define BSP_I2C3_SDA_PIN GPIO_Pin_9
#define BSP_I2C3_SDA_GPIO_PORT GPIOC
#define BSP_I2C3_SDA_GPIO_CLK RCC_AHB1Periph_GPIOC #else
#define BSP_I2C3_SCL_AF_Source GPIO_PinSource7
#define BSP_I2C3_SCL_PIN GPIO_Pin_7
#define BSP_I2C3_SCL_GPIO_PORT GPIOH
#define BSP_I2C3_SCL_GPIO_CLK RCC_AHB1Periph_GPIOH #define BSP_I2C3_SDA_AF_Source GPIO_PinSource8
#define BSP_I2C3_SDA_PIN GPIO_Pin_8
#define BSP_I2C3_SDA_GPIO_PORT GPIOH
#define BSP_I2C3_SDA_GPIO_CLK RCC_AHB1Periph_GPIOH
#endif /******************************函数声明****************************************/
void BSP_I2cOpen(uint8_t I2C_x, uint32_t clockSpeed);
void BSP_I2cClose(uint8_t I2C_x);
uint32_t BSP_I2cWrite(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t writeAddress, uint16_t writeLen);
uint32_t BSP_I2cRead(uint8_t I2C_x, uint8_t *buff, uint16_t i2cSaleAddress, uint8_t readAddress, uint16_t readLen);
uint32_t BSP_I2cIdleState(uint8_t I2C_x); #endif

BSP_I2c.h

STM32F4XX高效驱动篇2 I2C的更多相关文章

  1. STM32F4XX高效驱动篇1-UART

    之前一直在做驱动方面的整理工作,对驱动的高效性有一些自己的理解这里和大家分享一下.并奉驱动程序,本程序覆盖uart1-8. 串口驱动,这是在每个单片机中可以说是必备接口.可以说大部分产品中都会使用,更 ...

  2. linux i2c驱动架构-dm368 i2c驱动分析

      linux i2c驱动架构-dm368 i2c驱动分析   在阅读本文最好先熟悉一种i2c设备的驱动程序,并且浏览一下i2c-core.c以及芯片提供商的提供的i2c总线驱动(i2c-davinc ...

  3. Linux设备驱动模型之I2C总线

    一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,提供了与具体硬件无关的I2C读写函数. (2)I2 ...

  4. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】连载导读

    前言: 无数昼夜的来回轮替以后,这本<驱动篇I>终于编辑完毕了,笔者真的感动到连鼻涕也流下来.所谓驱动就是认识硬件,还有前期建模.虽然<驱动篇I>的硬件都是我们熟悉的老友记,例 ...

  5. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】原创教程连载导读【连载完成,共二十九章】

    前言: 无数昼夜的来回轮替以后,这本<驱动篇I>终于编辑完毕了,笔者真的感动到连鼻涕也流下来.所谓驱动就是认识硬件,还有前期建模.虽然<驱动篇I>的硬件都是我们熟悉的老友记,例 ...

  6. ARM Linux驱动篇 学习温度传感器ds18b20的驱动编写过程

    ARM Linux驱动篇 学习温度传感器ds18b20的驱动编写过程 原文地址:http://www.cnblogs.com/NickQ/p/9026545.html 一.开发板与ds18b20的入门 ...

  7. 羽夏看Win系统内核——驱动篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  8. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】【实验一】流水灯模块

    实验一:流水灯模块 对于发展商而言,动土仪式无疑是最重要的任务.为此,流水灯实验作为低级建模II的动土仪式再适合不过了.废话少说,我们还是开始实验吧. 图1.1 实验一建模图. 如图1.1 所示,实验 ...

  9. Linux驱动编程--基于I2C子系统的I2C驱动

    代码中,我添加了很多注释,应该不难理解,有错误大家可以指出来,我再改正 #include <linux/kernel.h> #include <linux/module.h> ...

随机推荐

  1. nc 查看端口是否 联通

    nc 47.9.16.1 3306 如果卡住,说明 该IP的这个端口 访问不通, 防火墙拦截了

  2. Spring MVC生成XML

    以下示例演示如何使用Spring Web MVC框架生成XML.首先使用Eclipse IDE,并按照以下步骤使用Spring Web Framework开发基于动态表单的Web应用程序: 创建一个名 ...

  3. Android仿QQ复制昵称效果2

    本文同步自http://javaexception.com/archives/77 背景: 在上一篇文章中,给出了一种复制QQ效果的方案,今天就来讲讲换一种方式实现.主要依赖的是一个开源项目https ...

  4. Servlet线程安全 Filter http://zwchen.iteye.com/blog/91088

    概述 在探讨java线程安全前,让我们先简要介绍一下Java语言. 任何语言,如C++,C#,Java,它们都有相通之处,特别是语法,但如果有人问你,Java语言的核心是什么?类库?关键字?语法?似乎 ...

  5. 解决OV系列摄像头寄存器读数据无法收到的问题

    最近工作中接了一款OV7725的sensor,由于平台已经接过很多的家的sensor也就没有太当回事.问题出现的很奇怪,再看了 register map后基本确定了要尽心register  R/W测试 ...

  6. vim-addon-manager【转】

    Vim是一个非常优秀的编辑器,但是没装插件的Vim就始终只是个编辑器而已,是插件让Vim变得更加强大. 但是插件装得多了,管理就成了问题,Vim本身并没有提供插件管理功能,往往时间一长,.vim/vi ...

  7. UICollectionView sectionHeader and sectionFooter悬浮

    UICollectionViewFlowLayout *yLayout = [[UICollectionViewFlowLayout alloc] init]; yLayout.sectionHead ...

  8. iOS - 逆向 - Objective-C代码混淆 -confuse.sh文件写法

    class-dump可以很方便的导出程序头文件,不仅让攻击者了解了程序结构方便逆向,还让着急赶进度时写出的欠完善的程序给同行留下笑柄. 所以,我们迫切的希望混淆自己的代码. 混淆的常规思路 混淆分许多 ...

  9. UTI 唯一类型标识

    本文转载至 http://blog.csdn.net/zaitianaoxiang/article/details/6657231   applicationdocumentationtypessys ...

  10. [Docker]学习笔记--简单介绍

    学习docker已经有一段时间了,一直没有静下心来好好总结一下. 最近用docker搭了一整套Gitlab的持续集成环境.(会在下一篇中详细的讲解具体步骤,敬请期待) 感觉是时候写点东西和大家一起分享 ...