找回密码
 立即注册
查看: 68|回复: 8

STC8H1K08存储数据问题

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2025-09-30 10:59:40
已绑定手机

6

主题

12

回帖

120

积分

注册会员

积分
120
发表于 6 天前 | 显示全部楼层 |阅读模式
使用STC8H1K08存储数据问题,先擦除,然后写入,再打印确认,结果发现打印的数据不对.

u8  DatastoreTest;
u8  DataPrintTmp;

u8  xdata   DataStore[8];

const u8 DataStoreT[8] = {0xCC, 0xCC, 0xCC, 0xCC, 0xBB, 0xBB, 0xBB, 0xBB};

u8   xdata   DataPrint[8];

#define  DataAddres        0x0004   


//********测试将数据存入EEPROM**********
void StoreBattery_value(void)
{
        ++ DatastoreTest;
        if (DatastoreTest > 100)
        {
                DatastoreTest = 0;
        }       
       
        EEPROM_SectorErase(DataAddres); //擦除扇区
        delay_ms(10);

  EEPROM_write_n(DataAddres, DataStoreT, 8);

        printf("*****DatastoreTest = 0x%04X\n", DatastoreTest);

        printf("DataStoreT[0] = 0x%02X\n", DataStoreT[0]);
        printf("DataStoreT[1] = 0x%02X\n", DataStoreT[1]);
        printf("DataStoreT[2] = 0x%02X\n", DataStoreT[2]);
        printf("DataStoreT[3] = 0x%02X\n", DataStoreT[3]);
        printf("DataStoreT[4] = 0x%02X\n", DataStoreT[4]);
        printf("DataStoreT[5] = 0x%02X\n", DataStoreT[5]);       
        printf("DataStoreT[6] = 0x%02X\n", DataStoreT[6]);       
        printf("DataStoreT[7] = 0x%02X\n", DataStoreT[7]);                  

}       


//********test 从EEPROM打印电压数据**********
void ReadBattery_value(void)
{
        EEPROM_read_n (DataAddres,DataPrint,8);       
        DataPrintTmp = (DataPrint[2] << 8) | DataPrint[3];         // 从DataStore[2]和DataStore[3]还原BatValueLast
        DBG_PRINTF("****EEPROM ReadBattery_value =: %d\n",Battery_value);       


   // 打印存储后的结果
        printf("*****DataPrintTmp = 0x%04X\n", DataPrintTmp);
        printf("----- 1111 DataRead From EEprom[2]-----\r\n");       
               
        printf("DataPrint[0] = 0x%02X\n", DataPrint[0]);       
        printf("DataPrint[1] = 0x%02X\n", DataPrint[1]);       
        printf("DataPrint[2] = 0x%02X\n", DataPrint[2]);
        printf("DataPrint[3] = 0x%02X\n", DataPrint[3]);
        printf("DataPrint[4] = 0x%02X\n", DataPrint[4]);
        printf("DataPrint[5] = 0x%02X\n", DataPrint[5]);        
        printf("DataPrint[6] = 0x%02X\n", DataPrint[6]);        
        printf("DataPrint[7] = 0x%02X\n", DataPrint[7]);                
}

运行后,打印的却不是完成的写入数据:

[15:54:36.110]接收←*****DatastoreTest = 0x4CEC
                    DataStoreT[0] = 0xCCEC
                    DataStoreT[1] = 0xCCEC
                    DataStoreT[2] = 0xCCEC
                    DataStoreT[3] = 0xCCEC
                    DataStoreT[4] = 0xBBEC
                    DataStoreT[5] = 0xBBEC
                    DataStoreT[6] = 0xBBEC
                    DataStoreT[7] = 0xBBEC
                    -------- StoreBattery_value: 1
                    ****EEPROM ReadBattery_value =: 0
                    *****DataPrintTmp = 0x8800
                    ----- 1111 DataRead From EEprom[2]-----
                    DataPrint[0] = 0x8800
                    DataPrint[1] = 0x8800
                    DataPrint[2] = 0x8800
                    DataPrint[3] = 0x8800
                    DataPrint[4] = 0xBB00
                    DataPrint[5] = 0xBB00
                    DataPrint[6] = 0xBB00
                    DataPrint[7] = 0xBB00





米高
回复

使用道具 举报 送花

3

主题

1928

回帖

704

积分

等待验证会员

