找回密码
 立即注册

QQ登录

只需一步,快速开始

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

STC12C5A60S2 EEPROM 不能写入,有时来回多写几次又可以???

[复制链接]
跳转到指定楼层
楼主
ID:8625 发表于 2016-1-20 19:34 来自手机 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
代码都是在别程序移植过来的,写一次再读出来基本上都不成功,还是之前的内容,有时来回多写几次又可以,各位坛友有遇到这样的问题?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:79481 发表于 2016-1-20 20:09 | 只看该作者
写之前要擦出,才能写成功
回复

使用道具 举报

板凳
ID:60379 发表于 2016-1-20 20:52 | 只看该作者
以下内容来源于《51单片机轻松入门-基于STC15W4K系列》,一般不用修改即可正常使用。
7.2.2DataFlash操作实例(断电瞬间存储数据)
例7.3  STC15F2K60S2单片机内部DataFlash读写测试
本程序上电时先擦除DataFlash的第1个扇区,然后将前半扇区与后半扇区分别写入数据0~255,然后读出数据并判断与写入的数据是否一致,并通过串口助手显示程序运行过程中的数据与最终结果是否正常,R/C时钟频率22.1184MHz,串口通信波特率9600。
程序主要使用到2个模块文件FLASH.H与FLASH.C,在程序移植过程中,FLASH.H里需要定义R/C时钟频率和FLASH存储单元地址,FLASH.C无需作任何更改。
////////////////////////////////// FLASH.H /////////////////////////////////
#ifndef __FLASH_H__
#define __FLASH_H__
#include "STC15W4K.H"           // FLASH操作要控制中断开关EA  
#include <intrins.h>            // FLASH读写要用到 _nop_();
// FLASH读写擦除延时等待时间需要用到R/C时钟频率   
#define SYSclk      22118400L   //定义CPU实际运行的系统时钟,可以修改
#define EEP_address 0x0000      // 主程序从0000地址开始读写数据,可以修改
/******************** 写N个字节函数最多255字节一次 *****************/
void EEPROM_write_n(unsignedint EE_address,unsigned char *DataAddress,unsigned char lenth);
/******************** 读N个字节函数最多255字节一次 *****************/
void EEPROM_read_n(unsignedint EE_address,unsigned char *DataAddress,unsigned char lenth);  
/******************** 扇区擦除函数*****************/
voidEEPROM_SectorErase(unsigned int EE_address);
#endif
////////////////////////////////////// FLASH.C ////////////////////////////////////////
//                      此文件直接复制使用,用户无需任何更改。
#include"FLASH.h"  
// 寄存器定义,虽然头文件已有定义,但不会冲突,这里列出来方便理解程序。
sfr ISP_DATA  = 0xC2;
sfr ISP_ADDRH = 0xC3;
sfr ISP_ADDRL = 0xC4;
sfr ISP_CMD   = 0xC5;
sfr ISP_TRIG  = 0xC6;
sfr ISP_CONTR = 0xC7;
/////////////////////////////////FLASH 操作延时等待参数  ////////////////////////////
#if (SYSclk >= 24000000L)
    #define     ISP_WAIT_FREQUENCY  0
#elif (SYSclk >= 20000000L)
    #define     ISP_WAIT_FREQUENCY  1
#elif (SYSclk >= 12000000L)
    #define     ISP_WAIT_FREQUENCY  2
#elif (SYSclk >= 6000000L)
    #define     ISP_WAIT_FREQUENCY  3
#elif (SYSclk >= 3000000L)
    #define     ISP_WAIT_FREQUENCY  4
#elif (SYSclk >= 2000000L)
    #define     ISP_WAIT_FREQUENCY  5
#elif (SYSclk >= 1000000L)
    #define     ISP_WAIT_FREQUENCY  6
#else
    #define     ISP_WAIT_FREQUENCY  7
