找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1097|回复: 2
打印 上一主题 下一主题
收起左侧

STC单片机的EEPROM问题

[复制链接]
跳转到指定楼层
楼主
  1. .C


  2. #include "eeprom.h"

  3. #include        "STC15Fxxxx.H"





  4. //========================================================================
  5. // 函数: void        ISP_Disable(void)
  6. // 描述: 禁止访问ISP/IAP.
  7. // 参数: non.
  8. // 返回: non.
  9. // 版本: V1.0, 2022-05-28
  10. //========================================================================
  11. void        DisableEEPROM(void)
  12. {
  13.         ISP_CONTR = 0;                        //禁止ISP/IAP操作
  14.         ISP_CMD   = 0;                        //去除ISP/IAP命令
  15.         ISP_TRIG  = 0;                        //防止ISP/IAP命令误触发
  16.         
  17.         ISP_ADDRH = 0xff;                //清0地址高字节
  18.         ISP_ADDRL = 0xff;                //清0地址低字节,指向非EEPROM区,防止误操作
  19. }

  20. //========================================================================
  21. // 函数: void EEPROM_read_n(u16 EE_address,u8 *DataAddress,u16 number)
  22. // 描述: 从指定EEPROM首地址读出n个字节放指定的缓冲.
  23. // 参数: EE_address:  读出EEPROM的首地址.
  24. //       DataAddress: 读出数据放缓冲的首地址.
  25. //       number:      读出的字节长度.
  26. // 返回: non.
  27. // 版本: V1.0, 2022-05-28
  28. //========================================================================

  29. void EEPROM_read_n(u16 EE_address,u8 *DataAddress,u16 number)
  30. {
  31.         ISP_CONTR = (ISP_EN + ISP_WAIT_FREQUENCY);        //设置等待时间,允许ISP/IAP操作,送一次就够
  32.         ISP_READ();                                                                                        //送字节读命令,命令不需改变时,不需重新送命令
  33.         
  34.         do
  35.         {
  36.                 ISP_ADDRH = EE_address / 256;                          //送地址高字节(地址需要改变时才需重新送地址)
  37.                 ISP_ADDRL = EE_address % 256;                          //送地址低字节
  38.                 _ISP_TRIG();                                                                        //先送5AH,再送A5H到ISP/IAP触发寄存器,每次都需要如此
  39.                                                                                                                 //送完A5H后,ISP/IAP命令立即被触发启动
  40.                                                                                                                 //CPU等待IAP完成后,才会继续执行程序。
  41.                 _nop_();
  42.                
  43.                 *DataAddress = ISP_DATA;                                    //读出的数据送往
  44.                
  45.                 EE_address++;
  46.                 DataAddress++;
  47.         }while(--number);
  48.         
  49.         
  50.         DisableEEPROM();
  51. }


  52. /******************** 扇区擦除函数 *****************/
  53. //========================================================================
  54. // 函数: void EEPROM_SectorErase(u16 EE_address)
  55. // 描述: 把指定地址的EEPROM扇区擦除.
  56. // 参数: EE_address:  要擦除的扇区EEPROM的地址.
  57. // 返回: non.
  58. // 版本: V1.0, 2022-05-28
  59. //========================================================================
  60. void EEPROM_SectorErase(u16 EE_address)
  61. {
  62.                                                                                                                 //只有扇区擦除,没有字节擦除,512字节/扇区。
  63.                                                                                                                 //扇区中任意一个字节地址都是扇区地址。
  64.         ISP_ADDRH = EE_address / 256;                                  //送扇区地址高字节(地址需要改变时才需重新送地址)
  65.         ISP_ADDRL = EE_address % 256;                                  //送扇区地址低字节
  66.         
  67.         ISP_CONTR = (ISP_EN + ISP_WAIT_FREQUENCY);        //设置等待时间,允许ISP/IAP操作,送一次就够
  68.         
  69.         ISP_ERASE();                                                                          //送扇区擦除命令,命令不需改变时,不需重新送命令
  70.         
  71.         _ISP_TRIG();                                                                          //先送5AH,再送A5H到ISP/IAP触发寄存器,每次都需要如此
  72.                                                                                                                 //送完A5H后,ISP/IAP命令立即被触发启动
  73.         
  74.         _nop_();
  75.         
  76.         DisableEEPROM();
  77. }

  78. //========================================================================
  79. // 函数: void EEPROM_write_n(u16 EE_address,u8 *DataAddress,u16 number)
  80. // 描述: 把缓冲的n个字节写入指定首地址的EEPROM.
  81. // 参数: EE_address:  写入EEPROM的首地址.
  82. //       DataAddress: 写入源数据的缓冲的首地址.
  83. //       number:      写入的字节长度.
  84. // 返回: non.
  85. // 版本: V1.0, 2022-05-28
  86. //========================================================================
  87. void EEPROM_write_n(u16 EE_address,u8 *DataAddress,u16 number)
  88. {
  89.         ISP_CONTR = (ISP_EN + ISP_WAIT_FREQUENCY);        //设置等待时间,允许ISP/IAP操作,送一次就够
  90.         
  91.         ISP_WRITE();                                                                          //送字节写命令,命令不需改变时,不需重新送命令
  92.         
  93.         do
  94.         {
  95.                 ISP_ADDRH = EE_address / 256;                          //送地址高字节(地址需要改变时才需重新送地址)
  96.                 ISP_ADDRL = EE_address % 256;                           //送地址低字节
  97.                
  98.                 ISP_DATA  = *DataAddress;                                    //送数据到ISP_DATA,只有数据改变时才需重新送
  99.                
  100.                 _ISP_TRIG();                                                                        //先送5AH,再送A5H到ISP/IAP触发寄存器,每次都需要如此
  101.                                                                                                                 //送完A5H后,ISP/IAP命令立即被触发启动
  102.                
  103.                 _nop_();
  104.                
  105.                 EE_address++;
  106.                 DataAddress++;
  107.         }while(--number);

  108.         DisableEEPROM();
  109. }