积分
704
发表于 6 天前 | 显示全部楼层
关于您在使用STC8H1K08进行EEPROM数据存储过程中出现的“写入后读取数据不一致”的问题,本文将从硬件原理、代码逻辑、常见问题及调试建议等方面进行全面分析,以帮助您定位问题并提出解决方案。

一、问题描述

您在使用STC8H1K08的EEPROM功能时,执行如下操作流程:

1. 擦除指定地址的扇区;
2. 写入固定数据;
3. 打印写入的数据与读取的数据,发现数据不一致。

代码中涉及如下关键点:
使用xdata关键字定义了DataStore[8]和DataPrint[8]数组;
定义了一个常量数组DataStoreT[8]用于写入;
使用宏定义DataAddres为0x0004;
调用EEPROMSectorErase(DataAddres)进行扇区擦除;
调用EEPROMwriten(DataAddres, DataStoreT, 8)进行写入;
使用printf()打印写入内容和测试变量。

二、EEPROM写入机制分析

STC8H系列单片机内置EEPROM模块,其工作原理与Flash类似,具有以下特点:

1. 擦写限制:每个扇区必须先擦除后写入,不能直接覆盖;
2. 写入单位:通常以字节或页为单位进行写入;
3. 擦除单位:通常以扇区为单位(如512字节);
4. 写入前必须擦除:否则写入失败或数据错误;
5. 写入速度较慢:需适当延时确保完成;
6. 地址对齐要求:部分型号要求写入地址为页对齐或扇区对齐。

三、代码分析与潜在问题

1. 擦除操作是否正确?

您使用了EEPROMSectorErase(DataAddres),其中DataAddres = 0x0004。需要确认:
该地址是否属于某个扇区的起始地址?如果不是,擦除可能影响到相邻数据;
STC8H1K08的EEPROM扇区大小是多少?例如是否为512字节?如果扇区大小为512字节,擦除0x0004将擦除整个0x0000~0x01FF扇区;
擦除后是否延时足够?虽然您使用了delayms(10),但建议查阅芯片手册确认最小擦除时间。

2. 写入操作是否正确?

使用EEPROMwriten(DataAddres, DataStoreT, 8)写入8字节数据,需注意:
EEPROMwriten()函数是否支持非页对齐地址写入?
是否存在写入缓冲区未刷新或未完成的情况?
是否有写入保护机制或校验失败?

3. 数据定义是否正确?
const u8 DataStoreT[8]为常量数组,理论上不会被修改,但需确认是否在EEPROM写入前被正确初始化;
DataStoreT的地址是否在程序运行期间被优化或覆盖?

4. 打印输出是否及时?
printf()函数是否为同步输出?在某些系统中,printf()可能为异步或缓存输出,导致打印结果与实际执行顺序不一致;
建议在打印后加入fflush(stdout)或等效操作,确保输出立即刷新。

四、常见问题与解决方案

问题1:写入地址未对齐

现象:写入失败或数据混乱  
解决方法:确认写入地址为页或扇区对齐,例如页大小为8字节,则写入地址应为0x0000、0x0008、0x0010等。

问题2:写入前未正确擦除

现象:写入失败或旧数据残留  
解决方法:确保写入前已擦除目标地址所在的整个扇区,并加入足够延时。

问题3:写入函数未正确实现

现象:数据写入不完整或错误  
解决方法:检查EEPROMwriten()函数的实现,确认其是否按芯片手册要求操作,包括状态检查、等待写入完成标志等。

问题4:EEPROM寿命耗尽

现象:写入失败或数据不稳定  
解决方法:EEPROM擦写次数有限(通常为10万次),若频繁擦写可能导致扇区损坏。建议更换扇区测试或使用磨损均衡算法。

问题5:变量定义与作用域问题

现象:打印数据与预期不符  
解决方法:检查DataPrint是否被正确读取,是否与写入数据地址一致,是否被其他函数修改。

