STM32 模拟IIC源代码 多个I2C减少冗余代码

当设计中使用I2C的数量多于1个时,其底层I2C的代码逻辑都是一样的,只有IO口变了,为此还要复制粘贴、修改IO,不仅费时,而且还浪费片内资源,因此可以使用指针来重复执行IIC底层代码,实现一个代码,多个IO使用。
注意:使用什么IO口,一定要打开其IO时钟,同时配置为输出开漏模式!!!
使用例程在最下面

Stm32f30x_SMLT_I2C.h



#ifndef __Stm32f30x_SMLT_I2C_H
#define __Stm32f30x_SMLT_I2C_H

//========================= Include ===============================================================

#include "stm32f30x.h"

//========================= Variable ==============================================================

typedef struct
{
	GPIO_TypeDef* SDA_GPIO;	//SDA的GPIO组地址
	GPIO_TypeDef* SCL_GPIO;	//SCL的GPIO组地址
	uint32_t SDA_SBIT;		//SDA 在 BSRR寄存器 中的置位
	uint32_t SDA_RBIT;		//SDA 在 BSRR寄存器 中的复位
	uint32_t SCL_SBIT;		//SCL 在 BSRR寄存器 中的置位
	uint32_t SCL_RBIT;		//SCL 在 BSRR寄存器 中的复位
	uint32_t SDA_MODER;		//SDA 在 MODER寄存器 中的配置位
	uint32_t SDA_MODER_0;	//SDA 在 MODER寄存器 中的配置位低位
	uint32_t SDA_MODER_1;	//SDA 在 MODER寄存器 中的配置位高位
	uint8_t SCL_Delay;		//SCL的延时参数 调整波特率 越大波特率越大
}I2C_Struct;

extern I2C_Struct S_I2C_IO[2];//------------------------------------- 修改处
//(想要3个的话,数组添加,下面的define也要添加,初始化函数S_I2C_Init中也要添加)

//========================= I2C1_Define ================================================================
//--------------------------SDA-------------------------------------- 修改处
#define S_I2C1_SDA_GPIO		GPIOE
#define S_I2C1_SDA_BIT		0
//--------------------------SCL-------------------------------------- 修改处
#define S_I2C1_SCL_GPIO		GPIOE
#define S_I2C1_SCL_BIT		1
#define S_I2C1_SCL_DELAY	0x80
//还需配置结构体初始化函数 S_I2C_Init 别忘了打开时钟及开漏配置

//========================= I2C2_Define ================================================================
//--------------------------SDA-------------------------------------- 修改处
#define S_I2C2_SDA_GPIO		GPIOE
#define S_I2C2_SDA_BIT		11
//--------------------------SCL-------------------------------------- 修改处
#define S_I2C2_SCL_GPIO		GPIOB
#define S_I2C2_SCL_BIT		13
#define S_I2C2_SCL_DELAY	0x10
//还需配置结构体初始化函数 S_I2C_Init 别忘了打开时钟及开漏配置

// //========================= I2Cx_Define ================================================================
// //--------------------------SDA-------------------------------------- 修改处
// #define S_I2Cx_SDA_GPIO		GPIOx
// #define S_I2Cx_SDA_BIT		x
// //--------------------------SCL-------------------------------------- 修改处
// #define S_I2Cx_SCL_GPIO		GPIOx
// #define S_I2Cx_SCL_BIT		x
// #define S_I2Cx_SCL_DELAY		x
// //添加在此添加


//========================= Function ==============================================================

void S_I2C_Init(void);//--------------------------------------------- 修改处

void S_I2C_Start(I2C_Struct I2C_temp);
void S_I2C_Stop(I2C_Struct I2C_temp);
uint8_t S_I2C_SendByte(I2C_Struct I2C_temp, uint8_t byte);
uint8_t S_I2C_ReceiveByte(I2C_Struct I2C_temp, uint8_t nack);
uint8_t S_I2C_WriteRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t data);
uint8_t S_I2C_ReadRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ);
uint8_t S_I2C_PointerRead(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ);

