查看: 3433|回复: 1

[分享] 【我要分享】Cortex-M3 (NXP LPC1788)之EEPROM存储器

[复制链接]

该用户从未签到

17

主题

32

帖子

0

注册会员

Rank: 2

积分
85
最后登录
2018-6-13
发表于 2017-2-28 08:57:26 | 显示全部楼层 |阅读模式
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后读出通过串口打印显示:

  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.      
  46.     void Init_EEPROM(void)
  47.     {
  48.         unsigned int val=0;
  49.          
  50.         rEEPWRDWN = 0;  //不处于掉电模式
  51.         rEECLKDIV = (CCLK/375000)-1;    //设置一个375KHZ的EEPROM时钟
  52.          
  53.         val  = ((((CCLK / 1000000) * 15) / 1000) + 1);      //配置等待状态时间
  54.         val |= (((((CCLK / 1000000) * 55) / 1000) + 1) << 8);
  55.         val |= (((((CCLK / 1000000) * 35) / 1000) + 1) << 16);
  56.         rEEWSTATE = val;
  57.     }
  58.     void Write_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count)
  59.     {
  60.         unsigned int i;
  61.          
  62.         rEEADDR = (page_offset&0x3f);   //确定开始写的页内偏移地址
  63.         for(i=0; i<count; i++)
  64.         {
  65.             rEECMD = 0x3;               //8位写操作
  66.             rEEWDATA = *(data+i);
  67.             while(!(rEEINTSTAT & (0x1<<26)));   //等待写操作完成
  68.             page_offset++;
  69.             
  70.             if(page_offset >= EEPROM_PAGE_SIZE)     //如果当前页写满了64Byte 则启动 编程操作
  71.             {
  72.                 rEEINTSTATCLR = 0x1<<28;
  73.                 rEEADDR = (page_num&0x3F)<<6;
  74.                 rEECMD = 0x6;   //擦除编程
  75.                 while(!(rEEINTSTAT & (0x1<<28)));   //等待编程完成
  76.                  
  77.                 page_offset = 0;
  78.                 page_num++;     //写满一页,准备写下一页
  79.                 rEEADDR = 0;    //写满一页,从页的开始写
  80.             }
  81.             elseif(i==count-1)                 //如果要写入EPPROM的数据写完成,启动编程操作
  82.             {
  83.                 rEEINTSTATCLR = 0x1<<28;
  84.                 rEEADDR = (page_num&0x3F)<<6;
  85.                 rEECMD = 0x6;   //擦除编程
  86.                 while(!(rEEINTSTAT & (0x1<<28)));
  87.             }
  88.         }
  89.     }
  90.      
  91.     void Read_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count)
  92.     {
  93.         unsigned int i;
  94.         rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F;      //确定读数据的起始位置,包括页偏移和页内的偏移
  95.         rEECMD = 0x1<<3;                                    //8位读,地址自动递增模式
  96.         for(i=0; i<count; i++)
  97.         {
  98.             while(!(rEEINTSTAT & (0x1<<26)));               //等待上一次读数据完成
  99.             *(data+i) = rEERDATA;
  100.             page_offset++;
  101.             
  102.             if(page_offset >= EEPROM_PAGE_SIZE)             //如果当前页64Byte读完,准备读下一页
  103.             {
  104.                 page_offset = 0;
  105.                 page_num++;
  106.                 rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F;   
  107.                 rEECMD = 0x1<<3;
  108.             }
  109.         }
  110.     }