五、建议改进代码
  1. c
  2. void StoreBatteryvalue(void)
  3. {
  4.     ++DatastoreTest;
  5.     if (DatastoreTest > 100)
  6.     {
  7.         DatastoreTest = 0;
  8.     }
  9.     // 确保写入地址为扇区起始地址
  10.     EEPROMSectorErase(DataAddres & (~0x01FF)); // 假设扇区大小为512字节
  11.     delayms(100); // 增加延时,确保擦除完成
  12.     EEPROMwriten(DataAddres, DataStoreT, 8);
  13.     // 延时确保写入完成
  14.     delayms(10);
  15.     // 读取回读数据
  16.     EEPROMreadn(DataAddres, DataPrint, 8);
  17.     printf("DatastoreTest = 0x%02X\n", DatastoreTest);
  18.     printf("Written Data[0] = 0x%02X\n", DataStoreT[0]);
  19.     printf("Written Data[1] = 0x%02X\n", DataStoreT[1]);
  20.     printf("Written Data[2] = 0x%02X\n", DataStoreT[2]);
  21.     printf("Written Data[3] = 0x%02X\n", DataStoreT[3]);
  22.     printf("Readback Data[0] = 0x%02X\n", DataPrint[0]);
  23.     printf("Readback Data[1] = 0x%02X\n", DataPrint[1]);
  24.     printf("Readback Data[2] = 0x%02X\n", DataPrint[2]);
  25.     printf("Readback Data[3] = 0x%02X\n", DataPrint[3]);
  26.     // 刷新输出缓冲区(如有)
  27.     // fflush(stdout);
  28. }
复制代码

六、调试建议

1. 使用逻辑分析仪或示波器:观察EEPROM写入时序是否符合手册要求;
2. 使用调试器读取EEPROM内容:绕过程序读取方式,直接查看物理地址内容;
3. 更换写入地址:尝试写入其他扇区,排除扇区损坏可能;
4. 减少写入频率:避免频繁擦写,延长EEPROM寿命;
5. 加入错误检测机制:如CRC校验、数据对比等,增强系统鲁棒性。

七、总结

您遇到的“写入EEPROM后数据不一致”问题,可能是由地址未对齐、擦除不完整、写入函数实现不当、变量作用域冲突或EEPROM硬件损坏等原因引起。建议从以下几个方面着手排查:
确认写入地址是否对齐;
增加擦写延时;
检查写入函数实现;
加入回读验证;
使用调试工具辅助分析。

通过系统性地排查与验证,可有效定位问题根源并加以解决。

如需进一步协助,建议提供以下信息:
EEPROMSectorErase()和EEPROMwriten()的具体实现;
STC8H1K08的EEPROM扇区大小与写入页大小;
实际打印输出结果;
使用的开发环境与编译器版本。

祝您调试顺利!

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2025-09-30 10:59:40
已绑定手机

6

主题

12

回帖

120

积分

注册会员

积分
120
发表于 6 天前 | 显示全部楼层
我们读写擦除的地址代码是:
IAP_ADDRH = EE_address / 256;  // 实际应写地址高8位
IAP_ADDRL = EE_address % 256;// 实际应写地址低8位
为何不是:

IAP_ADDRH = (EE_address >> 8) & 0xFF;  // 取地址高8位
IAP_ADDRL = EE_address & 0xFF;        // 取地址低8位

点评

这两个在同样是16位数据下是等效的  详情 回复 发表于 3 天前
米高
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2025-09-30 10:59:40
已绑定手机

6

主题

12

回帖

120

积分

注册会员

积分
120
发表于 3 天前 | 显示全部楼层
/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
/* --- BBS: www.STCAIMCU.com  -----------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序        */
/*---------------------------------------------------------------------*/


/*************  本程序功能说明  **************

本例程基于STC8H8K64U为主控芯片的实验箱9进行编写测试,STC8G、STC8H系列芯片可通用参考.

通过串口2(P4.6 P4.7)对STC内部自带的EEPROM(FLASH)进行读写测试。

对FLASH做扇区擦除、写入、读出的操作,命令指定地址。

默认波特率:  115200,8,N,1.
默认主时钟:  22.1184MHz.

串口命令设置: (命令字母不区分大小写)
    W 0x0040 1234567890  --> 对0x0040地址写入字符1234567890.
    R 0x0040 10          --> 对0x0040地址读出10个字节数据.

注意:下载时,下载界面"硬件选项"中设置用户EEPROM大小,

并确保串口命令中的地址在EEPROM设置的大小范围之内。

******************************************/

#include "stc8h.h"       //包含此头文件后,不需要再包含"reg51.h"头文件
#include "intrins.h"
#include "gloabe.h"

#include "main.h"
#define     MAIN_Fosc       22118400L   //定义主时钟(精确计算115200波特率)

typedef     unsigned char   u8;
typedef     unsigned int    u16;
typedef     unsigned long   u32;

#define     checkEEpromLog1          0XAAAA      //读写EEPROM缓冲长度
#define     checkEEpromLog2         0XBBBB      //读写EEPROM缓冲长度


