STM32F407-IIC通讯与EEPROM-1-IIC固件库

STM32内部自带有IIC通讯,可以直接使用它的固件操作EEPROM

IIC的初始化函数

#include "my_eeprom.h"

#define STM32_I2C_OWN_ADDR 					0x1F
#define EEPROM_I2C_ADDR							0xA0
#define TIME_OUT                    0xFF
uint16_t error_callbak(uint16_t no);
uint8_t Wait_For_Standby(void);
/* i2c
		PB8  I2C1_SCL
		PB9	 I2C1_SDA
*/

void my_eeprom_init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef  I2C_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);  //使能GPIOB的时钟	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); //使能 I2C的时钟
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource8,GPIO_AF_I2C1);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_I2C1); //配置GPIO的复用功能
	
	  /* GPIO SCL初始化 */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 ;  
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = 300000;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_OwnAddress1 = STM32_I2C_OWN_ADDR;	
	I2C_Init(I2C1, &I2C_InitStructure); 
	
	I2C_Cmd(I2C1, ENABLE);//使能
	
}

本案例中EEPROM的地址:
#define EEPROM_I2C_ADDR 0xA0
0xA0的地址原因:
首先官方手册地址规定:
在这里插入图片描述
该板子使用的是2K的EEPROM,而且电路图中,A0 A1 A2都接地,所以都为0,
在这里插入图片描述
所以EEPROM的地址最终为0xA0

ERPROM 写一个字节

向EEPROM中任何一个地址写一个字节数据:

uint8_t my_EEPROM_Byte_Write(uint8_t addr,uint8_t data)
{
	uint32_t count_wait;
	I2C_GenerateSTART(I2C1,ENABLE); //产生起始信号
	
	
	count_wait = TIME_OUT;
	//等待EV5事件,这是一个宏。STM32在起始信号稳定后会设置该宏
	while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0) {
			return error_callbak(1);
		}
	}
	
	I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDR, I2C_Direction_Transmitter); //发送 EEPROM 地址,并指明是写操作
	

	
		count_wait = TIME_OUT;
	//等待事件 EV6,成功发送地址后,有EV6事件触发,表示发送成功
	while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0) {
			return error_callbak(2);
		}
	}
	
	
		//发送要写入的存储单元地址
	I2C_SendData(I2C1,addr);
	//等待事件 EV8,成功发送数据后,有EV8事件触发,表示发送成功
	count_wait = TIME_OUT;
	while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0) {
			return error_callbak(3);
		}
	}
	
	I2C_SendData(I2C1,data); //发送要写入的数据
	//等待事件 EV8
	count_wait = TIME_OUT;
	while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0) {
			return error_callbak(4);
		}
	}	
	
		//产生结束信号
	I2C_GenerateSTOP(I2C1, ENABLE);
	
	
	return Wait_For_Standby();
	
}

这里需要注意,当发送完写数据给EEPROM完成后,EEPROM此时才开始操作内部寄存器存储数据,会消耗一定时间,在这段时间内如果再次访问EEPROM,会访问失败。这就是最后wait_for_standby()函数的作用。
代码如下:
一直发送访问请求,直到访问成功。

uint8_t Wait_For_Standby(void)
{
	uint32_t check_count = 0xFFFFF;
	
	while(check_count--)
	{
		//产生起始信号
		I2C_GenerateSTART(EEPROM_I2C, ENABLE);
		
		//重置 count_wait
		count_wait = TIME_OUT;
		//等待EV5事件,直到检测成功
		while(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
		{
			count_wait--;
			if(count_wait == 0 )
			{
				return Error_CallBack(11);
			}
		}	
		
		//要发送的EEPROM设备地址,并设置为写方向
		I2C_Send7bitAddress(EEPROM_I2C, EEPROM_I2C_ADDR, I2C_Direction_Transmitter);
		
		//重置 count_wait
		count_wait = TIME_OUT;
		//等待EV6事件,直到检测成功
		while(count_wait--)
		{
			//若检测到响应,说明内部写时序完成,跳出等待函数
			if(I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == SUCCESS)
			{
				//退出前停止本次通讯
				I2C_GenerateSTOP(EEPROM_I2C, ENABLE);	
				return 0;
			}			
		}		
	}
	
	//退出前停止本次通讯
	I2C_GenerateSTOP(EEPROM_I2C, ENABLE);	
	return 1;
}

ERPROM 读一个字节

EEPROM中一般使用任意地址读功能,而不使用当前地址读。代码实现如下:
读取任意一个地址的一个字节数据:

uint8_t my_EEPROM_Random_Read(uint8_t addr, uint8_t *data)
{
	uint32_t count_wait;
	//产生起始信号
	I2C_GenerateSTART(I2C1, ENABLE);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV5事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(5);
		}
	}	
	
	//要发送的EEPROM设备地址,并设置为写方向
	I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDR, I2C_Direction_Transmitter);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV6事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(6);
		}
	}
	
	//发送要读取的存储单元地址
	I2C_SendData(I2C1,addr);
	
	//重置 count_wait
	count_wait = TIME_OUT;	
	//等待EV8_2事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(7);
		}
	}
	
	//------------------------------------------------------------------------
	//产生第二次起始信号	
	I2C_GenerateSTART(I2C1, ENABLE);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV5事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(8);
		}
	}	
	
	//************************读方向**********************************************
	//要发送的EEPROM设备地址,并设置为读方向
	I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDR, I2C_Direction_Receiver);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV6事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(9);
		}
	}
	
	//作出非应答信号,     此处如果是应答,EEPROM就会一直发数据了
	I2C_AcknowledgeConfig(I2C1, DISABLE);
		
	//重置 count_wait
	count_wait = TIME_OUT;		
	//等待EV8_2事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(10);
		}
	}
		
	//接收数据
	*data = I2C_ReceiveData(I2C1);
		
	//产生结束信号
	I2C_GenerateSTOP(I2C1, ENABLE);
	
	return 0;

}

