E2PROM 多字节操作
我们知道,写数据的时候,E2PROM是先写到缓冲区,然后再“搬运到”到掉电非易失区。所以这个过程需要一定的时间,AT24C02这个过程是不超过5ms!如果在这个时候去让它应答是没有响应的!
所以,当我们在写多个字节时,写入一个字节之后,再写入下一个字节之前,必须等待E2PROM再次相应才可以。
main.c
#include "sys.h"
void main()
{
unsigned char dat1[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsigned char dat2[8] = {0};
int len = 0;
ALL_Init();
//将dat1数据写到E2PROM
E2Write(dat1,30,sizeof(dat1));
//将E2PROM所存的数据读到dat2中
E2Read(dat2,30,sizeof(dat2));
while(1)
{
//将dat2里面的值作为参数 实现流水灯
Led_illume(dat2[len]);
Operate_Delay(1000);
len++;
if(len == 8)
{
len = 0;
}
}
}
at24c02.c
#include "iic.h"
/*******************************************************************************
* 函数名 :E2Read
* 输入值 :unsigned char *buf, unsigned char addr, unsigned char len
* 返回值 :none
* 作者 : guyao
* 时间 :2021/2/22
* 功能描述:连续读取多个数据
* 备注 :buf为数据接收指针,addr为E2PROM中要读取的数据起始地址,len为读取长度
*******************************************************************************/
void E2Read(unsigned char *buf, unsigned char addr, unsigned char len)
{
do{ //用寻址操作查询当前是否可以进行读操作
IIC_Start();
IIC_SendByte(SlaveAddrW);//发送器件地址
if(IIC_WaitAck())//应答则跳出循环,非应答则进行下一次查询
{
break;
}
IIC_Stop();
}while(1);
IIC_SendByte(addr); //写入起始地址
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(SlaveAddrR); //寻址器件,后续为读操作
IIC_WaitAck();
while(len > 1) //连续读取len-1个字节
{
*buf++ = IIC_RecByte(); //最后字节之前为读取操作并且应答
IIC_Ack(1);
len--;
}
*buf = IIC_RecByte(); //最后一个字节为读取操作并且非应答
IIC_Ack(0);
IIC_Stop();
}
/*******************************************************************************
* 函数名 :E2Write
* 输入值 :unsigned char *buf, unsigned char addr, unsigned char len
* 返回值 :none
* 作者 :guyao
* 时间 :2021/2/22
* 功能描述:连续写入多个数据
* 备注 :buf为源数据指针,addr为E2PROM中要写入的数据起始地址,len为写入长度
*******************************************************************************/
void E2Write(unsigned char *buf, unsigned char addr, unsigned char len)
{
while(len--)
{
do{ //用寻址操作查询当前是否可以进行读操作
IIC_Start();
IIC_SendByte(SlaveAddrW);//发送器件地址
if(IIC_WaitAck())//应答则跳出循环,非应答则进行下一次查询
{
break;
}
IIC_Stop();
}while(1);
IIC_SendByte(addr++); //写入起始地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(*buf++); //写入一个字节数据
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //结束写操作,以等待写入完成
}
}
led.c
#include "sys.h"
void Led_illume(uchar dat)
{
P2 = (P2 & 0X1F)| 0X80;//打开Y4C
P0 = dat;
}
sys.c
#include "sys.h"
/**
*@brief 外设初始化
*@param[in] none
*@return none
**/
void ALL_Init()
{
P2 = (P2&0x1f)|0xa0; //打开Y5C
P0 = 0x00; //关闭蜂鸣器&继电器
P2 = (P2&0x1f)|0xe0; //打开Y7C
P0 = 0xff; //关闭数码管
P2 = (P2&0x1f)|0x80; //打开Y4C
P0 = 0xff; //关闭LED
P2 = P2&0x1f; //关闭所用使能
}
/**
*@brief 延时函数
*@param[in] 延时多少ms(0~65535)
*@return none
**/
void Operate_Delay(u16 ms)
{
u16 i;
for(ms;ms>0;ms--)
for(i=921;i>0;i--);
}
#ifndef __SYS_H__
#define __SYS_H__
//头文件包含
#include <STC15F2K60S2.H>
#include <intrins.h>
//管脚声明
//变量类型声明
typedef unsigned int uint;
typedef unsigned int u16;
typedef unsigned char uchar;
typedef unsigned char u8;
//外部变量声明
//函数声明
void ALL_Init();
void Operate_Delay(unsigned int ms);
//at24c02.c
void E2Read(unsigned char *buf, unsigned char addr, unsigned char len);
void E2Write(unsigned char *buf, unsigned char addr, unsigned char len);
//led.c
void Led_illume(uchar dat);
#endif
E2PROM 页写入
多字节写入我们也能感受到一次写一个字节的慢,然后等待ACK后才能写入下一个字节。效率太低!所以就诞生了分页写的模式。
这一次我们专门成立了一个eeprom的模块。
24C02,一共是 256 个字节,8 个字节一页,那么就一共有 32 页。
分配好页之后,如果我们在同一个页内连续写入几个字节后,最后再发送停止位的时序。EEPROM 检测到这个停止位后,就会一次性把这一页的数据写到非易失区域,就不需要像上节课那样写一个字节检测一次了,并且页写入的时间也不会超过 5ms。
如果我们写入的数据跨页了,那么写完了一页之后,我们要发送一个停止位,然后等待并且检测 EEPROM 的空闲模式,一直等到把上一页数据完全写到非易失区域后,再进行下一页的写入,这样就可以在很大程度上提高数据的写入效率。
/*******************************************************************************
* 函数名 :E2Write_page
* 输入值 :unsigned char *buf, unsigned char addr, unsigned char len
* 返回值 :none
* 作者 :guyao
* 时间 :2021/2/22
* 功能描述:连续写入一页数据
* 备注 :buf为源数据指针,addr为E2PROM中要写入的数据起始地址,len为写入长度
*******************************************************************************/
void E2Write_page(unsigned char *buf, unsigned char addr, unsigned char len)
{
while(len)
{
do{ //用寻址操作查询当前是否可以进行读操作
IIC_Start();
IIC_SendByte(SlaveAddrW);//发送器件地址
if(IIC_WaitAck())//应答则跳出循环,非应答则进行下一次查询
{
break;
}
IIC_Stop();
}while(1);
IIC_SendByte(addr);//写入起始地址
IIC_WaitAck();
while(len > 0)
{
IIC_SendByte(*buf++);//写入一个字节数据
IIC_WaitAck();
len--; //代写入长度递减
addr++; //E2PROM地址递增
if((addr & 0x07) == 0)//检查地址是否达到页边界,24c02每页8节
break;
}
IIC_Stop();
}
}