#define     Baudrate2           115200L
#define     Tmp_Length          100      //读写EEPROM缓冲长度

#define     UART2_BUF_LENGTH    (Tmp_Length+9)  //串口缓冲长度


u8  RX2_TimeOut;
u8  TX2_Cnt;    //发送计数
u8  RX2_Cnt;    //接收计数
bit B_TX2_Busy; //发送忙标志

u8  xdata   RX2_Buffer[UART2_BUF_LENGTH];   //接收缓冲
u8  xdata   tmp[Tmp_Length];        //EEPROM操作缓冲
//u16  xdata   DataStore[5];
u8 DataStore[32];
//u8 DataStoreT[8];
const u8 DataStoreT[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};//默认688,满电
const u8 DataStoreT1[8] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB};

u8 DataPrint[32];
const u8 DataFactory[8] = {0xAA, 0xBB, 0x02, 0xB0, 0xFF, 0xFF, 0xFF, 0xFF};//默认688,满电
//#define  DataAddres        0x0E00
#define  DataAddres        0x0000   

void    UART2_config(u8 brt);   // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
void    PrintString2(u8 *puts);
void    UART2_TxByte(u8 dat);
void    delay_ms(u8 ms);
u8      CheckData(u8 dat);
u16     GetAddress(void);
u8      GetDataLength(void);
void    EEPROM_SectorErase(u16 EE_address);
void    EEPROM_read_n(u16 EE_address,u8 *DataAddress,u8 length);
u8      EEPROM_write_n(u16 EE_address,u8 *DataAddress,u8 length);



void CheckEEpromData(void);

/********************* 主函数 *************************/
//void main(void)
//{
//    u8  i,j;
//    u16 addr;
//    u8  status;

//    P_SW2 |= 0x80;  //扩展寄存器(XFR)访问使能

////    P0M1 = 0x30;   P0M0 = 0x30;   //设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
////    P1M1 = 0x30;   P1M0 = 0x30;   //设置P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V)
////    P2M1 = 0x3c;   P2M0 = 0x3c;   //设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
////    P3M1 = 0x50;   P3M0 = 0x50;   //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
////    P4M1 = 0x3c;   P4M0 = 0x3c;   //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
////    P5M1 = 0x0c;   P5M0 = 0x0c;   //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
////    P6M1 = 0xff;   P6M0 = 0xff;   //设置为漏极开路(实验箱加了上拉电阻到3.3V)
////    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

//    UART2_config(2);    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
//    EA = 1; //允许总中断

//    PrintString2("STC8H8K64U系列单片机EEPROM测试程序,串口命令设置如下:\r\n");    //UART2发送一个字符串
//    PrintString2("W 0x0040 1234567890  --> 对0x0040地址写入字符1234567890.\r\n");   //UART2发送一个字符串
//    PrintString2("R 0x0040 10          --> 对0x0040地址读出10个字节内容.\r\n"); //UART2发送一个字符串

//    while(1)
//    {
//        delay_ms(1);
//        if(RX2_TimeOut > 0)     //超时计数
//        {
//            if(--RX2_TimeOut == 0)
//            {
//              for(i=0; i<RX2_Cnt; i++)    UART2_TxByte(RX2_Buffer);    //把收到的数据原样返回,用于测试

//                status = 0xff;  //状态给一个非0值
//                if((RX2_Cnt >= 10) && (RX2_Buffer[1] == ' ') && (RX2_Buffer[8] == ' ')) //最短命令为10个字节
//                {
//                    for(i=0; i<8; i++)
//                    {
//                        if((RX2_Buffer >= 'a') && (RX2_Buffer <= 'z'))    RX2_Buffer = RX2_Buffer - 'a' + 'A';  //小写转大写
//                    }
//                    addr = GetAddress();
//                    if(addr < 63488)    //限制在0~123扇区
//                    {
//                        if(RX2_Buffer[0] == 'W')    //写入N个字节
//                        {
//                            j = RX2_Cnt - 9;
//                            if(j > Tmp_Length)  j = Tmp_Length; //越界检测
//                            EEPROM_SectorErase(addr);           //擦除扇区
//                            i = EEPROM_write_n(addr,&RX2_Buffer[9],j);      //写N个字节
//                            if(i == 0)
//                            {
//                                PrintString2("已写入");
//                                if(j >= 100)    {UART2_TxByte(j/100+'0');   j = j % 100;}
//                                if(j >= 10)     {UART2_TxByte(j/10+'0');    j = j % 10;}
//                                UART2_TxByte(j%10+'0');
//                                PrintString2("字节!\r\n");
//                            }
//                            else    PrintString2("写入错误!\r\n");
//                            status = 0; //命令正确
//                        }

