博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转)Cortex-M3 (NXP LPC1788)之EEPROM存储器
阅读量:6197 次
发布时间:2019-06-21

本文共 7004 字,大约阅读时间需要 23 分钟。

EEPROM是一种非易失性存储器,主要用于存储相对少量的数据,如存储一些系统的配置信息。通过系统的EEPROM控制模块可以轻松的进行EERPOM的存储控制。

        要正确使用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后读出通过串口打印显示

[cpp]
  1. #include "LPC1788_REG.h" 
  2. #include "uart.h" 
  3.  
  4. #define rEECMD          (*(volatile unsigned*)(0x00200080)) 
  5. #define rEEADDR         (*(volatile unsigned*)(0x00200084)) 
  6. #define rEEWDATA        (*(volatile unsigned*)(0x00200088)) 
  7. #define rEERDATA        (*(volatile unsigned*)(0x0020008C)) 
  8. #define rEEWSTATE       (*(volatile unsigned*)(0x00200090)) 
  9. #define rEECLKDIV       (*(volatile unsigned*)(0x00200094)) 
  10. #define rEEPWRDWN       (*(volatile unsigned*)(0x00200098)) 
  11.  
  12. #define rEEINTEN        (*(volatile unsigned*)(0x00200FE4)) 
  13. #define rEEINTCLR       (*(volatile unsigned*)(0x00200FD8)) 
  14. #define rEEINTSET       (*(volatile unsigned*)(0x00200FDC)) 
  15. #define rEEINTSTAT      (*(volatile unsigned*)(0x00200FE0)) 
  16. #define rEEINTSTATCLR   (*(volatile unsigned*)(0x00200FE8)) 
  17. #define rEEINTSTATSET   (*(volatile unsigned*)(0x00200FEC)) 
  18.  
  19. #define EEPROM_PAGE_SIZE 64 
  20. void Init_EEPROM(void); 
  21. void Write_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count); 
  22. void Read_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count); 
  23.  
  24. char read_buffer[]; 
  25. char write_buffer[] = {"\n\r\ 
  26. \t - Name: Nuncle.lee \n\r\ 
  27. \t - QQ: 23610603 \n\r\ 
  28. \t - Email: nuncle.lee@gmail.com\n\r"}; 
  29.  
  30. int main(void
  31. {    
  32.     Init_Uart2(); 
  33.     Init_EEPROM(); 
  34.      
  35.      
  36.     Write_EEPROM(0, 0, write_buffer, sizeof(write_buffer)); 
  37.     Write_EEPROM(sizeof(write_buffer)/64, sizeof(write_buffer)%64, '\0', 1); 
  38.      
  39.     Read_EEPROM(0, 0, read_buffer, sizeof(write_buffer)+1); 
  40.      
  41.     Uart2SendS(read_buffer); 
  42.  
  43.     return 0; 
  44.  
  45. void Init_EEPROM(void
  46.     unsigned int val=0; 
  47.      
  48.     rEEPWRDWN = 0;  //不处于掉电模式 
  49.     rEECLKDIV = (CCLK/375000)-1;    //设置一个375KHZ的EEPROM时钟 
  50.      
  51.     val  = ((((CCLK / 1000000) * 15) / 1000) + 1);      //配置等待状态时间 
  52.     val |= (((((CCLK / 1000000) * 55) / 1000) + 1) << 8); 
  53.     val |= (((((CCLK / 1000000) * 35) / 1000) + 1) << 16); 
  54.     rEEWSTATE = val; 
  55. void Write_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count) 
  56.     unsigned int i; 
  57.      
  58.     rEEADDR = (page_offset&0x3f);   //确定开始写的页内偏移地址 
  59.     for(i=0; i<count; i++) 
  60.     { 
  61.         rEECMD = 0x3;               //8位写操作 
  62.         rEEWDATA = *(data+i); 
  63.         while(!(rEEINTSTAT & (0x1<<26)));   //等待写操作完成 
  64.         page_offset++; 
  65.          
  66.         if(page_offset >= EEPROM_PAGE_SIZE)     //如果当前页写满了64Byte 则启动 编程操作 
  67.         { 
  68.             rEEINTSTATCLR = 0x1<<28; 
  69.             rEEADDR = (page_num&0x3F)<<6; 
  70.             rEECMD = 0x6;   //擦除编程 
  71.             while(!(rEEINTSTAT & (0x1<<28)));   //等待编程完成 
  72.              
  73.             page_offset = 0; 
  74.             page_num++;     //写满一页,准备写下一页 
  75.             rEEADDR = 0;    //写满一页,从页的开始写 
  76.         } 
  77.         elseif(i==count-1)                 //如果要写入EPPROM的数据写完成,启动编程操作 
  78.         { 
  79.             rEEINTSTATCLR = 0x1<<28; 
  80.             rEEADDR = (page_num&0x3F)<<6; 
  81.             rEECMD = 0x6;   //擦除编程 
  82.             while(!(rEEINTSTAT & (0x1<<28))); 
  83.         } 
  84.     } 
  85.  
  86. void Read_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count) 
  87.     unsigned int i; 
  88.     rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F;      //确定读数据的起始位置,包括页偏移和页内的偏移 
  89.     rEECMD = 0x1<<3;                                    //8位读,地址自动递增模式 
  90.     for(i=0; i<count; i++) 
  91.     { 
  92.         while(!(rEEINTSTAT & (0x1<<26)));               //等待上一次读数据完成 
  93.         *(data+i) = rEERDATA; 
  94.         page_offset++; 
  95.          
  96.         if(page_offset >= EEPROM_PAGE_SIZE)             //如果当前页64Byte读完,准备读下一页 
  97.         { 
  98.             page_offset = 0; 
  99.             page_num++; 
  100.             rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F;   
  101.             rEECMD = 0x1<<3; 
  102.         } 
  103.     } 
#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 64void 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
= 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
= 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个字节,才能正确的通过串口打印数据。当然,也可以自己指定串口打印字符的个数,而不用字符串结束标志去判断。

转载地址:http://ncuca.baihongyu.com/

你可能感兴趣的文章
vue21 slot占位
查看>>
12C -- 配置Application Continuity
查看>>
Redis从入门到精通:初级篇(转)
查看>>
代码质量与上线压力
查看>>
jQuery EasyUI API 中文文档 - 加载器
查看>>
addedbytes.com 制作的速查表欣赏
查看>>
Flymeos插桩适配教程
查看>>
Aspose.Pdf for Java 4.0 发布
查看>>
SQL Server 自定义函数(1)把某一列多行的值拼接成一个字符串
查看>>
Elasticsearch教程(九) elasticsearch 查询数据 | 分页查询
查看>>
yii 10.16
查看>>
读《程序员的SQL金典》[4]--SQL调优
查看>>
C#的delegate简单练习
查看>>
必须关注的25位知名JavaScript开发者
查看>>
[贝聊科技]谈谈 iOS 如何动态切换 APP 的主题
查看>>
如何克服解决Git冲突的恐惧症?(序)
查看>>
LaTeX模板(二)
查看>>
移动端解决方案学习记录
查看>>
算法与数据结构(七) 图论
查看>>
95后博士入职达摩院,14岁上大学,成阿里史上最年轻科学家
查看>>