//========================= Define ================================================================
//通过宏定义将IO结构体直接放入基础函数中
//-------------------------- I2C1 -----------------------------------
#define S_I2C1_Start()											S_I2C_Start(S_I2C_IO[0])
#define S_I2C1_Stop()											S_I2C_Stop(S_I2C_IO[0])
#define S_I2C1_SendByte(byte)									S_I2C_SendByte(S_I2C_IO[0], byte)
#define S_I2C1_ReceiveByte(nack)								S_I2C_ReceiveByte(S_I2C_IO[0], nack)
#define S_I2C1_WriteRegister(addr, regAddr, data)				S_I2C_WriteRegister(S_I2C_IO[0], addr, regAddr, data)
#define S_I2C1_ReadRegister(addr, regAddr, amount, data, typ)	S_I2C_ReadRegister(S_I2C_IO[0], addr, regAddr, amount, data, typ)
#define S_I2C1_PointerRead(addr, regAddr, amount, data, typ)	S_I2C_PointerRead(S_I2C_IO[0], addr, regAddr, amount, data, typ)

//-------------------------- I2C2 -----------------------------------
#define S_I2C2_Start()											S_I2C_Start(S_I2C_IO[1])
#define S_I2C2_Stop()											S_I2C_Stop(S_I2C_IO[1])
#define S_I2C2_SendByte(byte)									S_I2C_SendByte(S_I2C_IO[1], byte)
#define S_I2C2_ReceiveByte(nack)								S_I2C_ReceiveByte(S_I2C_IO[1], nack)
#define S_I2C2_WriteRegister(addr, regAddr, data)				S_I2C_WriteRegister(S_I2C_IO[1], addr, regAddr, data)
#define S_I2C2_ReadRegister(addr, regAddr, amount, data, typ)	S_I2C_ReadRegister(S_I2C_IO[1], addr, regAddr, amount, data, typ)
#define S_I2C2_PointerRead(addr, regAddr, amount, data, typ)	S_I2C_PointerRead(S_I2C_IO[1], addr, regAddr, amount, data, typ)

//-------------------------- Another --------------------------------
#define ACK		0
#define NACK	1

#define FAILED	0
#define SUCCEED	1

#define ARRAY	0
#define STRUCT	1
//=================================================================================================

#endif

Stm32f30x_SMLT_I2C.c


#include "Stm32f30x_SMLT_I2C.h"

I2C_Struct S_I2C_IO[2];//IO口结构体,通过.h文件定义使用的引脚

/**
 * @description: I2C结构体IO初始化
 * @param {I2C_Struct*} I2C_temp	I2C的IO结构体
 * @param {GPIO_TypeDef*}	SDA_GPIO		I2C SDA GPIO(GPIOA~GPIOx)
 * @param {uint8_t}			SDA_BIT			I2C SDA引脚号(1~16)
 * @param {GPIO_TypeDef*}	SCL_GPIO		I2C SCL GPIO(GPIOA~GPIOx)
 * @param {uint8_t}			SCL_BIT			I2C SCL引脚号(1~16)
 * @param {uint8_t}			SCL_Delay		I2C SCL时钟延时(0x00~0xff)越大波特率越低
 * @return {*}
 */
void S_I2C_Struct_Init(I2C_Struct* I2C_temp, GPIO_TypeDef* SDA_GPIO, uint8_t SDA_BIT, GPIO_TypeDef* SCL_GPIO, uint8_t SCL_BIT, uint8_t SCL_Delay)
{
	I2C_temp->SDA_GPIO = SDA_GPIO;
	I2C_temp->SCL_GPIO = SCL_GPIO;
	I2C_temp->SDA_SBIT = (0x00000001 << SDA_BIT);
	I2C_temp->SDA_RBIT = (0x00010000 << SDA_BIT);
	I2C_temp->SCL_SBIT = (0x00000001 << SCL_BIT);
	I2C_temp->SCL_RBIT = (0x00010000 << SCL_BIT);
	I2C_temp->SDA_MODER = 0x00000003 << (SDA_BIT << 1);
	I2C_temp->SDA_MODER_0 = 0x00000001 << (SDA_BIT << 1);
	I2C_temp->SDA_MODER_1 = 0x00000002 << (SDA_BIT << 1);
	I2C_temp->SCL_Delay = SCL_Delay;
}

