要正确使用EPPROM需要配置掉电寄存器EEPWRDWN确定EEPROM的工作模式,配置EEPROM时钟分频器寄存器,使EPPROM工作在375KHZ。下面对EPPROM的读和写数据进行介绍。
EEPROM存储器的访问有三种操作方式:读、写、擦除/编程。对EPPROM中写数据分成两个单独的操作:写和擦除/编程。第一步写操作并不是真正把数据写入EPPROM的存储介质中,而只是更新被称作“页寄存器”的临时数据寄存器。只有执行下一步”擦除/编程“操作才会真正地更新非易失存储器。LPC1788共有4K的片内EPPROM,其中EPPROM的每一页等于页寄存器大小为64Byte,总共有64页。大小正好是64*64=4096Byte=4K。首先我们指定的位数,如8、16或者32位,将数据写入页寄存器,页内的地址偏移由EEPROM地址寄存器的第6位决定。如果需要往页寄存器写入一串数据,写完第一个数据后,页内的偏移地址会自动增加,我们只需把要操作的下一个数据填入EEPROM写数据寄存器即可。当页寄存器的64个字节被写满,必须进行编程操作,将数据写入到EEPROM的存储介质。然后更新页寄存器的偏移地址。
对于EEPROM的读操作,首先要向地址寄存器写入一个12位的地址,高6位为页的偏移,即我们需要读哪个页寄存器。低6位为页内的偏移,即我们需要读当前页的哪个字节。读操作也可以自动的对地址寄存器做后递增,这样就可以对EEPROM存储器进行连续的操作而无需每次读数据都写入一个新地址。
下面的程序将信息写入EEPROM后读出通过串口打印显示
- #include "LPC1788_REG.h"
- #include "uart.h"
- #define rEECMD (*(volatile unsigned*)(0x00200080))
- #define rEEADDR (*(volatile unsigned*)(0x00200084))
- #define rEEWDATA (*(volatile unsigned*)(0x00200088))
- #define rEERDATA (*(volatile unsigned*)(0x0020008C))
- #define rEEWSTATE (*(volatile unsigned*)(0x00200090))
- #define rEECLKDIV (*(volatile unsigned*)(0x00200094))
- #define rEEPWRDWN (*(volatile unsigned*)(0x00200098))
- #define rEEINTEN (*(volatile unsigned*)(0x00200FE4))
- #define rEEINTCLR (*(volatile unsigned*)(0x00200FD8))
- #define rEEINTSET (*(volatile unsigned*)(0x00200FDC))
- #define rEEINTSTAT (*(volatile unsigned*)(0x00200FE0))
- #define rEEINTSTATCLR (*(volatile unsigned*)(0x00200FE8))
- #define rEEINTSTATSET (*(volatile unsigned*)(0x00200FEC))
- #define EEPROM_PAGE_SIZE 64
- void Init_EEPROM(void);
- void Write_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count);
- void Read_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count);
- char read_buffer[];
- char write_buffer[] = {"\n\r\
- \t - Name: Nuncle.lee \n\r\
- \t - QQ: 23610603 \n\r\
- \t - Email: nuncle.lee@gmail.com\n\r"};
- int main(void)
- {
- Init_Uart2();
- Init_EEPROM();
- Write_EEPROM(0, 0, write_buffer, sizeof(write_buffer));
- Write_EEPROM(sizeof(write_buffer)/64, sizeof(write_buffer)%64, '\0', 1);
- Read_EEPROM(0, 0, read_buffer, sizeof(write_buffer)+1);
- Uart2SendS(read_buffer);
- return 0;
- }
- void Init_EEPROM(void)
- {
- unsigned int val=0;
- rEEPWRDWN = 0; //不处于掉电模式
- rEECLKDIV = (CCLK/375000)-1; //设置一个375KHZ的EEPROM时钟
- val = ((((CCLK / 1000000) * 15) / 1000) + 1); //配置等待状态时间
- val |= (((((CCLK / 1000000) * 55) / 1000) + 1) << 8);
- val |= (((((CCLK / 1000000) * 35) / 1000) + 1) << 16);
- rEEWSTATE = val;
- }
- void Write_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count)
- {
- unsigned int i;
- rEEADDR = (page_offset&0x3f); //确定开始写的页内偏移地址
- for(i=0; i
- {
- rEECMD = 0x3; //8位写操作
- rEEWDATA = *(data+i);
- while(!(rEEINTSTAT & (0x1<<26))); //等待写操作完成
- page_offset++;
- if(page_offset >= EEPROM_PAGE_SIZE) //如果当前页写满了64Byte 则启动 编程操作
- {
- rEEINTSTATCLR = 0x1<<28;
- rEEADDR = (page_num&0x3F)<<6;
- rEECMD = 0x6; //擦除编程
- while(!(rEEINTSTAT & (0x1<<28))); //等待编程完成
- page_offset = 0;
- page_num++; //写满一页,准备写下一页
- rEEADDR = 0; //写满一页,从页的开始写
- }
- else if(i==count-1) //如果要写入EPPROM的数据写完成,启动编程操作
- {
- rEEINTSTATCLR = 0x1<<28;
- rEEADDR = (page_num&0x3F)<<6;
- rEECMD = 0x6; //擦除编程
- while(!(rEEINTSTAT & (0x1<<28)));
- }
- }
- }
- void Read_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count)
- {
- unsigned int i;
- rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F; //确定读数据的起始位置,包括页偏移和页内的偏移
- rEECMD = 0x1<<3; //8位读,地址自动递增模式
- for(i=0; i
- {
- while(!(rEEINTSTAT & (0x1<<26))); //等待上一次读数据完成
- *(data+i) = rEERDATA;
- page_offset++;
- if(page_offset >= EEPROM_PAGE_SIZE) //如果当前页64Byte读完,准备读下一页
- {
- page_offset = 0;
- page_num++;
- rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F;
- rEECMD = 0x1<<3;
- }
- }
- }
程序的执行结果如下图
程序中,sizeof关键字计算出字符数组的大小,并不包含字符串的结束标志‘\0’。因此还需在sizeof(write_buffer)的位置写入字符串的结束标志。读取时读sizeof(write_buffer)+1个字节,才能正确的通过串口打印数据。当然,也可以自己指定串口打印字符的个数,而不用字符串结束标志去判断。
上一篇:Cortex-M3 (NXP LPC1788)之IIC控制器
下一篇:Cortex-M3 (NXP LPC1788)之ADC数模转换器的应用
推荐阅读最新更新时间:2024-03-16 14:55