基于STM32F103的软件I2C应用

1、eeprom

eeprom是一种掉电不丢失数据的器件,常用于上电加载初始化数据,最常用的通讯方式是I2C协议。

如下图,芯片型号AT24C02(共存256个字节,每页8个字节),设备地址一共7位,高四位固定,后三位由A0 A1 A2如下图连接的电平决定。

R/W是读写方向,与地址无关,即主设备读取时=1,主设备写时=0。

wp是写保护,即可写入数据时=0,不可写入数据时=1。

 

2、软件模拟

配置两个IO口

void i2c_CfgGpio(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE);	
	GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN | EEPROM_I2C_SCL_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	//开漏模式
	GPIO_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure);
		
	i2c_Stop();//复位从设备

}

 检查eeprom器件是否在线

uint8_t i2c_CheckDevice(uint8_t _Address)
{
	uint8_t ucAck;

	i2c_CfgGpio();		

	i2c_Start();		

	i2c_SendByte(_Address | EEPROM_I2C_WR);
	ucAck = i2c_WaitAck();	

	i2c_Stop();			

	return ucAck;
}

 写函数

uint8_t ee_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint16_t _usSize)
{
	uint16_t i,m;
	uint16_t usAddr;
	
	usAddr = _usAddress;	
	
	for (i = 0; i < _usSize; i++)
	{
		if ((i == 0) || (usAddr & (EEPROM_PAGE_SIZE - 1)) == 0)
		{
			
			i2c_Stop();

			for (m = 0; m < 1000; m++)
			{				
				i2c_Start();
				
				i2c_SendByte(EEPROM_DEV_ADDR | EEPROM_I2C_WR);	
				
				if (i2c_WaitAck() == 0)
				{
					break;
				}
			}
			if (m  == 1000)//写数据超时监测
			{
				goto cmd_fail;	
			}
		
			i2c_SendByte((uint8_t)usAddr);
			
			if (i2c_WaitAck() != 0)
			{
				goto cmd_fail;	
			}
		}
	
		i2c_SendByte(_pWriteBuf[i]);
	
		if (i2c_WaitAck() != 0)
		{
			goto cmd_fail;	
		}

		usAddr++;	
	}
	
	
	i2c_Stop();
	return 1;

cmd_fail: 
	
	i2c_Stop();
	return 0;
}

 读函数

uint8_t ee_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize)
{
	uint16_t i;
	
	i2c_Start();
	
	i2c_SendByte(EEPROM_DEV_ADDR | EEPROM_I2C_WR);//写入地址
	 
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	
	}

	i2c_SendByte((uint8_t)_usAddress);
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	
	}

	i2c_Start();
	
	i2c_SendByte(EEPROM_DEV_ADDR | EEPROM_I2C_RD);//读取指令
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	
	}	
	
	for (i = 0; i < _usSize; i++)
	{
		_pReadBuf[i] = i2c_ReadByte();
		
		if (i != _usSize - 1)
		{
			i2c_Ack();	
		}
		else
		{
			i2c_NAck();	
		}
	}

	i2c_Stop();
	return 1;	

cmd_fail: 
	i2c_Stop();
	return 0;
}

起始信号和停止信号 

 

void i2c_Start(void)
{
	
	EEPROM_I2C_SDA_1();
	EEPROM_I2C_SCL_1();
	i2c_Delay();
	EEPROM_I2C_SDA_0();
	i2c_Delay();
	EEPROM_I2C_SCL_0();
	i2c_Delay();
}
//
void i2c_Stop(void)
{
	
	EEPROM_I2C_SDA_0();
	EEPROM_I2C_SCL_1();
	i2c_Delay();
	EEPROM_I2C_SDA_1();
}

 应答与非应答

 

void i2c_Ack(void)
{
	EEPROM_I2C_SDA_0();	
	i2c_Delay();
	EEPROM_I2C_SCL_1();	
	i2c_Delay();
	EEPROM_I2C_SCL_0();
	i2c_Delay();
	EEPROM_I2C_SDA_1();	
}
//
void i2c_NAck(void)
{
	EEPROM_I2C_SDA_1();	
	i2c_Delay();
	EEPROM_I2C_SCL_1();	
	i2c_Delay();
	EEPROM_I2C_SCL_0();
	i2c_Delay();	
}

 3、实验

向EEPROM写入15个数据,0 1 2 3 。。。14

读取第15个数据

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值