STM32 I2C 编程实践

1. I2C 固件库简介

I2C 初始化结构体

typedef struct {
	uint32_t I2C_ClockSpeed; /*!< 设置 SCL 时钟频率,此值要低于 400000*/
	uint16_t I2C_Mode; /*!< 指定工作模式,可选 I2C 模式及 SMBUS 模式 */
	uint16_t I2C_DutyCycle; /*指定时钟占空比,可选 low/high = 2:1 及 16:9 模式*/
	uint16_t I2C_OwnAddress1; /*!< 指定自身的 I2C 设备地址 */
	uint16_t I2C_Ack; /*!< 使能或关闭响应(一般都要使能) */
	uint16_t I2C_AcknowledgedAddress; /*!< 指定地址的长度,可为 7 位及 10 位 */
} I2C_InitTypeDef;

2. I2C—读写 EEPROM 实验

2.1 硬件设计

STM32 I2C 编程实践

2.2 软件设计

2.2.1 编程要点

(1) 配置通讯使用的目标引脚为开漏模式;

(2) 使能 I2C 外设的时钟;

(3) 配置 I2C 外设的模式、地址、速率等参数并使能 I2C 外设;

(4) 编写基本 I2C 按字节收发的函数;

(5) 编写读写 EEPROM 存储内容的函数;

(6) 编写测试程序,对读写数据进行校验。

2.2.2 代码分析

I2C 硬件配置相关的宏

/**************************I2C 参数定义,I2C1 或 I2C2*********************/
#define EEPROM_I2Cx I2C1
#define EEPROM_I2C_APBxClock_FUN RCC_APB1PeriphClockCmd
#define EEPROM_I2C_CLK RCC_APB1Periph_I2C1
#define EEPROM_I2C_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define EEPROM_I2C_GPIO_CLK RCC_APB2Periph_GPIOB
#define EEPROM_I2C_SCL_PORT GPIOB
#define EEPROM_I2C_SCL_PIN GPIO_Pin_6
#define EEPROM_I2C_SDA_PORT GPIOB
#define EEPROM_I2C_SDA_PIN GPIO_Pin_7

/* STM32 I2C 快速模式 */
#define I2C_Speed 400000 //*

/* 这个地址只要与 STM32 外挂的 I2C 器件地址不一样即可 */
#define I2Cx_OWN_ADDRESS7 0X0A

/* AT24C01/02 每页有 8 个字节 */
#define I2C_PageSize 8

初始化 I2C 的 GPIO

static void I2C_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* 使能与 I2C 有关的时钟 */
	EEPROM_I2C_APBxClock_FUN ( EEPROM_I2C_CLK, ENABLE );
	EEPROM_I2C_GPIO_APBxClock_FUN ( EEPROM_I2C_GPIO_CLK, ENABLE );

	/* I2C_SCL、I2C_SDA*/
	GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出
	GPIO_Init(EEPROM_I2C_SCL_PORT, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出
	GPIO_Init(EEPROM_I2C_SDA_PORT, &GPIO_InitStructure);
}

配置 I2C 的模式

/**
* @brief I2C 工作模式配置
* @param 无
* @retval 无
*/
static void I2C_Mode_Configu(void)
{
	I2C_InitTypeDef I2C_InitStructure;

	/* I2C 配置 */
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

	/* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

	I2C_InitStructure.I2C_OwnAddress1 =I2Cx_OWN_ADDRESS7;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;

	/* I2C 的寻址模式 */
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

	/* 通信速率 */
	I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;

	/* I2C 初始化 */
	I2C_Init(EEPROM_I2Cx, &I2C_InitStructure);

	/* 使能 I2C */
	I2C_Cmd(EEPROM_I2Cx, ENABLE);
}


/**
* @brief I2C 外设(EEPROM)初始化
* @param 无
* @retval 无
*/
void I2C_EE_Init(void)
{
	I2C_GPIO_Config();

	I2C_Mode_Configu();

	/* 根据头文件 i2c_ee.h 中的定义来选择 EEPROM 要写入的设备地址 */
	/* 选择 EEPROM Block0 来写入 */
	EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
}

向 EEPROM 写入一个字节的数据

/***************************************************************/

