一,EEPROM
这里用的EEPROM是AT24C02芯片, 02 代表2K个位 , 那么总容量就是:256(2K/8)个字节。接口:IIC.
AT24C02字节写时序图:
AT24C02字节读时序图:
AT24C02与STM32的连接:
例如:24C02 的 SCL 和 SDA 分别连在 STM32 的 PB6 和 PB7 上的,连接关系如图所示:
二,代码实现
I2C驱动与通信协议代码实现:
// 根据原理图设置IO
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
// 初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //PB 时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIO
GPIO_SetBits(GPIOB, GPIO_Pin_6|GPIO_Pin_7); // PB6, PB7 输出高,空闲状态
}
// 产生IIC的起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda 线输出
IIC_SDA = 1;
IIC_SCL = 1; // 空闲状态需要将2根线拉高
delay_us(4);
IIC_SDA = 0; // START: 当SCL高电平时, SDA 由高拉低.
delay_us(4);
IIC_SCL = 0; // SCL拉低,钳住I2C总线,准备发送或接收数据
}
// 产生IIC的停止信号
void IIC_Stop(void)
{
SDA_OUT(); //sda 线输出
IIC_SCL = 0;
IIC_SDA = 0;
delay_us(4);
IIC_SCL = 1; // 发送I2C总线结束信号
IIC_SDA = 1; // STOP: 当SCL高电平时, SDA 由低拉高.
delay_us(4);
}
// IIC发送一个字节数据
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL = 0; // 拉低时钟开始数据传输
for(t=0; t<8; t++) {
if ((txd & 0x80)>>7) //最高位是1,SDA 拉高,否则拉低。
IIC_SDA = 1;
else
IIC_SDA = 0;
txd <<= 1; // 依次从高地址到低地址发送数据。
delay_us(2);
IIC_SCL = 1; // SDA数据准备之后,将SCL 拉高。
delay_us(2);
IIC_SCL = 0; // 再将SCL 拉低。
delay_us(2);
}
}
// IIC读取一个字节数据
// ack=1时,发送ack,ack=0时,发送nack。
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i, receive=0;
SDA_IN(); // SDA 设置为输入
for(i=0;i<8;i++) {
IIC_SCL = 0;
delay_us(2);
IIC_SCL = 1; // 拉高SCL, 为高电平时,读取数据,
receive <<= 1; // 读数据保存在高位
if(READ_SDA) receive++; // 如果是输入模式,低位+1,否则不加
delay_us(1);
}
if(!ack)
IIC_NAck(); // 发送nack
else
IIC_Ack(); // 发送ack
return receive;
}
// 等待应答信号的到来
// 返回值: 1, 接收应答失败
// 0, 接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime = 0;
SDA_IN(); // SDA 设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA) {
ucErrTime++;
if (ucErrTime > 250) {
IIC_Stop();
return 1;
}
}
IIC_SCL = 0; // 时钟输出 0
return 0;
}
// 产生IIC的应答信号
void IIC_Ack(void)
{
IIC_SCL = 0;
SDA_OUT();
IIC_SDA = 0;
delay_us(2);
IIC_SCL = 1;
delay_us(2);
IIC_SCL = 0;
}
// 不产生IIC的应答信号
void IIC_NAck(void)
{
IIC_SCL = 0;
SDA_OUT();
IIC_SDA = 1;
delay_us(2);
IIC_SCL = 1;
delay_us(2);
IIC_SCL = 0;
}
AT24C02驱动与I2C接口实现:
//初始化IIC接口
void AT24C02_Init(void)
{
IIC_Init();
}
//ReadAddr:开始读数的地址
//返回值 :读到的数据
u8 AT24C02_ReadOneByte(u16 ReadAddr)
{
u8 temp = 0;
// dummy write
IIC_Start();
IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr%256); //发送低地址
IIC_Wait_Ack();
//real write
IIC_Start();
IIC_Send_Byte(0XA1); //进入接收模式
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
return temp;
}
// WriteAddr :写入数据的目的地址
// DataToWrite:要写入的数据
void AT24C02_WriteOneByte(u16 WriteAddr, u8 DataToWrite)
{
// write device addresss
IIC_Start();
IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据
IIC_Wait_Ack();
// write word address
IIC_Send_Byte(WriteAddr%256); //发送低地址
IIC_Wait_Ack();
// write data
IIC_Send_Byte(DataToWrite); //发送字节
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
delay_ms(10);
}