#endif   
/*************************禁止操作FLASH ( 固定不变 )*******************************/
void DisableEEPROM(void)        // 以下语句可以不用,只是出于安全考虑而已
{
    ISP_CONTR = 0;              //禁止ISP/IAP操作
    ISP_CMD   = 0;              // 去除ISP/IAP命令
    ISP_TRIG  = 0;              // 防止ISP/IAP命令误触发
    ISP_ADDRH = 0xff;           //指向非EEPROM区,防止误操作
    ISP_ADDRL = 0xff;           //指向非EEPROM区,防止误操作
}
/******************** 写N个字节函数最多255字节一次( 固定不变 ) *****************/
void EEPROM_write_n(unsignedint EE_address,unsigned char *DataAddress,unsigned char lenth)
{
    EA = 0;              // 禁止中断                                      
    ISP_CONTR = 0x80 + ISP_WAIT_FREQUENCY;  // 允许操作FLASH + 延时等待时间,送一次就够
    ISP_CMD = 2 ;                           // 字节写命令,命令不需改变时,不需重新送命令
    do
    {
        ISP_ADDRH = EE_address / 256;       //送地址高字节(地址需要改变时才需重新送地址)
        ISP_ADDRL = EE_address % 256;       //送地址低字节
        ISP_DATA  =*DataAddress;           // 送数据到ISP_DATA,只有数据改变时才需重新送
        ISP_TRIG = 0x5A;// ISP触发命令,先送5AH,再送A5H到ISP/IAP触发寄存器,每次都需要如此
        ISP_TRIG = 0xA5;// ISP触发命令,写字节最长需要55uS,因此本行语句会暂停55uS以上的时间
        _nop_();        
        EE_address++;                       //下一个地址
        DataAddress++;                      //下一个数据
    }while(--lenth);                        //直到结束
    DisableEEPROM();
    EA = 1;                                 // 重新允许中断
}
/******************** 读N个字节函数最多255字节一次 ( 固定不变 )*****************/
void EEPROM_read_n(unsignedint EE_address,unsigned char *DataAddress,unsigned char lenth)
{
    EA = 0;             // 禁止中断
    ISP_CONTR = 0x80 + ISP_WAIT_FREQUENCY;  // 允许操作FLASH + 延时等待时间,送一次就够
    ISP_CMD = 1 ;       // 字节读命令,命令不需改变时,不需重新送命令
    do
    {
        ISP_ADDRH = EE_address / 256;       //送地址高字节(地址需要改变时才需重新送地址)
        ISP_ADDRL = EE_address % 256;       //送地址低字节
        ISP_TRIG = 0x5A;                    //ISP触发命令
        ISP_TRIG = 0xA5;            
        // ISP触发命令,读一个字节最长需要2个时钟,因此本行语句会暂停2个时钟以上的时间
        _nop_();        
        *DataAddress = ISP_DATA;            //读出的数据送往外部变量地址
        EE_address++;
        DataAddress++;
    }while(--lenth);
    DisableEEPROM();                        
    EA = 1;            // 重新允许中断
}  
/******************** 扇区擦除函数( 固定不变 )  *****************/
voidEEPROM_SectorErase(unsigned int EE_address)
{
    EA = 0;              // 禁止中断
    // 只有扇区擦除,没有字节擦除,512字节/扇区。扇区中任意一个字节地址都是扇区地址。
    ISP_ADDRH = EE_address / 256;       //送扇区地址高字节(地址需要改变时才需重新送地址)
    ISP_ADDRL = EE_address % 256;           //送扇区地址低字节
    ISP_CONTR = 0x80 + ISP_WAIT_FREQUENCY;  // 允许操作FLASH + 延时等待时间,送一次就够
    ISP_CMD = 3;                            // 送扇区擦除命令,命令不需改变时,不需重新送命令
    ISP_TRIG = 0x5A;                        //ISP触发命令
    ISP_TRIG = 0xA5;    // ISP触发命令,擦除最长需要21mS,因此本行语句会暂停21mS以上的时间
    _nop_();        
    DisableEEPROM();                        //禁止命令
    EA = 1;             // 重新允许中断
}
///////////////////////////////////  主程序:Flash_Test.C  /////////////////////////////////
#include "FLASH.H"
#include"uart_debug.h"   
void main()
{      
    unsigned char a;
    unsigned int i;  
    UART_init();                       // 占用定时器1,波特率:9600/22.1184MHZ     
    UART_Send_Str("开始擦除\n");
    EEPROM_SectorErase(EEP_address);   // 扇区擦除
    UART_Send_Str("擦除完毕\n");
    for (i=0; i<512; i++)              // 检测是否擦除成功(全FF检测)
    {
         EEPROM_read_n(EEP_address+i,&a,1);   // 地址、数据、长度
         UART_Send_StrNum("擦除值:",a) ;
         if (a!=0xff)  goto Error;              // 如果校验错误,则退出
    }  
    UART_Send_Str("开始写入\n");            
    for (i=0; i<512; i++)                       // 编程512字节
    {
        a=i;
       EEPROM_write_n(EEP_address+i,&a,1);    // 地址、数据、长度
    }
    UART_Send_Str("写入完毕\n");   
    for (i=0; i<512; i++)                       // 校验512字节
    {
        EEPROM_read_n(EEP_address+i,&a,1);      // 地址、数据、长度
        UART_Send_StrNum("数据:",a);
        if (a!=i%256)  gotoError;              // 如果校验错误,则退出
    }
    UART_Send_Str("读出结束,测试正常");
    while (1);
Error:
    UART_Send_Str("数据错误");                  // IAP操作失败
    while (1);
}  
本程序使用“丁丁版本的串口调试助手”在电脑上显示接收到的数据,文本模式,9600波特率,测试结果正常,由于接收的数据量较大,其它串口助手可能会出现乱码或开始接收到的数据被后来的数据覆盖掉而不能完整显示的问题。

回复

使用道具 举报

地板
ID:8625 发表于 2016-1-20 22:46 来自手机 | 只看该作者
1176658950 发表于 2016-1-20 20:09
写之前要擦出,才能写成功

有擦除的
回复

使用道具 举报

5#
ID:8625 发表于 2016-1-20 22:50 来自手机 | 只看该作者
无量寿经 发表于 2016-1-20 20:52
以下内容来源于《51单片机轻松入门-基于STC15W4K系列》,一般不用修改即可正常使用。
7.2.2DataFlash操作 ...

多谢你,明天试试我这个程序也是通过串口接收内容之后用EEPROM保存的
回复

使用道具 举报

6#
ID:94642 发表于 2016-1-21 15:17 | 只看该作者
我的也是这个单片机,但是E2PROM断电后,读出的值是一个很大的数一闪而过,然后能够读取正常的值,这是什么情况
回复

使用道具 举报

7#
ID:8625 发表于 2016-2-19 11:18 来自手机 | 只看该作者
问题解决可,参数未传好
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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