zoukankan      html  css  js  c++  java
  • (转)CortexM3 (NXP LPC1788)之EEPROM存储器

    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 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<count; 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<count; 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个字节,才能正确的通过串口打印数据。当然,也可以自己指定串口打印字符的个数,而不用字符串结束标志去判断。

  • 相关阅读:
    深拷贝与浅拷贝+可变与不可变的数据类型
    列表+列表循环+列表切片+元祖
    接口+session与cookie的区别+http状态码
    JSP中文乱码问题终极解决方案
    关于AS使用git的那些奇葩事儿
    ListView中动态显示隐藏HeaderView和FooterView
    关于沉浸式的那些奇葩问题
    Android Bug分析系列:第三方平台安装app启动后,home键回到桌面后点击app启动时会再次启动入口类bug的原因剖析
    快速搭建tab
    使用 gradle 在编译时动态设置 Android resValue / BuildConfig / Manifes中<meta-data>变量的值
  • 原文地址:https://www.cnblogs.com/tdyizhen1314/p/2704601.html
Copyright © 2011-2022 走看看