复制代码
  1. #include "LPC1788_REG.h"
  2. #include "uart.h"

  3. #define rEECMD          (*(volatile unsigned*)(0x00200080))
  4. #define rEEADDR         (*(volatile unsigned*)(0x00200084))
  5. #define rEEWDATA        (*(volatile unsigned*)(0x00200088))
  6. #define rEERDATA        (*(volatile unsigned*)(0x0020008C))
  7. #define rEEWSTATE       (*(volatile unsigned*)(0x00200090))
  8. #define rEECLKDIV       (*(volatile unsigned*)(0x00200094))
  9. #define rEEPWRDWN       (*(volatile unsigned*)(0x00200098))

  10. #define rEEINTEN        (*(volatile unsigned*)(0x00200FE4))
  11. #define rEEINTCLR       (*(volatile unsigned*)(0x00200FD8))
  12. #define rEEINTSET       (*(volatile unsigned*)(0x00200FDC))
  13. #define rEEINTSTAT      (*(volatile unsigned*)(0x00200FE0))
  14. #define rEEINTSTATCLR   (*(volatile unsigned*)(0x00200FE8))
  15. #define rEEINTSTATSET   (*(volatile unsigned*)(0x00200FEC))

  16. #define EEPROM_PAGE_SIZE 64
  17. void Init_EEPROM(void);
  18. void Write_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count);
  19. void Read_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count);

  20. char read_buffer[];
  21. char write_buffer[] = {"\n\r\
  22. \t - Name: Nuncle.lee \n\r\
  23. \t - QQ: 23610603 \n\r\
  24. \t - Email: nuncle.lee@gmail.com\n\r"};

  25. int main(void)
  26. {   
  27.     Init_Uart2();
  28.     Init_EEPROM();
  29.    
  30.    
  31.     Write_EEPROM(0, 0, write_buffer, sizeof(write_buffer));
  32.     Write_EEPROM(sizeof(write_buffer)/64, sizeof(write_buffer)%64, '\0', 1);
  33.    
  34.     Read_EEPROM(0, 0, read_buffer, sizeof(write_buffer)+1);
  35.    
  36.     Uart2SendS(read_buffer);

  37.     return 0;
  38. }

  39. void Init_EEPROM(void)
  40. {
  41.     unsigned int val=0;
  42.    
  43.     rEEPWRDWN = 0;  //不处于掉电模式
  44.     rEECLKDIV = (CCLK/375000)-1;    //设置一个375KHZ的EEPROM时钟
  45.    
  46.     val  = ((((CCLK / 1000000) * 15) / 1000) + 1);      //配置等待状态时间
  47.         val |= (((((CCLK / 1000000) * 55) / 1000) + 1) << 8);
  48.         val |= (((((CCLK / 1000000) * 35) / 1000) + 1) << 16);
  49.     rEEWSTATE = val;
  50. }
  51. void Write_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count)
  52. {
  53.     unsigned int i;
  54.    
  55.     rEEADDR = (page_offset&0x3f);   //确定开始写的页内偏移地址
  56.     for(i=0; i<count; i++)
  57.     {
  58.         rEECMD = 0x3;               //8位写操作
  59.         rEEWDATA = *(data+i);
  60.         while(!(rEEINTSTAT & (0x1<<26)));   //等待写操作完成
  61.         page_offset++;
  62.         
  63.         if(page_offset >= EEPROM_PAGE_SIZE)     //如果当前页写满了64Byte 则启动 编程操作
  64.         {
  65.             rEEINTSTATCLR = 0x1<<28;
  66.             rEEADDR = (page_num&0x3F)<<6;
  67.             rEECMD = 0x6;   //擦除编程
  68.             while(!(rEEINTSTAT & (0x1<<28)));   //等待编程完成
  69.             
  70.             page_offset = 0;
  71.             page_num++;     //写满一页,准备写下一页
  72.             rEEADDR = 0;    //写满一页,从页的开始写
  73.         }
  74.         else if(i==count-1)                 //如果要写入EPPROM的数据写完成,启动编程操作
  75.         {
  76.             rEEINTSTATCLR = 0x1<<28;
  77.             rEEADDR = (page_num&0x3F)<<6;
  78.             rEECMD = 0x6;   //擦除编程
  79.             while(!(rEEINTSTAT & (0x1<<28)));
  80.         }
  81.     }
  82. }

  83. void Read_EEPROM(unsigned char page_num, unsigned char page_offset, char* data, unsigned int count)
  84. {
  85.     unsigned int i;
  86.     rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F;      //确定读数据的起始位置,包括页偏移和页内的偏移
  87.     rEECMD = 0x1<<3;                                    //8位读,地址自动递增模式
  88.     for(i=0; i<count; i++)
  89.     {
  90.         while(!(rEEINTSTAT & (0x1<<26)));               //等待上一次读数据完成
  91.         *(data+i) = rEERDATA;
  92.         page_offset++;
  93.         
  94.         if(page_offset >= EEPROM_PAGE_SIZE)             //如果当前页64Byte读完,准备读下一页
  95.         {
  96.             page_offset = 0;
  97.             page_num++;
  98.             rEEADDR = (page_num&0x3F)<<6|page_offset&0x3F;  
  99.             rEECMD = 0x1<<3;
  100.         }
  101.     }
  102. }
复制代码
序的执行结果如下图
1341819637_2250.jpg
程序中,sizeof关键字计算出字符数组的大小,并不包含字符串的结束标志‘\0’。因此还需在sizeof(write_buffer)的位置写入字符串的结束标志。读取时读sizeof(write_buffer)+1个字节,才能正确的通过串口打印数据。当然,也可以自己指定串口打印字符的个数,而不用字符串结束标志去判断。

回复

使用道具 举报

  • TA的每日心情
    擦汗
    2017-10-15 13:16
  • 签到天数: 191 天

    连续签到: 1 天

    [LV.7]常住居民III

    11

    主题

    664

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1722
    最后登录
    2017-10-15
    发表于 2017-2-28 09:22:05 | 显示全部楼层
    谢谢分享                     
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-23 10:59 , Processed in 0.099197 second(s), 25 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表