/**
 * @description: I2C结构体总初始化,将计算的各个变量存入结构体中
 * @param {*}
 * @return {*}
 */
void S_I2C_Init(void)
{
	S_I2C_Struct_Init(&S_I2C_IO[0], S_I2C1_SDA_GPIO, S_I2C1_SDA_BIT, S_I2C1_SCL_GPIO, S_I2C1_SCL_BIT, S_I2C1_SCL_DELAY);
	S_I2C_Struct_Init(&S_I2C_IO[1], S_I2C2_SDA_GPIO, S_I2C2_SDA_BIT, S_I2C2_SCL_GPIO, S_I2C2_SCL_BIT, S_I2C2_SCL_DELAY);
	// S_I2C_Struct_Init(&S_I2C_IO[x], S_I2Cx_SDA_GPIO, S_I2Cx_SDA_BIT, S_I2Cx_SCL_GPIO, S_I2Cx_SCL_BIT, S_I2Cx_SCL_DELAY);//添加在此添加
}

/**
 * @description: I2C时钟延时,调整波特率
 * @param {*}
 * @return {*}
 */
void S_I2C_Delay(uint8_t temp)
{
    for ( ; temp; temp--)
	{
		/* code */
	}
}

/**
 * @description: 产生起始信号
 * @param {I2C_Struct} I2C_temp I2C_IO结构体
 * @return {*}
 */
void S_I2C_Start(I2C_Struct I2C_temp)
{
	I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;
	I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
	I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
}

/**
 * @description: 产生停止信号
 * @param {I2C_Struct} I2C_temp
 * @return {*}
 */
void S_I2C_Stop(I2C_Struct I2C_temp)
{
	I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
	I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
	I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
}

/**
 * @description: 发送一个字节数据
 * @param {I2C_Struct} I2C_temp	I2C_IO结构体
 * @param {uint8_t} byte	数据
 * @return {uint8_t}		NACK
 * 							ACK
 */
uint8_t S_I2C_SendByte(I2C_Struct I2C_temp, uint8_t byte)
{
	uint8_t temp = 0x00;
	for(uint8_t i = 0x80; i; i >>= 1)
	{
		I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
		if(byte & i)
		{
			I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;
		}
		else
		{
			I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;
		}
        S_I2C_Delay(I2C_temp.SCL_Delay);
		I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;
        S_I2C_Delay(I2C_temp.SCL_Delay);
	}
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
	I2C_temp.SDA_GPIO->MODER &= ~I2C_temp.SDA_MODER;
	S_I2C_Delay(I2C_temp.SCL_Delay);
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;
	if(I2C_temp.SDA_GPIO -> IDR & I2C_temp.SDA_SBIT)
	{
		temp = NACK;
	}
	else
	{
		temp = ACK;
	}
    S_I2C_Delay(I2C_temp.SCL_Delay);
	I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;
	I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
	return temp;
}

/**
 * @description: 接收一个字节数据
 * @param {I2C_Struct} I2C_temp	I2C_IO结构体
 * @param {uint8_t} nack	接收后结束要发送的应答信号
 * 							NACK
 * 							ACK
 * @return {uint8_t}	接收到的字节
 */
