384 lines
7.4 KiB
C
384 lines
7.4 KiB
C
#include "eeprom.h"
|
||
|
||
uint8_t Tx1_Buffer[] = "3.14159265358978";
|
||
uint8_t Rx1_Buffer[BufferSize1] = "";
|
||
|
||
void ee_io_init(void)
|
||
{
|
||
|
||
GPIO_InitTypeDef GPIO_InitStruct;
|
||
|
||
/* GPIO Ports Clock Enable */
|
||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||
/*Configure GPIO pin Output Level */
|
||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
|
||
|
||
/*Configure GPIO pins : PB6 PB9 */
|
||
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; //PB6 PB7
|
||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; //开漏输出
|
||
GPIO_InitStruct.Pull = GPIO_NOPULL; //上下拉模式配置为既不上拉也不下拉
|
||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//IO口速度配置
|
||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); //初始化
|
||
}
|
||
|
||
static void i2c_delay(void)
|
||
{
|
||
uint8_t i;
|
||
for (i = 0; i < 40; i++);
|
||
}
|
||
void i2c_start(void)
|
||
{
|
||
// 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号
|
||
|
||
I2C_SDA_1();
|
||
I2C_SCL_1();
|
||
i2c_delay();
|
||
I2C_SDA_0();
|
||
i2c_delay();
|
||
|
||
I2C_SCL_0();
|
||
i2c_delay();
|
||
}
|
||
|
||
void i2c_stop(void)
|
||
{
|
||
// 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号
|
||
I2C_SDA_0();
|
||
I2C_SCL_1();
|
||
i2c_delay();
|
||
I2C_SDA_1();
|
||
i2c_delay();
|
||
}
|
||
void i2c_sendbyte(uint8_t _ucByte)
|
||
{
|
||
uint8_t i;
|
||
|
||
// 先发送字节的高位bit7
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
if (_ucByte & 0x80)
|
||
{
|
||
I2C_SDA_1();
|
||
}
|
||
else
|
||
{
|
||
I2C_SDA_0();
|
||
}
|
||
i2c_delay();
|
||
I2C_SCL_1();
|
||
i2c_delay();
|
||
I2C_SCL_0();
|
||
if (i == 7)
|
||
{
|
||
I2C_SDA_1(); // 释放总线
|
||
}
|
||
_ucByte <<= 1; // 左移一个bit
|
||
i2c_delay();
|
||
}
|
||
}
|
||
uint8_t i2c_readbyte(void)
|
||
{
|
||
uint8_t i;
|
||
uint8_t value;
|
||
|
||
/* 读到第1个bit为数据的bit7 */
|
||
value = 0;
|
||
for (i = 0; i < 8; i++)
|
||
{
|
||
value <<= 1;
|
||
I2C_SCL_1();
|
||
i2c_delay();
|
||
if (I2C_SDA_READ())
|
||
{
|
||
value++;
|
||
}
|
||
I2C_SCL_0();
|
||
i2c_delay();
|
||
}
|
||
return value;
|
||
}
|
||
|
||
|
||
uint8_t i2c_waitack(void)
|
||
{
|
||
uint8_t re;
|
||
|
||
I2C_SDA_1(); /* CPU释放SDA总线 */
|
||
// i2c_Delay();
|
||
I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
|
||
i2c_delay();
|
||
|
||
if (I2C_SDA_READ()) /* CPU读取SDA口线状态 */
|
||
{
|
||
re = 1;
|
||
}
|
||
else
|
||
{
|
||
re = 0;
|
||
}
|
||
|
||
I2C_SCL_0();
|
||
i2c_delay();
|
||
return re;
|
||
}
|
||
|
||
void i2c_ack(void)
|
||
{
|
||
I2C_SDA_0(); /* CPU驱动SDA = 0 */
|
||
i2c_delay();
|
||
I2C_SCL_1(); /* CPU产生1个时钟 */
|
||
i2c_delay();
|
||
I2C_SCL_0();
|
||
i2c_delay();
|
||
I2C_SDA_1(); /* CPU释放SDA总线 */
|
||
}
|
||
|
||
void i2c_nack(void)
|
||
{
|
||
I2C_SDA_1(); /* CPU驱动SDA = 1 */
|
||
i2c_delay();
|
||
I2C_SCL_1(); /* CPU产生1个时钟 */
|
||
i2c_delay();
|
||
I2C_SCL_0();
|
||
i2c_delay();
|
||
}
|
||
|
||
uint8_t i2c_checkdevice(uint8_t _Address)
|
||
{
|
||
uint8_t ucAck;
|
||
|
||
if (I2C_SDA_READ() && I2C_SCL_READ())
|
||
{
|
||
i2c_start(); /* 发送启动信号 */
|
||
|
||
/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
|
||
i2c_sendbyte(_Address | I2C_WR);
|
||
ucAck = i2c_waitack(); /* 检测设备的ACK应答 */
|
||
|
||
i2c_stop(); /* 发送停止信号 */
|
||
|
||
return ucAck;
|
||
}
|
||
return 1; /* I2C总线异常 */
|
||
}
|
||
|
||
uint8_t ee_checkok(void)
|
||
{
|
||
if (i2c_checkdevice(EE_DEV_ADDR) == 0)
|
||
{
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
/* 失败后,切记发送I2C总线停止信号 */
|
||
i2c_stop();
|
||
return 0;
|
||
}
|
||
}
|
||
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++)
|
||
{
|
||
/* 当发送第1个字节或是页面首地址时,需要重新发起启动信号和地址 */
|
||
if ((i == 0) || (usAddr & (EE_PAGE_SIZE - 1)) == 0)
|
||
{
|
||
/* 第0步:发停止信号,启动内部写操作 */
|
||
i2c_stop();
|
||
|
||
/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms
|
||
CLK频率为200KHz时,查询次数为30次左右
|
||
*/
|
||
for (m = 0; m < 1000; m++)
|
||
{
|
||
/* 第1步:发起I2C总线启动信号 */
|
||
i2c_start();
|
||
|
||
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
|
||
|
||
// #if EE_ADDR_A8 == 1
|
||
// i2c_SendByte(EE_DEV_ADDR | I2C_WR | ((_usAddress >> 7) & 0x0E)); /* 此处是写指令 */
|
||
// #else
|
||
i2c_sendbyte(EE_DEV_ADDR | I2C_WR);
|
||
// #endif
|
||
|
||
/* 第3步:发送一个时钟,判断器件是否正确应答 */
|
||
if (i2c_waitack() == 0)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
if (m == 1000)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件写超时 */
|
||
}
|
||
/* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
|
||
if (EE_ADDR_BYTES == 1)
|
||
{
|
||
i2c_sendbyte((uint8_t)usAddr);
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
i2c_sendbyte(usAddr >> 8);
|
||
if (i2c_waitack()!= 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
|
||
i2c_sendbyte(usAddr);
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 第6步:开始写入数据 */
|
||
i2c_sendbyte(_pWriteBuf[i]);
|
||
|
||
/* 第7步:发送ACK */
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
usAddr++; /* 地址增1 */
|
||
}
|
||
|
||
/* 命令执行成功,发送I2C总线停止信号 */
|
||
i2c_stop();
|
||
|
||
/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms
|
||
CLK频率为200KHz时,查询次数为30次左右
|
||
*/
|
||
for (m = 0; m < 1000; m++)
|
||
{
|
||
/* 第1步:发起I2C总线启动信号 */
|
||
i2c_start();
|
||
|
||
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
|
||
#if EE_ADDR_A8 == 1
|
||
i2c_sendbyte(EE_DEV_ADDR | I2C_WR | ((_usAddress >> 7) & 0x0E)); /* 此处是写指令 */
|
||
#else
|
||
i2c_sendbyte(EE_DEV_ADDR | I2C_WR); /* 此处是写指令 */
|
||
#endif
|
||
|
||
/* 第3步:发送一个时钟,判断器件是否正确应答 */
|
||
if (i2c_waitack() == 0)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
if (m == 1000)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件写超时 */
|
||
}
|
||
|
||
/* 命令执行成功,发送I2C总线停止信号 */
|
||
i2c_stop();
|
||
|
||
return 1;
|
||
|
||
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
|
||
/* 发送I2C总线停止信号 */
|
||
i2c_stop();
|
||
return 0;
|
||
}
|
||
uint8_t ee_readbytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize)
|
||
{
|
||
uint16_t i;
|
||
|
||
/* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */
|
||
|
||
/* 第1步:发起I2C总线启动信号 */
|
||
i2c_start();
|
||
|
||
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
|
||
|
||
i2c_sendbyte(EE_DEV_ADDR | I2C_WR); /* 此处是写指令 */
|
||
|
||
/* 第3步:发送ACK */
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
/* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
|
||
if (EE_ADDR_BYTES == 1)
|
||
{
|
||
i2c_sendbyte((uint8_t)_usAddress);
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
i2c_sendbyte(_usAddress >> 8);
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
|
||
i2c_sendbyte(_usAddress);
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
}
|
||
|
||
/* 第6步:重新启动I2C总线。下面开始读取数据 */
|
||
i2c_start();
|
||
|
||
/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
|
||
|
||
i2c_sendbyte(EE_DEV_ADDR | I2C_RD); /* 此处是写指令 */
|
||
|
||
/* 第8步:发送ACK */
|
||
if (i2c_waitack() != 0)
|
||
{
|
||
goto cmd_fail; /* EEPROM器件无应答 */
|
||
}
|
||
|
||
/* 第9步:循环读取数据 */
|
||
for (i = 0; i < _usSize; i++)
|
||
{
|
||
_pReadBuf[i] = i2c_readbyte(); /* 读1个字节 */
|
||
|
||
/* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack */
|
||
if (i != _usSize - 1)
|
||
{
|
||
i2c_ack(); /* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) */
|
||
}
|
||
else
|
||
{
|
||
i2c_nack(); /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
|
||
}
|
||
}
|
||
/* 发送I2C总线停止信号 */
|
||
i2c_stop();
|
||
|
||
return 1; /* 执行成功 */
|
||
|
||
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
|
||
/* 发送I2C总线停止信号 */
|
||
i2c_stop();
|
||
return 0;
|
||
}
|
||
|
||
// m=ee_writebytes(Tx1_Buffer,0,BufferSize1);
|
||
|
||
// printf("I2C_WriteByte %d %s\r\n",m,(uint8_t*)&Tx1_Buffer[0]);
|
||
|
||
// m=ee_readbytes(Rx1_Buffer,0,BufferSize1);
|
||
|
||
// printf("I2C_ReadByte %d %s\r\n",m,(uint8_t*)&Rx1_Buffer[0]);
|
||
|
||
// printf(" Rx1_Buffer is:%s,\t the BufferSize1 is:%d\r\n",Rx1_Buffer,BufferSize1);
|
||
|
||
|