复制代码


STC芯片的IAP版本:IAP15F2K61S2

使用官方IAP示例代码测试,如代码所示:

IAP15F2K61S2据说整片Flash都可以模拟EEPROM,地址:0x0000-0xF3FF(测试时需要避开程序空间,测试读写地址:0xF200)使用官方IAP示例代码测试

测试:部分代码

unsigned char EPR1[20]={0x20,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

写:

EEPROM_SectorErase(0xF200);                //擦除一个扇区
EEPROM_write_n(0xF200,EPR1,sizeof(EPR1));  //写

读:
EEPROM_read_n(0xF200,EPR1,sizeof(EPR1));  //读出n字节,存放在EPR1数组内
uartWrite(EPR1,sizeof(EPR1));//串口发送


测试结果如图:

问题:
1,代码是使用IAP读写官方Demo修改,有没有问题?

2,正常读出来的数据为0x20,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,但是芯片运行一段时间后,Flash好像无法通过IAP程序再次读写了,即读出来都是0x00,目测坏了,更换新的同型号芯片又没有问题了(代码均一致,只是换了新的芯片),但是或者有什么办法修复一下?还是代码哪里可以优化一下?又感觉没坏,因为程序还在正常运行,只是没办法通过IAP读写Flash,来模拟EEPROM了


PS:正常与非正常的芯片,代码运行均正常(因为串口发送0x15是用来测试IC的,由此得出芯片其实除了IAP,其他正常),读写次数最多也没超过100次,地址均为0xF200,且没有与程序区冲突,就坏了


没有遇到过类似无法IAP读写的问题,分享一下!


1正常.png (15.48 KB, 下载次数: 8)

1正常.png

2非正常.png (10.77 KB, 下载次数: 8)

2非正常.png
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:526108 发表于 2022-10-5 15:47 | 只看该作者
http://www.51hei.com/bbs/dpj-223265-1.html
用这软件生成通用型EEPROM函数,简单明了
回复

使用道具 举报

板凳
ID:213173 发表于 2022-10-5 16:56 | 只看该作者
所有端口初始化为准双向口试试,以前用IAP15F4K58S4吃过苦头。
        P0M0 = 0x00;
        P0M1 = 0x00;
        P1M0 = 0x00;
        P1M1 = 0x00;
        P2M0 = 0x00;
        P2M1 = 0x00;
        P3M0 = 0x00;
        P3M1 = 0x00;
        P4M0 = 0x00;
        P4M1 = 0x00;
        P5M0 = 0x00;
        P5M1 = 0x00;
        P6M0 = 0x00;
        P6M1 = 0x00;
        P7M0 = 0x00;
        P7M1 = 0x00;
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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