uint8_t S_I2C_ReceiveByte(I2C_Struct I2C_temp, uint8_t nack)
{
	uint8_t byte = 0x00;
	I2C_temp.SDA_GPIO->MODER &= ~I2C_temp.SDA_MODER;
	for (uint8_t i = 8; i; i--)
	{
		I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
        S_I2C_Delay(I2C_temp.SCL_Delay);
		byte <<= 1;
		I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;
		if(I2C_temp.SDA_GPIO -> IDR & I2C_temp.SDA_SBIT)
		{
			byte |= 0x01;
		}
        S_I2C_Delay(I2C_temp.SCL_Delay);
	}
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
	I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;
	I2C_temp.SDA_GPIO->MODER |= I2C_temp.SDA_MODER_0;
	if(nack)
		I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_SBIT;
	else
		I2C_temp.SDA_GPIO->BSRR |= I2C_temp.SDA_RBIT;
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_RBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
	I2C_temp.SCL_GPIO->BSRR |= I2C_temp.SCL_SBIT;
    S_I2C_Delay(I2C_temp.SCL_Delay);
	return byte;
}


/**
 * @description: 写一个字节的寄存器
 * @param {I2C_Struct} I2C_temp	I2C_IO结构体
 * @param {uint8_t} addr	器件地址(0x00~0x7f)
 * @param {uint8_t} regAddr	寄存器地址(0x00~0xff)
 * @param {uint8_t} data	数据
 * @return {uint8_t}	FAILED	失败
 * 						SUCCEED	成功
 */
uint8_t S_I2C_WriteRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t data)
{
	addr <<= 1;
	S_I2C_Start(I2C_temp);
	if(S_I2C_SendByte(I2C_temp, addr) == NACK)
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	if(S_I2C_SendByte(I2C_temp, regAddr) == NACK)
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	if(S_I2C_SendByte(I2C_temp, data) == NACK)
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	S_I2C_Stop(I2C_temp);
	return SUCCEED;
}


/**
 * @description: 		读取器件,读取格式:器件读-寄存器地址-读取数据
 * @param {I2C_Struct} I2C_temp	I2C_IO结构体
 * @param {uint8_t} addr	器件地址(0x00~0x7f)
 * @param {uint8_t} regAddr	寄存器地址(0x00~0xff)
 * @param {uint8_t} amount	读取数据数量(0x00~0xff)
 * @param {uint8_t*} data	返回数据指针
 * @param {uint8_t} typ		数据指针类型(由于结构体和数组存储方式不一样,因此需要区分)
 * 						ARRAY	数组
 * 						STRUCT	结构体
 * @return {*}			FAILD   读取失败 数据无效
 * 						SUCCEED 读取成功 数据有效
 */
uint8_t S_I2C_ReadRegister(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ)
{
	S_I2C_Start(I2C_temp);
	addr = (addr << 1) | 0x01;
	if(S_I2C_SendByte(I2C_temp, addr) == NACK)
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	if(S_I2C_SendByte(I2C_temp, regAddr) == NACK)
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	for(amount -= 1;amount;amount --)
	{
		*data = S_I2C_ReceiveByte(I2C_temp, ACK);
		if(typ == ARRAY)
			data ++;
		else
			data --;
	}
	*data = S_I2C_ReceiveByte(I2C_temp, NACK);
	S_I2C_Stop(I2C_temp);
	return SUCCEED;
}

/**
 * @description: 		读取器件,读取格式:器件写-寄存器地址-器件读-读取数据
 * @param {I2C_Struct} I2C_temp	I2C_IO结构体
 * @param {uint8_t} addr	器件地址(0x00~0x7f)
 * @param {uint8_t} regAddr	寄存器地址(0x00~0xff)
 * @param {uint8_t} amount	读取数据数量(0x00~0xff)
 * @param {uint8_t*} data	返回数据指针
 * @param {uint8_t} typ		数据指针类型(由于结构体和数组存储方式不一样,因此需要区分)
 * 						ARRAY	数组
 * 						STRUCT	结构体
 * @return {uint8_t}	FAILD   读取失败 数据无效
 * 						SUCCEED 读取成功 数据有效
 */
