AT24C128,ATMEL公司出的EEPROM芯片,共有16,384 x 8bit,整个存储器共有256页,每页64BYTES.
使用IIC协议。
#ifndef EEPROM_H
#define EEPROM_H
#include "Typedef.h"
#define IIC_SDA_PORT GPIOA
#define IIC_SCL_PORT GPIOA
#define IIC_SCL_PIN GPIO_PIN_3
#define IIC_SDA_PIN GPIO_PIN_4
#define HIGH GPIO_PIN_SET
#define LOW GPIO_PIN_RESET
#define PinInput 1
#define PinOutput 0
#define SDA_IN() {GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)8<<16;}
#define SDA_OUT() {GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)3<<16;}
#define GetSDA() (HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)==GPIO_PIN_SET) //(GPIOA->IDR&((u32)1<<4))
#define SetSDA(state) HAL_GPIO_WritePin(IIC_SDA_PORT,IIC_SDA_PIN,state)
#define SetSCL(state) HAL_GPIO_WritePin(IIC_SCL_PORT,IIC_SCL_PIN,state)
#define E_DELAY 2 // 两个EEPROM命令之间的间隔
extern u8 iic_cmd_delay;
extern u8 AT24CXX_ReadOneByte(u32 ReadAddr);
extern void AT24CXX_WriteOneByte(u32 WriteAddr,u8 DataToWrite);
extern void AT24CXX_Read(u32 ReadAddr,u8 *pBuffer,u16 NumToRead);
extern void AT24CXX_Write(u32 WriteAddr,u8 *pBuffer,u16 NumToWrite);
extern void AT24CXX_clr(u32 WriteAddr,u32 NumToWrite);
extern void IIC_Start1(void);
void IIC_Stop(void);
u8 IIC_Wait_Ack(void);
void IIC_Ack(void);
void IIC_NAck(void);
void IIC_Send_Byte(u8 txd);
void delay_nop(void);
void SetSDADirection(u8 direction);
#endif
#include "main.h"
#include "eeprom.h"
/* AT24C128C organized as 256 pages of 64-bytes each
AT24C512C, organized as 512 pages of 128 bytes each
不同的的EEPROM对应的页大小不一样,注意修改
*/
#define PAGE_SIZE 64
u8 iic_cmd_delay=0;
void SetSDADirection(u8 direction)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = IIC_SDA_PIN;
if(direction)
{
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
}
else
{
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
}
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// SDA
/***********************iic**************************/
void delay_nop(void)
{
unsigned int i;
for(i=0;i<50;i++)
__nop();
}
//产生IIC起始信号
void IIC_Start(void)
{
/*while(iic_cmd_delay < E_DELAY) // 距上一个命令时间太短
{
R_WDT_Restart();
}*/
SDA_OUT();//sda线输出
SetSDA(HIGH);
SetSCL(HIGH);
delay_nop();
SetSDA(LOW);//START:when CLK is high,DATA change form high to low
delay_nop();
SetSCL(LOW);//钳住I2C总线,准备发送或接收数据
}
void IIC_Start1(void)
{
SDA_OUT(); //sda线输出
SetSDA(HIGH);
delay_nop();
SetSCL(HIGH);
delay_nop();
SetSDA(LOW); //START:when CLK is high,DATA change form high to low
delay_nop();
SetSCL(LOW); //钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SetSDA(LOW);
SDA_OUT();//sda线输出
SetSCL(LOW);
delay_nop();
SetSCL(HIGH);
delay_nop();
SetSDA(HIGH);//发送I2C总线结束信号
delay_nop();
iic_cmd_delay=0;
}
//等待应答信号到来
//返回值:
// 1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 flag;
SDA_IN(); //SDA设置为输入
SetSDA(HIGH);
delay_nop();
SetSCL(HIGH);
delay_nop();
if(GetSDA())
flag=1;
else
flag=0;
SetSCL(LOW); //时钟输出0
return flag;
}
//产生ACK应答
void IIC_Ack(void)
{
SetSCL(LOW);
SDA_OUT();
SetSDA(LOW);
delay_nop();
SetSCL(HIGH);
delay_nop();
SetSCL(LOW);
}
//不产生ACK应答
void IIC_NAck(void)
{
SetSCL(LOW);
SDA_OUT();
SetSDA(HIGH);
delay_nop();
SetSCL(HIGH);
delay_nop();
SetSCL(LOW);
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
SetSCL(LOW);//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
if((txd&0x80)>>7)
SetSDA(HIGH);
else SetSDA(LOW);
txd<<=1;
delay_nop();
SetSCL(HIGH);
delay_nop();
SetSCL(LOW);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(u8 ack)
{
u8 i,receive=0;
SDA_IN();
for(i=0;i<8;i++ )
{
SetSCL(LOW);
delay_nop();
SetSCL(HIGH);
delay_nop();
receive<<=1;
if(GetSDA())
receive++;
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
/***********************iic**************************/
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址
//返回值 :读到的数据
u8 AT24CXX_ReadOneByte(u32 ReadAddr)
{
u8 temp;
u8 addrH,addrL;
addrH=ReadAddr>>8;
addrL=ReadAddr&0xff;
IIC_Start();
IIC_Send_Byte(0xa0);
IIC_Wait_Ack();
IIC_Send_Byte(addrH); //发送高地址
IIC_Wait_Ack();
IIC_Send_Byte(addrL); //发送低地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0xa1); //进入接收模式
IIC_Wait_Ack();
temp= IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
return temp;
}
//在AT24CXX指定地址写入一个数据
//WriteAddr :写入数据的目的地址
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u32 WriteAddr,u8 DataToWrite)
{
u8 addrH,addrL;
addrH=WriteAddr>>8;
addrL=WriteAddr&0xff;
IIC_Start();
IIC_Send_Byte(0xa0);
IIC_Wait_Ack();
IIC_Send_Byte(addrH); //发送高地址
IIC_Wait_Ack();
IIC_Send_Byte(addrL); //发送低地址
IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite); //发送字节
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
}
//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u32 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
u8 addrH,addrL;
if(NumToRead==0)
return;
addrH=ReadAddr>>8;
addrL=ReadAddr&0xff;
IIC_Start();
IIC_Send_Byte(0xa0);//写
IIC_Wait_Ack();
IIC_Send_Byte(addrH); //发送高地址
IIC_Wait_Ack();
IIC_Send_Byte(addrL); //发送低地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0xa1); //读 //进入接收模式
IIC_Wait_Ack();
NumToRead--;
while(NumToRead)
{
*pBuffer=IIC_Read_Byte(1);
pBuffer++;
ReadAddr++;
NumToRead--;
}
*pBuffer=IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
}
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer :数据数组首地址
//NumToWrite:要写入数据的个数
// 每128bytes为一个page,写操作不能跨页
void AT24CXX_Write(u32 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
u8 addrH,addrL;
u16 lentmp,lentow,lens;
u8 tmp;
if(NumToWrite==0)
return;
lentmp=NumToWrite;
while(lentmp)
{
tmp=WriteAddr%PAGE_SIZE;
tmp=PAGE_SIZE-tmp;
if(tmp>=lentmp)//当页剩余空间大于要写入的长度
{
lentow=lentmp;
}
else
{
lentow=tmp;//写入长度只能是剩余空间长度
}
lentmp=lentmp-lentow;//计算要在下一页写入的长度
lens=lentow;
addrH=WriteAddr>>8;
addrL=WriteAddr&0xff;
IIC_Start();
IIC_Send_Byte(0xa0);
IIC_Wait_Ack();
IIC_Send_Byte(addrH); //发送高地址
IIC_Wait_Ack();
IIC_Send_Byte(addrL); //发送低地址
IIC_Wait_Ack();
while(lentow--)
{
IIC_Send_Byte(*pBuffer);
IIC_Wait_Ack();
pBuffer++;
}
IIC_Stop();//产生一个停止条件
WriteAddr=WriteAddr+lens;//下一页的地址
}
}
void AT24CXX_clr(u32 WriteAddr,u32 NumToWrite)
{
u8 addrH,addrL;
u16 lentmp,lentow,lens;
u8 tmp;
lentmp=NumToWrite;
while(lentmp)
{
tmp=WriteAddr%PAGE_SIZE;
tmp=PAGE_SIZE-tmp;
if(tmp>=lentmp)
{
lentow=lentmp;
}
else
{
lentow=tmp;
}
lentmp=lentmp-lentow;
lens=lentow;
addrH=WriteAddr>>8;
addrL=WriteAddr&0xff;
IIC_Start();
IIC_Send_Byte(0xa0);
IIC_Wait_Ack();
IIC_Send_Byte(addrH); //发送高地址
IIC_Wait_Ack();
IIC_Send_Byte(addrL); //发送低地址
IIC_Wait_Ack();
while(lentow--)
{
IIC_Send_Byte(0xff);
IIC_Wait_Ack();
}
IIC_Stop();//产生一个停止条件
WriteAddr=WriteAddr+lens;
}
}
//----------------------EEPROM---------------------------//
//--------------------------------------------------------EEPROM DATA
本文写的时候是为AT24C128写的,但是也支持其他容量的芯片,比如AT24C02,AT24C256等等。只需要根据对应芯片的页大小修改对应的宏定义就可以了。