//                        else if(RX2_Buffer[0] == 'R')   //PC请求返回N字节EEPROM数据
//                        {
//                            j = GetDataLength();
//                            if(j > Tmp_Length)  j = Tmp_Length; //越界检测
//                            if(j > 0)
//                            {
//                                PrintString2("读出");
//                                UART2_TxByte(j/10+'0');
//                                UART2_TxByte(j%10+'0');
//                                PrintString2("个字节内容如下:\r\n");
//                                EEPROM_read_n(addr,tmp,j);
//                                for(i=0; i<j; i++)  UART2_TxByte(tmp);
//                                UART2_TxByte(0x0d);
//                                UART2_TxByte(0x0a);
//                                status = 0; //命令正确
//                            }
//                        }
//                    }
//                }
//                if(status != 0) PrintString2("命令错误!\r\n");
//                RX2_Cnt  = 0;   //清除字节数
//            }
//        }
//    }
//}
//========================================================================


//========================================================================
// 函数: void delay_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-3-9
// 备注:
//========================================================================
void delay_ms(u8 ms)
{
     u16 i;
     do{
          i = MAIN_Fosc / 10000;
          while(--i);   //10T per loop
     }while(--ms);
}

//========================================================================
// 函数: u8 CheckData(u8 dat)
// 描述: 将字符"0~9,A~F或a~f"转成十六进制.
// 参数: dat: 要检测的字符.
// 返回: 0x00~0x0F为正确. 0xFF为错误.
// 版本: V1.0, 2012-10-22
//========================================================================
u8 CheckData(u8 dat)
{
    if((dat >= '0') && (dat <= '9'))        return (dat-'0');
    if((dat >= 'A') && (dat <= 'F'))        return (dat-'A'+10);
    return 0xff;
}

//========================================================================
// 函数: u16    GetAddress(void)
// 描述: 计算各种输入方式的地址.
// 参数: 无.
// 返回: 16位EEPROM地址.
// 版本: V1.0, 2013-6-6
//========================================================================
u16 GetAddress(void)
{
    u16 address;
    u8  i,j;
   
    address = 0;
    if((RX2_Buffer[2] == '0') && (RX2_Buffer[3] == 'X'))
    {
        for(i=4; i<8; i++)
        {
            j = CheckData(RX2_Buffer);
            if(j >= 0x10)   return 65535;   //error
            address = (address << 4) + j;
        }
        return (address);
    }
    return  65535;  //error
}

/**************** 获取要读出数据的字节数 ****************************/
u8 GetDataLength(void)
{
    u8  i;
    u8  length;
   
    length = 0;
    for(i=9; i<RX2_Cnt; i++)
    {
        if(CheckData(RX2_Buffer) >= 10)  break;
        length = length * 10 + CheckData(RX2_Buffer);
    }
    return (length);
}


//========================================================================
// 函数: void UART2_TxByte(u8 dat)
// 描述: 发送一个字节.
// 参数: 无.
// 返回: 无.
// 版本: V1.0, 2014-6-30
//========================================================================
void UART2_TxByte(u8 dat)
{
    S2BUF = dat;
    B_TX2_Busy = 1;
    while(B_TX2_Busy);
}


//========================================================================
// 函数: void PrintString2(u8 *puts)
// 描述: 串口2发送字符串函数。
// 参数: puts:  字符串指针.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void PrintString2(u8 *puts) //发送一个字符串
{
    for (; *puts != 0;  puts++) UART2_TxByte(*puts);    //遇到停止符0结束
}

//========================================================================
// 函数: void SetTimer2Baudraye(u16 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void SetTimer2Baudraye(u16 dat)  // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
{
    AUXR &= ~(1<<4);    //Timer stop
    AUXR &= ~(1<<3);    //Timer2 set As Timer
    AUXR |=  (1<<2);    //Timer2 set as 1T mode
    T2H = dat / 256;
    T2L = dat % 256;
    IE2  &= ~(1<<2);    //禁止中断
    AUXR |=  (1<<4);    //Timer run enable
}