uint8_t S_I2C_PointerRead(I2C_Struct I2C_temp, uint8_t addr, uint8_t regAddr, uint8_t amount, uint8_t* data, uint8_t typ)
{
	addr <<= 1;
	S_I2C_Start(I2C_temp);
	if(S_I2C_SendByte(I2C_temp, addr) == NACK)
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	if(S_I2C_SendByte(I2C_temp, regAddr) == NACK)
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	S_I2C_Stop(I2C_temp);
	
	addr |= 0x01;
	S_I2C_Start(I2C_temp);
	if(S_I2C_SendByte(I2C_temp, addr) == NACK)	//NACK
	{
		S_I2C_Stop(I2C_temp);
		return FAILED;
	}
	for(amount -= 1;amount;amount --)
	{
		*data = S_I2C_ReceiveByte(I2C_temp, ACK);
		if(typ == ARRAY)
			data ++;
		else
			data --;
	}
	*data = S_I2C_ReceiveByte(I2C_temp, NACK);
	S_I2C_Stop(I2C_temp);
	return SUCCEED;
}

使用方法

void main(void)
{
	CLOCK_Init();
	GPIO_Init();
	S_I2C_Init();//初始化结构体,在宏定义中修改引脚等定义
	//接下来就可以调用I2C函数了
}
  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
STM32模拟IIC代码是在STM32单片机上实现IIC通讯协议的模拟仿真代码。下面以F103为例,以软件模拟IIC通信为主要讲解。 首先,我们需要定义IIC相关的GPIO引脚及其功能,以及一些IIC初始化函数。 ```c GPIO_InitTypeDef GPIO_InitStruct; void IIC_Init(void) { //使能GPIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //配置IIC_SCL引脚 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); //配置IIC_SDA引脚 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); //初始化IIC总线 IIC_Start(); IIC_Stop(); } void IIC_Start(void) { IIC_SDA_OUT(); IIC_SCL_HIGH(); IIC_SDA_HIGH(); IIC_DELAY(); IIC_SDA_LOW(); IIC_DELAY(); IIC_SCL_LOW(); } void IIC_Stop(void) { IIC_SDA_OUT(); IIC_SCL_LOW(); IIC_SDA_LOW(); IIC_DELAY(); IIC_SCL_HIGH(); IIC_DELAY(); IIC_SDA_HIGH(); } void IIC_SendByte(uint8_t data) { uint8_t i; IIC_SDA_OUT(); for (i = 0; i < 8; i++) { IIC_SCL_LOW(); if ((data & 0x80) == 0x80) IIC_SDA_HIGH(); else IIC_SDA_LOW(); data <<= 1; IIC_DELAY(); IIC_SCL_HIGH(); IIC_DELAY(); } IIC_SCL_LOW(); } uint8_t IIC_ReceiveByte(void) { uint8_t i, data = 0; IIC_SDA_IN(); for (i = 0; i < 8; i++) { IIC_SCL_LOW(); IIC_DELAY(); IIC_SCL_HIGH(); data <<= 1; if (IIC_READ_SDA()) data |= 0x01; IIC_DELAY(); } IIC_SCL_LOW(); return data; } ``` 以上代码模拟IIC基本操作的函数,包括初始化IIC总线、启动和停止信号的发送、发送和接收数据等。其中,根据实际需求可能需要根据具体的GPIO引脚和时钟配置来修改。 在使用模拟IIC通信时,需要注意的是,STM32I2C外设与模拟IIC通信并不相同。I2C外设直接在硬件层面上实现了I2C通信,而模拟IIC需要通过GPIO口的软件控制来模拟实现。所以在使用STM32模拟IIC时,需要禁用I2C外设,并根据实际需求修改代码中的引脚定义。 以上是关于STM32模拟IIC代码的基本讲解,通过使用这些函数,我们可以在STM32单片机上实现模拟IIC通信。当然,具体的代码实现可能会因为不同的项目需求而有所变化,需要根据实际情况进行修改与优化。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值