目录标题
前言
在有必要注释的部分都进行了注释,可放心食用!
1、IIC通信协议基本特征
链接: 常见通信协议
2、F407系列芯片的IIC资源分布
IIC号 | SCL | SDA |
---|---|---|
IIC1 | PB6(PB8) | PB7(PB9) |
IIC2 | PB10 | PB11 |
IIC3 | PA8 | PC9 |
3、代码部分
3.1、IIC1初始化
如果有需要IIC2、IIC3初始化的,可以去看下面4完整代码部分。
/*
* 函数名称:IIC1_Config
* 功能描述:初始化硬件IIC1(PB8\PB9)
* 传入参数:无
* 传出参数:无
* 返回值:无
*/
void IIC1_Config(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
// RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);
// RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; /*开漏*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /*浮空*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; /*复用*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1); /*重映射*/
GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_I2C1);
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; /*使能应答*/
I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit; /*7bit寻址模式*/
I2C_InitStructure.I2C_ClockSpeed = 400000; /*I2C时钟速度为400KHZ*/
I2C_InitStructure.I2C_DutyCycle =I2C_DutyCycle_2; /*占控比为50%*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; /*标准IIC模式*/
I2C_InitStructure.I2C_OwnAddress1 = 0x30; /*主设备地址,一般情况下随意设置即可*/
I2C_Init(I2C1,&I2C_InitStructure);
I2C_Cmd(I2C1,ENABLE);
}
3.2、向指定从机的指定地址写8bit数据
/*
* 函数名称: IIC_WriteByte
* 功能描述: 向指定从机的指定地址写8bit数据
* 传入参数: I2Cx:要使用的IIC号
* SlaveAddr:从机地址
* WriteAddr:内存单元地址
* pBuffer :写入的字节数据
* 传出参数: 无
* 返回值: 无
*/
void IIC_WriteByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t WriteAddr, uint8_t pBuffer)
{
while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); //检查I2C总线是否繁忙,等待空闲
I2C_GenerateSTART(I2Cx, ENABLE); //产生起始信号
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);//检测EV5事件
I2C_Send7bitAddress(I2Cx, SlaveAddr, I2C_Direction_Transmitter); //发送设备地址(写模式)
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);//检测EV6事件
I2C_SendData(I2Cx, WriteAddr); //发送要写入的内存单元地址
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR); //检测EV8事件
I2C_SendData(I2Cx, pBuffer); //发送要写入的数据
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR); //检测EV8_2事件
I2C_GenerateSTOP(I2Cx, ENABLE); //产生停止信号
}
3.3、从指定从机的指定地址读取8bit数据
/*
* 函数名称: IIC_ReadByte
* 功能描述: 从指定从机的指定地址读取8bit数据
* 传入参数: I2Cx:要使用的IIC号
* SlaveAddr:从机地址
* ReadAddr:内存单元地址
* 传出参数: 无
* 返回值: data:从指定地址读取到的8bit数据
*/
uint8_t IIC_ReadByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t ReadAddr)
{
uint8_t data;
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); //检查IIC总线是否忙碌,等待空闲
I2C_GenerateSTART(I2Cx,ENABLE); //发送起始信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT )==ERROR); //检测EV5事件
I2C_Send7bitAddress(I2Cx,SlaveAddr,I2C_Direction_Transmitter); //发送设备写地址
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR);//检测EV6事件等待从机应答
I2C_SendData(I2Cx,ReadAddr); //发送要操作设备内部存储器的地址
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR); //检测EV8事件
I2C_GenerateSTART(I2Cx,ENABLE); //发送起始信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT )==ERROR); //检测EV5事件
I2C_Send7bitAddress(I2Cx,SlaveAddr+1,I2C_Direction_Receiver); //发送设备读地址(接收模式)
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR); //检测EV6事件
I2C_AcknowledgeConfig(I2Cx,DISABLE); //发送非应答信号
I2C_GenerateSTOP(I2Cx,ENABLE); //发送停止信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR); //检测EV7事件
data=I2C_ReceiveData(I2Cx); /*读数据*/
I2C_AcknowledgeConfig(I2Cx,ENABLE); //重新开启应答信号
return data;
}
4、完整代码
4.1、IIC.h
#ifndef __IIC_H
#define __IIC_H
#include "stm32f4xx.h" // Device header
void IIC1_Config(void); /*初始化硬件IIC1*/
void IIC2_Config(void); /*初始化硬件IIC2*/
void IIC3_Config(void); /*初始化硬件IIC3*/
/*
* 函数名称: IIC_WriteByte
* 功能描述: 向指定从机的指定地址写1字节数据
* 传入参数: I2Cx: 要使用的IIC号
* SlaveAddr :从机地址
* WriteAddr :内存单元地址
* pBuffer :写入的字节数据
*/
void IIC_WriteByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t WriteAddr, uint8_t pBuffer);
/*
* 函数名称: IIC_ReadByte
* 功能描述: 从指定从机的指定地址读1字节数据
* 传入参数: I2Cx:要使用的IIC号
* SlaveAddr:从机地址
* ReadAddr :内存单元地址
* 返回值 : data:从指定地址读取到的8bit数据
*/
uint8_t IIC_ReadByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t ReadAddr);
/*
* 函数名称: IIC_ReadTwoByte
* 功能描述: 从指定从机的指定地址读2字节数据
* 传入参数: I2Cx:要使用的IIC号
* SlaveAddr:从机地址
* ReadAddr :内存单元地址
*/
short IIC_ReadTwoByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t ReadAddr);
#endif
4.2、IIC.c
#include "IIC.h"
/*
* 函数名称:IIC1_Config
* 功能描述:初始化硬件IIC1(PB8\PB9)
* 传入参数:无
* 传出参数:无
* 返回值:无
*/
void IIC1_Config(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
// RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);
// RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; /*开漏*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /*浮空*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; /*复用*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1); /*重映射*/
GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_I2C1);
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; /*使能应答*/
I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit; /*7bit寻址模式*/
I2C_InitStructure.I2C_ClockSpeed = 400000; /*I2C时钟速度为400KHZ*/
I2C_InitStructure.I2C_DutyCycle =I2C_DutyCycle_2; /*占控比为50%*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; /*标准IIC模式*/
I2C_InitStructure.I2C_OwnAddress1 = 0x30; /*主设备地址,一般情况下随意设置即可*/
I2C_Init(I2C1,&I2C_InitStructure);
I2C_Cmd(I2C1,ENABLE);
}
/*
* 函数名称:IIC2_Config
* 功能描述:初始化硬件IIC2(PB10-SCL\PB11-SDA)
* 传入参数:无
* 传出参数:无
* 返回值:无
*/
void IIC2_Config(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; /*开漏*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /*浮空*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; /*复用*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_I2C1); /*重映射*/
GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_I2C1);
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(I2C2);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; /*使能应答*/
I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit; /*7bit寻址模式*/
I2C_InitStructure.I2C_ClockSpeed = 400000; /*I2C时钟速度为400KHZ*/
I2C_InitStructure.I2C_DutyCycle =I2C_DutyCycle_2; /*占控比为50%*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; /*标准IIC模式*/
I2C_InitStructure.I2C_OwnAddress1 = 0x30; /*主设备地址,一般情况下随意设置即可*/
I2C_Init(I2C2,&I2C_InitStructure);
I2C_Cmd(I2C2,ENABLE);
}
/*
* 函数名称:IIC3_Config
* 功能描述:初始化硬件IIC3(PA8-SCL\PC9-SDA)
* 传入参数:无
* 传出参数:无
* 返回值:无
*/
void IIC3_Config(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
// RCC_APB1PeriphClockCmd(RCC_APB1ENR_I2C3EN,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C3,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;/*复用开漏*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_I2C3);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_I2C3);
I2C_InitTypeDef I2C_InitStructure;
I2C_DeInit(I2C3);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; /*使能应答*/
I2C_InitStructure.I2C_AcknowledgedAddress =I2C_AcknowledgedAddress_7bit; /*7bit寻址模式*/
I2C_InitStructure.I2C_ClockSpeed = 400000; /*I2C时钟速度为400KHZ*/
I2C_InitStructure.I2C_DutyCycle =I2C_DutyCycle_2; /*占控比为50%*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; /*标准IIC模式*/
I2C_InitStructure.I2C_OwnAddress1 = 0x30; /*主设备地址,一般情况下随意设置即可*/
I2C_Init(I2C3,&I2C_InitStructure);
I2C_Cmd(I2C3,ENABLE);
}
/*
* 函数名称: IIC_WriteByte
* 功能描述: 向指定从机的指定地址写8bit数据
* 传入参数: I2Cx:要使用的IIC号
* SlaveAddr:从机地址
* WriteAddr:内存单元地址
* pBuffer :写入的字节数据
* 传出参数: 无
* 返回值: 无
*/
void IIC_WriteByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t WriteAddr, uint8_t pBuffer)
{
while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); //检查I2C总线是否繁忙,等待空闲
I2C_GenerateSTART(I2Cx, ENABLE); //产生起始信号
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);//检测EV5事件
I2C_Send7bitAddress(I2Cx, SlaveAddr, I2C_Direction_Transmitter); //发送设备地址(写模式)
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR);//检测EV6事件
I2C_SendData(I2Cx, WriteAddr); //发送要写入的内存单元地址
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR); //检测EV8事件
I2C_SendData(I2Cx, pBuffer); //发送要写入的数据
while(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR); //检测EV8_2事件
I2C_GenerateSTOP(I2Cx, ENABLE); //产生停止信号
}
/*
* 函数名称: IIC_ReadByte
* 功能描述: 从指定从机的指定地址读取8bit数据
* 传入参数: I2Cx:要使用的IIC号
* SlaveAddr:从机地址
* ReadAddr:内存单元地址
* 传出参数: 无
* 返回值: data:从指定地址读取到的8bit数据
*/
uint8_t IIC_ReadByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t ReadAddr)
{
uint8_t data;
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); //检查IIC总线是否忙碌,等待空闲
I2C_GenerateSTART(I2Cx,ENABLE); //发送起始信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT )==ERROR); //检测EV5事件
I2C_Send7bitAddress(I2Cx,SlaveAddr,I2C_Direction_Transmitter); //发送设备写地址
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR);//检测EV6事件等待从机应答
I2C_SendData(I2Cx,ReadAddr); //发送要操作设备内部存储器的地址
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR); //检测EV8事件
I2C_GenerateSTART(I2Cx,ENABLE); //发送起始信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT )==ERROR); //检测EV5事件
I2C_Send7bitAddress(I2Cx,SlaveAddr+1,I2C_Direction_Receiver); //发送设备读地址(接收模式)
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR); //检测EV6事件
I2C_AcknowledgeConfig(I2Cx,DISABLE); //发送非应答信号
I2C_GenerateSTOP(I2Cx,ENABLE); //发送停止信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR); //检测EV7事件
data=I2C_ReceiveData(I2Cx); /*读数据*/
I2C_AcknowledgeConfig(I2Cx,ENABLE); //重新开启应答信号
return data;
}
/*
* 函数名称: IIC_ReadTwoByte
* 功能描述: 从指定地址读取16bit数据
* 传入参数: I2Cx:要使用的IIC号
* SlaveAddr:从机地址
* ReadAddr:内存单元地址
* 传出参数: 无
* 返回值: data:从指定地址读取到的16bit数据
*/
short IIC_ReadTwoByte(I2C_TypeDef* I2Cx,uint16_t SlaveAddr,uint8_t ReadAddr)
{
short data;
uint8_t msb,lsb;
u32 Num_ByteToRead=2;
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); //检查IIC总线是否忙碌,等待空闲
I2C_GenerateSTART(I2Cx,ENABLE);//发送起始信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT )==ERROR);//检测EV5事件
I2C_Send7bitAddress(I2Cx,SlaveAddr,I2C_Direction_Transmitter);//发送设备写地址
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR);//检测EV6事件等待从机应答
I2C_SendData(I2Cx,ReadAddr);//发送要操作设备内部存储器的地址
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR);//检测EV8事件
I2C_GenerateSTART(I2Cx,ENABLE);//发送起始信号
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT )==ERROR);//检测EV5事件
I2C_Send7bitAddress(I2Cx,SlaveAddr+1,I2C_Direction_Receiver);//发送设备读地址
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR);//检测EV6事件
while(Num_ByteToRead--)
{
if( Num_ByteToRead==0)//是否是最后一个字节,若是则发送非应答信号
{
I2C_AcknowledgeConfig(I2Cx,DISABLE);//发送非应答信号
I2C_GenerateSTOP(I2Cx,ENABLE);//发送停止信号
}
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR);//检测EV7事件
if( Num_ByteToRead==1)msb=I2C_ReceiveData(I2Cx);
if( Num_ByteToRead==0)lsb=I2C_ReceiveData(I2Cx);
}
//重新开启应答信号
I2C_AcknowledgeConfig(I2Cx,ENABLE);
data = msb*256 + lsb;
return data;
}