//========================================================================
// 函数: void UART2_config(u8 brt)
// 描述: UART2初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART2_config(u8 brt)    // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
{
    /*********** 波特率固定使用定时器2 *****************/
    if(brt == 2)
    {
        SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / Baudrate2);

        S2CON &= ~(1<<7);   // 8位数据, 1位起始位, 1位停止位, 无校验
        IE2   |= 1;         //允许中断
        S2CON |= (1<<4);    //允许接收
        P_SW2 &= ~0x01;
        P_SW2 |= 1;         //UART2 switch to: 0: P1.0 P1.1,  1: P4.6 P4.7

        RX2_TimeOut = 0;
        B_TX2_Busy = 0;
        TX2_Cnt = 0;
        RX2_Cnt = 0;
    }
}


//========================================================================
// 函数: void UART2_int (void) interrupt UART2_VECTOR
// 描述: UART2中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART2_int (void) interrupt 8
{
    if((S2CON & 1) != 0)
    {
        S2CON &= ~1;    //Clear Rx flag
        RX2_Buffer[RX2_Cnt] = S2BUF;
        if(++RX2_Cnt >= UART2_BUF_LENGTH)   RX2_Cnt = 0;
        RX2_TimeOut = 5;
    }

    if((S2CON & 2) != 0)
    {
        S2CON &= ~2;    //Clear Tx flag
        B_TX2_Busy = 0;
    }
}


#define     IAP_STANDBY()   IAP_CMD = 0     //IAP空闲命令(禁止)
#define     IAP_READ()      IAP_CMD = 1     //IAP读出命令
#define     IAP_WRITE()     IAP_CMD = 2     //IAP写入命令
#define     IAP_ERASE()     IAP_CMD = 3     //IAP擦除命令

#define     IAP_ENABLE()    IAP_CONTR = IAP_EN; IAP_TPS = MAIN_Fosc / 1000000
#define     IAP_DISABLE()   IAP_CONTR = 0; IAP_CMD = 0; IAP_TRIG = 0; IAP_ADDRH = 0xff; IAP_ADDRL = 0xff

#define IAP_EN          (1<<7)
#define IAP_SWBS        (1<<6)
#define IAP_SWRST       (1<<5)
#define IAP_CMD_FAIL    (1<<4)


//========================================================================
// 函数: void DisableEEPROM(void)
// 描述: 禁止EEPROM.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2014-6-30
//========================================================================
void DisableEEPROM(void)        //禁止访问EEPROM
{
    IAP_CONTR = 0;          //关闭 IAP 功能
    IAP_CMD = 0;            //清除命令寄存器
    IAP_TRIG = 0;           //清除触发寄存器
    IAP_ADDRH = 0xff;       //将地址设置到非 IAP 区域
    IAP_ADDRL = 0xff;
}

//========================================================================
// 函数: void EEPROM_Trig(void)
// 描述: 触发EEPROM操作.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2014-6-30
//========================================================================
void EEPROM_Trig(void)
{
    F0 = EA;    //保存全局中断
    EA = 0;     //禁止中断, 避免触发命令无效
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;                    //先送5AH,再送A5H到IAP触发寄存器,每次都需要如此
                                        //送完A5H后,IAP命令立即被触发启动
                                        //CPU等待IAP完成后,才会继续执行程序。
    _nop_();
    _nop_();
    EA = F0;    //恢复全局中断
}

//========================================================================
// 函数: void EEPROM_SectorErase(u16 EE_address)
// 描述: 擦除一个扇区.
// 参数: EE_address:  要擦除的EEPROM的扇区中的一个字节地址.
// 返回: none.
// 版本: V1.0, 2014-6-30
//========================================================================
void EEPROM_SectorErase(u16 EE_address)
{
    IAP_ENABLE();                       //设置等待时间,允许IAP操作,送一次就够
    IAP_ERASE();                        //宏调用, 送扇区擦除命令,命令不需改变时,不需重新送命令
                                        //只有扇区擦除,没有字节擦除,512字节/扇区。
                                        //扇区中任意一个字节地址都是扇区地址。
    IAP_ADDRH = EE_address / 256;       //送扇区地址高字节(地址需要改变时才需重新送地址)
    IAP_ADDRL = EE_address % 256;       //送扇区地址低字节
    EEPROM_Trig();                      //触发EEPROM操作
    DisableEEPROM();                    //禁止EEPROM操作
}