/**
* @brief I2C 等待事件超时的情况下会调用这个函数来处理
* @param errorCode:错误代码,可以用来定位是哪个环节出错.
* @retval 返回 0,表示 IIC 读取失败.
*/
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{
	/* 使用串口 printf 输出错误信息,方便调试 */
	EEPROM_ERROR("I2C 等待超时!errorCode = %d",errorCode);
	return 0;
}
/**
* @brief 写一个字节到 I2C EEPROM 中
* @param pBuffer:缓冲区指针
* @param WriteAddr:写地址
* @retval 正常返回 1,异常返回 0
*/
uint32_t I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
	/* 产生 I2C 起始信号 */
	I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);

	/*设置超时等待时间*/
	I2CTimeout = I2CT_FLAG_TIMEOUT;
	/* 检测 EV5 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
	}

	/* 发送 EEPROM 设备地址 */
	I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);

	I2CTimeout = I2CT_FLAG_TIMEOUT;
	/* 检测 EV6 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx,
	I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
	}

	/* 发送要写入的 EEPROM 内部地址(即 EEPROM 内部存储器的地址) */
	I2C_SendData(EEPROM_I2Cx, WriteAddr);

	I2CTimeout = I2CT_FLAG_TIMEOUT;
	/* 检测 EV8 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx,
	I2C_EVENT_MASTER_BYTE_TRANSMITTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
	}
	/* 发送一字节要写入的数据 */
	I2C_SendData(EEPROM_I2Cx, *pBuffer);

	I2CTimeout = I2CT_FLAG_TIMEOUT;
	/* 检测 EV8 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx,
	I2C_EVENT_MASTER_BYTE_TRANSMITTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
	}

	/* 发送停止信号 */
	I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);

	return 1;
}

多字节写入及状态等待

/**
* @brief 将缓冲区中的数据写到 I2C EEPROM 中,采用单字节写入的方式,
速度比页写入慢
* @param pBuffer:缓冲区指针
* @param WriteAddr:写地址
* @param NumByteToWrite:写的字节数
* @retval 无
*/
uint8_t I2C_EE_ByetsWrite(uint8_t* pBuffer,uint8_t WriteAddr,
	uint16_t NumByteToWrite)
{
	uint16_t i;
	uint8_t res;

	/*每写一个字节调用一次 I2C_EE_ByteWrite 函数*/
	for (i=0; i<NumByteToWrite; i++)
	{
		/*等待 EEPROM 准备完毕*/
		I2C_EE_WaitEepromStandbyState();
		/*按字节写入数据*/
		res = I2C_EE_ByteWrite(pBuffer++,WriteAddr++);
	}
	return res;
}

/**
* @brief 等待 EEPROM 到准备状态
* @param 无
* @retval 无
*/
void I2C_EE_WaitEepromStandbyState(void)
{
	vu16 SR1_Tmp = 0;

	do {
		/* 发送起始信号 */
		I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);

		/* 读 I2C1 SR1 寄存器 */
		SR1_Tmp = I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1);

		/* 发送 EEPROM 地址 + 写方向 */
		I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS,
		I2C_Direction_Transmitter);
	}
	// SR1 位 1 ADDR:1 表示地址发送成功,0 表示地址发送没有结束
	// 等待地址发送成功
	while (!(I2C_ReadRegister(EEPROM_I2Cx, I2C_Register_SR1) & 0x0002));

	/* 清除 AF 位 */
	I2C_ClearFlag(EEPROM_I2Cx, I2C_FLAG_AF);
	/* 发送停止信号 */
	I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
}

EEPROM 的页写入

/**
* @brief 在 EEPROM 的一个写循环中可以写多个字节,但一次写入的字节数
* 不能超过 EEPROM 页的大小,AT24C02 每页有 8 个字节
* @param
* @param pBuffer:缓冲区指针
* @param WriteAddr:写地址
* @param NumByteToWrite:要写的字节数要求 NumByToWrite 小于页大小
* @retval 正常返回 1,异常返回 0
*/
uint8_t I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr,
uint8_t NumByteToWrite)
{
	I2CTimeout = I2CT_LONG_TIMEOUT;

	while (I2C_GetFlagStatus(EEPROM_I2Cx, I2C_FLAG_BUSY))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(4);
	}

	/* 产生 I2C 起始信号 */
	I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV5 事件并清除标志 */
	while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);
	}

	/* 发送 EEPROM 设备地址 */
	I2C_Send7bitAddress(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_Direction_Transmitter);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV6 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx,
	I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
	}
	/* 发送要写入的 EEPROM 内部地址(即 EEPROM 内部存储器的地址) */
	I2C_SendData(EEPROM_I2Cx, WriteAddr);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV8 事件并清除标志*/
	while (! I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(7);
	}
	/* 循环发送 NumByteToWrite 个数据 */
	while (NumByteToWrite--)
	{
		/* 发送缓冲区中的数据 */
		I2C_SendData(EEPROM_I2Cx, *pBuffer);

		/* 指向缓冲区中的下一个数据 */
		pBuffer++;

		I2CTimeout = I2CT_FLAG_TIMEOUT;

		/* 检测 EV8 事件并清除标志*/
		while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
		{
			if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(8);
		}
	}
	/* 发送停止信号 */
	I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
	return 1;
}