按页写入数据

uint8_t my_eeprom_page_write(uint16_t addr,uint8_t* data,uint8_t size)	
{	
	uint32_t count_wait;
	
	if(size > 8) {
		return error_callbak(10);
	}
	

	I2C_GenerateSTART(I2C1,ENABLE); //产生起始信号
	
	
	count_wait = TIME_OUT;
	//等待EV5事件
	while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0) {
			return error_callbak(1);
		}
	}
	
	I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDR, I2C_Direction_Transmitter); //发送 EEPROM 地址,写方向
	

	
	count_wait = TIME_OUT;
	//等待事件 EV6
	while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0) {
			return error_callbak(2);
		}
	}
	
	
	//发送要写入的存储单元地址
	I2C_SendData(I2C1,addr);
	//等待事件 EV8
	count_wait = TIME_OUT;
	while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0) {
			return error_callbak(3);
		}
	}
	
	while(size--) {
		
		I2C_SendData(I2C1,*data); //发送要写入的数据
		//等待事件 EV8
		count_wait = TIME_OUT;
		while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
		{
			count_wait--;
			if(count_wait == 0) {
				return error_callbak(4);
			}
		}

		data++;
	
	}
		//产生结束信号
	I2C_GenerateSTOP(I2C1, ENABLE);
	
	return Wait_For_Standby();
		

写入任意大小数据

uint8_t my_eeprom_buffer_write(uint16_t addr,uint8_t* data,uint16_t size)
{
	//本次使用的EEPROM 是8字节 为一页对其
	
	if(size > EEPROM_MAX_SIZE)
	{
		return error_callbak(22);
	}
	
	uint8_t addr_page = addr % 8;  //检测地址是否对其
	uint16_t num_page,surplus_page;
	if(addr_page == 0)
	{
		surplus_page = size % 8; //数据是否对其,多出多少
		num_page = size / 8; //算出数据是多少页
		
		while(num_page--)
		{
			my_eeprom_page_write(addr,data,8);
			addr += 8;
			data += 8;			
		}
		
		my_eeprom_page_write(addr,data,surplus_page); //发送不满一页的数据
		
		
	}
	else{              //地址不对齐
		uint16_t first_page = 8 - addr_page;  //还差这么多地址才对齐
		
		my_eeprom_page_write(addr,data,first_page);//先发这么多,让地址对齐
		
		addr += first_page;
		data += first_page;
		size -= first_page;
		
		surplus_page = size % 8;
		num_page = size / 8;
		
		while(num_page--)
		{
			my_eeprom_page_write(addr,data,8);
			addr += 8;
			data += 8;
		}
		
		my_eeprom_page_write(addr,data,surplus_page);
		
		
	}
	
	return 0;
	
}

读取EEPROM中所有数据

uint8_t my_eeprom_buffer_read(uint16_t addr, uint8_t *data,uint16_t size)
{
	uint32_t count_wait;
	//产生起始信号
	I2C_GenerateSTART(I2C1, ENABLE);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV5事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(16);
		}
	}	
	
	//要发送的EEPROM设备地址,并设置为写方向
	I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDR, I2C_Direction_Transmitter);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV6事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(17);
		}
	}
	
	//发送要读取的存储单元地址
	I2C_SendData(I2C1,addr);
	
	//重置 count_wait
	count_wait = TIME_OUT;	
	//等待EV8_2事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(18);
		}
	}
	
	//------------------------------------------------------------------------
	//产生第二次起始信号	
	I2C_GenerateSTART(I2C1, ENABLE);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV5事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(19);
		}
	}	
	
	//************************读方向**********************************************
	//要发送的EEPROM设备地址,并设置为读方向
	I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDR, I2C_Direction_Receiver);
	
	//重置 count_wait
	count_wait = TIME_OUT;
	//等待EV6事件,直到检测成功
	while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
	{
		count_wait--;
		if(count_wait == 0 )
		{
			return error_callbak(20);
		}
	}
	
	while(size--)
	{
		if(size == 0)
		{
			I2C_AcknowledgeConfig(I2C1, DISABLE);
		}else {
			I2C_AcknowledgeConfig(I2C1,ENABLE);
		}
				//重置 count_wait
		count_wait = TIME_OUT;		
		//等待EV8_2事件,直到检测成功
		while(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
		{
			count_wait--;
			if(count_wait == 0 )
			{
				return error_callbak(21);
			}
		}
			
		//接收数据
		*data = I2C_ReceiveData(I2C1);
		data++;
	}
	
		
	//产生结束信号
	I2C_GenerateSTOP(I2C1, ENABLE);
	
	return 0;

}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值