//========================================================================
// 函数: void EEPROM_read_n(u16 EE_address,u8 *DataAddress,u8 lenth)
// 描述: 读N个字节函数.
// 参数: EE_address:  要读出的EEPROM的首地址.
//       DataAddress: 要读出数据的指针.
//       length:      要读出的长度
// 返回: 0: 写入正确.  1: 写入长度为0错误.  2: 写入数据错误.
// 版本: V1.0, 2014-6-30
//========================================================================
void EEPROM_read_n(u16 EE_address,u8 *DataAddress,u8 length)
{
    IAP_ENABLE();                           //设置等待时间,允许IAP操作,送一次就够
    IAP_READ();                             //送字节读命令,命令不需改变时,不需重新送命令
    do
    {
        IAP_ADDRL = EE_address / 256;       //送地址高字节(地址需要改变时才需重新送地址)
        IAP_ADDRH = EE_address % 256;       //送地址低字节
        EEPROM_Trig();                      //触发EEPROM操作
        *DataAddress = IAP_DATA;            //读出的数据送往
        EE_address++;
        DataAddress++;
    }while(--length);

    DisableEEPROM();
}


//========================================================================
// 函数: u8 EEPROM_write_n(u16 EE_address,u8 *DataAddress,u8 length)
// 描述: 写N个字节函数.
// 参数: EE_address:  要写入的EEPROM的首地址.
//       DataAddress: 要写入数据的指针.
//       length:      要写入的长度
// 返回: 0: 写入正确.  1: 写入长度为0错误.  2: 写入数据错误.
// 版本: V1.0, 2014-6-30
//========================================================================
u8 EEPROM_write_n(u16 EE_address,u8 *DataAddress,u8 length)
{
    u8  i;
    u16 j;
    u8  *p;
   
    if(length == 0) return 1;   //长度为0错误

    IAP_ENABLE();                       //设置等待时间,允许IAP操作,送一次就够
    i = length;
    j = EE_address;
    p = DataAddress;
    IAP_WRITE();                            //宏调用, 送字节写命令
    do
    {
        IAP_ADDRL = EE_address / 256;       //送地址高字节(地址需要改变时才需重新送地址)
        IAP_ADDRH = EE_address % 256;       //送地址低字节
        IAP_DATA  = *DataAddress;           //送数据到IAP_DATA,只有数据改变时才需重新送
        EEPROM_Trig();                      //触发EEPROM操作
        EE_address++;                       //下一个地址
        DataAddress++;                      //下一个数据
    }while(--length);                       //直到结束

    EE_address = j;
    length = i;
    DataAddress = p;
    i = 0;
    IAP_READ();                             //读N个字节并比较
    do
    {
        IAP_ADDRH = EE_address / 256;       //送地址高字节(地址需要改变时才需重新送地址)
        IAP_ADDRL = EE_address % 256;       //送地址低字节
        EEPROM_Trig();                      //触发EEPROM操作
        if(*DataAddress != IAP_DATA)        //读出的数据与源数据比较
        {
            i = 2;
            break;
        }
        EE_address++;
        DataAddress++;
    }while(--length);

    DisableEEPROM();
    return i;
}