快速写入多字节

/**
* @brief 将缓冲区中的数据写到 I2C EEPROM 中
* @param
* @arg pBuffer:缓冲区指针
* @arg WriteAddr:写地址
* @arg NumByteToWrite:写的字节数
* @retval 无
*/
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)
{
	u8 NumOfPage=0,NumOfSingle=0,Addr =0,count=0,temp =0;

	/*mod 运算求余,若 writeAddr 是 I2C_PageSize 整数倍,
	运算结果 Addr 值为 0*/
	Addr = WriteAddr % I2C_PageSize;

	/*差 count 个数据值,刚好可以对齐到页地址*/
	count = I2C_PageSize - Addr;

	/*计算出要写多少整数页*/
	NumOfPage = NumByteToWrite / I2C_PageSize;

	/*mod 运算求余,计算出剩余不满一页的字节数*/
	NumOfSingle = NumByteToWrite % I2C_PageSize;

	// Addr=0,则 WriteAddr 刚好按页对齐 aligned
	// 这样就很简单了,直接写就可以,写完整页后
	// 把剩下的不满一页的写完即可
	if (Addr == 0) {
		/* 如果 NumByteToWrite < I2C_PageSize */
		if (NumOfPage == 0) {
			I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
			I2C_EE_WaitEepromStandbyState();
		}
		/* 如果 NumByteToWrite > I2C_PageSize */
		else {
			/*先把整数页都写了*/
			while (NumOfPage--) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
				I2C_EE_WaitEepromStandbyState();
				WriteAddr += I2C_PageSize;
				pBuffer += I2C_PageSize;
			}
			/*若有多余的不满一页的数据,把它写完*/
			if (NumOfSingle!=0) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
				I2C_EE_WaitEepromStandbyState();
			}
		}
	}
	// 如果 WriteAddr 不是按 I2C_PageSize 对齐
	// 那就算出对齐到页地址还需要多少个数据,然后
	// 先把这几个数据写完,剩下开始的地址就已经对齐
	// 到页地址了,代码重复上面的即可
	else {
		/* 如果 NumByteToWrite < I2C_PageSize */
		if (NumOfPage== 0) {
			/*若 NumOfSingle>count,当前面写不完,要写到下一页*/
			if (NumOfSingle > count) {
				// temp 的数据要写到写一页
				temp = NumOfSingle - count;

				I2C_EE_PageWrite(pBuffer, WriteAddr, count);
				I2C_EE_WaitEepromStandbyState();
				WriteAddr += count;
				pBuffer += count;

				I2C_EE_PageWrite(pBuffer, WriteAddr, temp);
				I2C_EE_WaitEepromStandbyState();
			} else { /*若 count 比 NumOfSingle 大*/
				I2C_EE_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
				I2C_EE_WaitEepromStandbyState();
			}
		}
		/* 如果 NumByteToWrite > I2C_PageSize */
		else {
			/*地址不对齐多出的 count 分开处理,不加入这个运算*/
			NumByteToWrite -= count;
			NumOfPage = NumByteToWrite / I2C_PageSize;
			NumOfSingle = NumByteToWrite % I2C_PageSize;

			/*先把 WriteAddr 所在页的剩余字节写了*/
			if (count != 0) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, count);
				I2C_EE_WaitEepromStandbyState();

				/*WriteAddr 加上 count 后,地址就对齐到页了*/
				WriteAddr += count;
				pBuffer += count;
			}
			/*把整数页都写了*/
			while (NumOfPage--) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
				I2C_EE_WaitEepromStandbyState();
				WriteAddr += I2C_PageSize;
				pBuffer += I2C_PageSize;
			}
			/*若有多余的不满一页的数据,把它写完*/
			if (NumOfSingle != 0) {
			I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
			I2C_EE_WaitEepromStandbyState();
			}
		}
	}
}

从 EEPROM 读取数据