//********测试将数据存入EEPROM**********
void StoreBattery_value(void)
{
        u16  DatastoreTest;
        u16  DatastoreTest1;
        u16  DataPrintTmp;
        u16  DataPrintTmp0;
        u16  DataPrintTmp1;
        u16  DataPrintTmp2;
        u16  DataPrintTmp3;
        u16  DataPrintTmp4;
        u16  DataPrintTmp5;
        u16  DataPrintTmp6;
        u16  DataPrintTmp7;
        u16  DataPrintTmp8;
        u16  DataPrintTmp9;
        u16  DataPrintTmp10;
        u16  DataPrintTmp11;
        u16  DataPrintTmp12;
        u16  DataPrintTmp13;
        u16  DataPrintTmp14;
        u16  DataPrintTmp15;
        u16  DataPrintTmp16;
//        DataStore[0] = DatastoreTest;
        EEPROM_SectorErase(DataAddres); //擦除扇区
        delay_ms(100);
//                        DatastoreTest1 = 0xAAAA;

                printf("*****DatastoreTest = 0d%04d\n", DatastoreTest);
//        DataStore[2] = (DatastoreTest >> 8) & 0xFF; // 高位字节
//        DataStore[3] = DatastoreTest & 0xFF;       // 低位字节
//                EEPROM_write_n (DataAddres,&DatastoreTest,2);       
//        EEPROM_write_n (DataAddres+8,&DatastoreTest,2);        DataStoreT
//                EEPROM_write_n (DataAddres,DataStore,32);       

                DatastoreTest ++;
        if(DatastoreTest > 20)       //100ms
        {
                EEPROM_write_n (DataAddres,DataStoreT,8);       
                delay_ms(100);
                DatastoreTest = 18;
                printf("***** DatastoreTest > 100 DatastoreTest = 0d%04d\n", DatastoreTest);

        }        else
        {
                EEPROM_write_n (DataAddres,DataStoreT1,8);
                printf("*****DatastoreTest < 100 DatastoreTest = 0d%04d\n", DatastoreTest);
       
                delay_ms(100);       
        }
       

                EEPROM_read_n (DataAddres,DataPrint,8);               
                delay_ms(100);       
        printf("DataPrint[0] = 0d%04d\n", DataPrint[0]);       
        printf("DataPrint[1] = 0d%04d\n", DataPrint[1]);       
        printf("DataPrint[2] = 0x%02X\n", DataPrint[2]);
        printf("DataPrint[3] = 0x%02X\n", DataPrint[3]);
        printf("DataPrint[4] = 0x%02X\n", DataPrint[4]);
        printf("DataPrint[5] = 0x%02X\n", DataPrint[5]);        
        printf("DataPrint[6] = 0x%02X\n", DataPrint[6]);        
        printf("DataPrint[7] = 0x%02X\n", DataPrint[7]);


}       





//********test 从EEPROM打印电压数据**********
void ReadBattery_value(void)
{
               
}
//*************开机启动检测电压数据*********
void CheckEEpromData(void)
{
    u16  i;
        u8 tmp;
        WDT_Clean();   
        EEPROM_read_n (DataAddres,DataStore,40);       

//        printf("----- 0000 EEPROM_read_n-----\r\n");
//        for (i = 0; i < 5; i++)
//        {
//                        printf(" 0x%02x\t",  DataStore);
//        }
//        printf("\n");
//*******检查是否第一次烧录**********       
        if ((DataStore[0]==0XAA)&&(DataStore[1]==0XBB))
        {
                ReadBattery_value();
//                LED3 = 0;               
        }else       
        {
                EEPROM_write_n (DataAddres,DataFactory,32);                //烧录出厂预设值
                for (i = 0; i <8; i++ )
                {
        DataStore = DataFactory;
    }
                Battery_value = (DataStore[2] << 8) | DataStore[3];         // 从DataStore[2]和DataStore[3]还原BatValueLast

        DBG_PRINTF("-----Factory Battery_value =: %d\n",Battery_value);       
//        LED6 = 0;               
        }       
       
}       


用上面测试程序去写EEPROM,却没有成功,
米高
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:315
  • 最近打卡:2025-10-02 12:32:59
已绑定手机

83

主题

3209

回帖

7092

积分

荣誉版主

无情的代码机器

积分
7092
发表于 3 天前 | 显示全部楼层
优先使用例程测试,注意型号间EEPROM大小差异

https://www.stcaimcu.com/data/do ... -DEMO-CODE-V9.6.zip
截图202509301207499242.jpg
截图202509301208485940.jpg
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:315
  • 最近打卡:2025-10-02 12:32:59
已绑定手机

83

主题

3209

回帖

7092

积分

荣誉版主

无情的代码机器

积分
7092
发表于 3 天前 | 显示全部楼层
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:582
  • 最近打卡:2025-10-02 20:27:04
已绑定手机
已实名认证

116

主题

2846

回帖

7234

积分

版主

积分
7234
发表于 3 天前 | 显示全部楼层
可以先使用实验箱例程测试一下
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:582
  • 最近打卡:2025-10-02 20:27:04
已绑定手机
已实名认证

116

主题

2846

回帖

7234

积分

版主

积分
7234
发表于 3 天前 | 显示全部楼层
mig*** 发表于 2025-9-27 16:27
我们读写擦除的地址代码是:
IAP_ADDRH = EE_address / 256;  // 实际应写地址高8位
IAP_ADDRL = EE_address ...

这两个在同样是16位数据下是等效的
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2025-09-30 10:59:40
已绑定手机

6

主题

12

回帖

120

积分

注册会员

积分
120
发表于 3 天前 | 显示全部楼层
原来的读写SDK有问题,换用新的擦除读写SDK后就可以了.谢谢eric!
米高
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-10-3 08:52 , Processed in 0.132620 second(s), 100 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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