/**
* @brief 从 EEPROM 里面读取一块数据
* @param pBuffer:存放从 EEPROM 读取的数据的缓冲区指针
* @param ReadAddr:接收数据的 EEPROM 的地址
* @param NumByteToRead:要从 EEPROM 读取的字节数
* @retval 正常返回 1,异常返回 0
*/
uint8_t I2C_EE_BufferRead(uint8_t* pBuffer, uint8_t ReadAddr,
	u16 NumByteToRead)
{
	I2CTimeout = I2CT_LONG_TIMEOUT;

	while (I2C_GetFlagStatus(EEPROM_I2Cx, I2C_FLAG_BUSY))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);
	}

	/* 产生 I2C 起始信号 */
	I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV5 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);
	}

	/* 发送 EEPROM 设备地址 */
	I2C_Send7bitAddress(EEPROM_I2Cx,EEPROM_ADDRESS,I2C_Direction_Transmitter);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV6 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx,
													I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);
	}
	/*通过重新设置 PE 位清除 EV6 事件 */
	I2C_Cmd(EEPROM_I2Cx, ENABLE);

	/* 发送要读取的 EEPROM 内部地址(即 EEPROM 内部存储器的地址) */
	I2C_SendData(EEPROM_I2Cx, ReadAddr);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV8 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx,I2C_EVENT_MASTER_BYTE_TRANSMITTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);
	}
	/* 产生第二次 I2C 起始信号 */
	I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV5 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);
	}
	/* 发送 EEPROM 设备地址 */
	I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Receiver);

	I2CTimeout = I2CT_FLAG_TIMEOUT;

	/* 检测 EV6 事件并清除标志*/
	while (!I2C_CheckEvent(EEPROM_I2Cx,
													I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
	{
		if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);
	}
	/* 读取 NumByteToRead 个数据*/
	while (NumByteToRead)
	{
		/*若 NumByteToRead=1,表示已经接收到最后一个数据了,
		发送非应答信号,结束传输*/
		if (NumByteToRead == 1)
		{
			/* 发送非应答信号 */
			I2C_AcknowledgeConfig(EEPROM_I2Cx, DISABLE);

			/* 发送停止信号 */
			I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
		}

		I2CTimeout = I2CT_LONG_TIMEOUT;
		while (I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)==0)
		{
			if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
		}
		{
			/*通过 I2C,从设备中读取一个字节的数据 */
			*pBuffer = I2C_ReceiveData(EEPROM_I2Cx);

			/* 存储数据的指针指向下一个地址 */
			pBuffer++;

			/* 接收数据自减 */
			NumByteToRead--;
		}
	}

	/* 使能应答,方便下一次 I2C 传输 */
	I2C_AcknowledgeConfig(EEPROM_I2Cx, ENABLE);
	return 1;
}

EEPROM 读写测试函数

#define  EEP_Firstpage      0x00
uint8_t I2c_Buf_Write[256];
uint8_t I2c_Buf_Read[256];
uint8_t I2C_Test(void);

/**
* @brief I2C(AT24C02)读写测试
* @param 无
* @retval 正常返回 1 ,不正常返回 0
*/
uint8_t I2C_Test(void)
{
	u16 i;
	EEPROM_INFO("写入的数据");

	for ( i=0; i<=255; i++ ) //填充缓冲
	{
		I2c_Buf_Write[i] = i;

		printf("0x%02X ", I2c_Buf_Write[i]);
		if (i%16 == 15)
		printf("\n\r");
	}

	//将 I2c_Buf_Write 中顺序递增的数据写入 EERPOM 中
	//页写入方式
	// I2C_EE_BufferWrite( I2c_Buf_Write, EEP_Firstpage, 256);
	//字节写入方式
	I2C_EE_ByetsWrite( I2c_Buf_Write, EEP_Firstpage, 256);

	EEPROM_INFO("写结束");

	EEPROM_INFO("读出的数据");
	//将 EEPROM 读出数据顺序保持到 I2c_Buf_Read 中
	I2C_EE_BufferRead(I2c_Buf_Read, EEP_Firstpage, 256);

	//将 I2c_Buf_Read 中的数据通过串口打印
	for (i=0; i<256; i++)
	{
		if (I2c_Buf_Read[i] != I2c_Buf_Write[i])
		{
		printf("0x%02X ", I2c_Buf_Read[i]);
		EEPROM_ERROR("错误:I2C EEPROM 写入与读出的数据不一致");
		return 0;
		}
		printf("0x%02X ", I2c_Buf_Read[i]);
		if (i%16 == 15)
		printf("\n\r");

	}
	EEPROM_INFO("I2C(AT24C02)读写测试成功");
	return 1;
}

main 函数

int main(void)
{
	LED_GPIO_Config();

	LED_BLUE;
	/*初始化 USART1*/
	USART_Config();

	printf("\r\n 欢迎使用野火 STM32 F103 开发板。\r\n");

	printf("\r\n 这是一个 I2C 外设(AT24C02)读写测试例程 \r\n");

	/* I2C 外设(AT24C02)初始化 */
	I2C_EE_Init();

	if (I2C_Test() ==1)
	{
		LED_GREEN;
	}
	else
	{
		LED_RED;
	}

	while (1)
	{
	}

}

实测有效

上一篇:基于单片机射频密码锁门禁刷卡开锁系统射频卡IC卡设计


下一篇:STM32F103_I2C硬件模拟