找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 298|回復: 7
收起左側

關于單片機EEPROM讀數(shù)據(jù)偶爾不正確的情況

[復制鏈接]
ID:675145 發(fā)表于 2025-6-2 11:06 | 顯示全部樓層 |閱讀模式
一:問題描述
之前用的單片機是stc15w408a都是正常的,因為FLASH太小又需要增加其他功能費不得不改成stc15f2k60s2,但是EEPROM代碼是差不多的。從原來保存在2,3扇區(qū)變成了0,1扇區(qū)(stc15f2k60s2只有0,1這兩個扇區(qū))
換完芯片后EEPROM讀取大部分時候是正常的,隨機出現(xiàn)讀出來的數(shù)據(jù)是0xff,而且第0扇區(qū)和第1扇區(qū)隨機出現(xiàn),讀取異常后無論如何重新上電都是異常的需要重新寫入

二:看代碼:
1.EEPROM.c
[code]#include "all.h"
void IapIdle()
{
        IAP_CONTR = 0;
        IAP_CMD = 0;
        IAP_TRIG = 0;
        IAP_ADDRH = 0x80;
        IAP_ADDRL = 0;
}
void EEPROM_Wipe512_Drive(u8 ADDRH)        //清空某個扇區(qū)
{
        
        IAP_CONTR|=0x82;
        IAP_CMD=0x03;
        IAP_ADDRH=ADDRH;
        IAP_TRIG=0x5A;
        IAP_TRIG=0xA5;
        _nop_();
        _nop_();
        _nop_();
        IapIdle();
}
u8 EEPROM_Read_Byte_Drive(u8 ADDRH,u8 ADDRL)        //讀某個扇區(qū)數(shù)據(jù)
{
        u8 idata DATA;
        
        IAP_CONTR|=0x82;
        IAP_CMD=0x01;
        IAP_ADDRH=ADDRH;
        IAP_ADDRL=ADDRL;
        IAP_TRIG=0x5A;
        IAP_TRIG=0xA5;
        _nop_();
        _nop_();
        _nop_();
        DATA=IAP_DATA;
        IapIdle();
        
        return  DATA;
}
void EEPROM_Write_Byte_Drive(u8 ADDRH,u8 ADDRL,u8 Byte)//往某個扇區(qū)寫數(shù)據(jù)
{
        IAP_CONTR|=0x82;
        IAP_CMD=0x02;
        IAP_ADDRH=ADDRH;
        IAP_ADDRL=ADDRL;
        IAP_DATA=Byte;
        IAP_TRIG=0x5A;
        IAP_TRIG=0xA5;
        _nop_();
        _nop_();
        _nop_();
        IapIdle();
}

void EEPROM_Write_Data(u8 ADDRH)
{
        EEPROM_Wipe512_Drive(ADDRH);
        
        if(ADDRH == EEPROM_ID)
        {
                EEPROM_Write_Byte_Drive(EEPROM_ID, EEPROM_Drive_ID0, Drive_ID[0]);
                EEPROM_Write_Byte_Drive(EEPROM_ID, EEPROM_Drive_ID1, Drive_ID[1]);
        }
        else if(ADDRH == EEPROM_SET)
        {
                EEPROM_Write_Byte_Drive(EEPROM_SET, EEPROM_Set_Num, Set_Num);
                EEPROM_Write_Byte_Drive(EEPROM_SET, EEPROM_Hall_Open, Hall_Open);
                EEPROM_Write_Byte_Drive(EEPROM_SET, EEPROM_Motor_Open, Motor_Open);
                EEPROM_Write_Byte_Drive(EEPROM_SET, EEPROM_Limit_Flag, Limit_Flag);
                EEPROM_Write_Byte_Drive(EEPROM_SET, EEPROM_Version, Version);
        }
}

2.EEPROM.h
#ifndef EEPROM
#define EEPROM

#define EEPROM_ID                                        0
#define EEPROM_SET                                        2

#define EEPROM_Drive_ID0                        0
#define EEPROM_Drive_ID1                        1

#define EEPROM_Set_Num                                0
#define EEPROM_Hall_Open                        1
#define EEPROM_Motor_Open                        2
#define EEPROM_Limit_Flag                        3
#define EEPROM_Version                                4

extern u8 EEPROM_Read_Byte_Drive(u8 ADDRH,u8 ADDRL);//讀某個扇區(qū)數(shù)據(jù)
extern void EEPROM_Write_Data(u8 ADDRH);
        
#endif

3.EEPROM寫應用:設備通過RS485進行參數(shù)設置時才會用到寫EEPROM,一般情況不會隨意修改
void RS485_RX_Drive()        //RS485接收底層函數(shù)
{
        u8 i;
        
        send_cnt++;    //只要有數(shù)據(jù)接收,send_cnt每次都被串口中斷清零
        if(send_cnt>200)   //延時一段時間,確認緩沖區(qū)沒有繼續(xù)接收數(shù)據(jù)
        {
                send_cnt=0;
                RS485_Busy=0;
                RxLen=0;
                for(i=0;i<7;i++)
                {
                        //檢驗數(shù)據(jù)頭(D6  F7)
                        if(RS485_Up_Num_Buffer==0xD6 && RS485_Up_Num_Buffer[i+1]==0xF7)
                        {                                
                                switch(RS485_Up_Num_Buffer[i+4])
                                {
                                        case Cmd_Hall:
                                                {
                                                        if(RS485_Up_Num_Buffer[i+3]==Drive_ID[1] || RS485_Up_Num_Buffer[i+3]==0)
                                                        {
                                                                Hall_Open = RS485_Up_Num_Buffer[i+2];                //是否打開霍爾電流開關        
                                                                EEPROM_Write_Data(EEPROM_SET);
                                                        }
                                                }
                                                break;
                                        case Cmd_Motor:
                                                {
                                                        if(RS485_Up_Num_Buffer[i+3]==Drive_ID[1] || RS485_Up_Num_Buffer[i+3]==0)
                                                        {
                                                                Motor_Open = RS485_Up_Num_Buffer[i+2];                //是否打開電機電流開關
                                                                EEPROM_Write_Data(EEPROM_SET);
                                                        }
                                                }
                                                break;
                                        case Cmd_Limit:
                                                {
                                                        if(RS485_Up_Num_Buffer[i+3]==Drive_ID[1] || RS485_Up_Num_Buffer[i+3]==0)
                                                        {
                                                                Limit_Flag = RS485_Up_Num_Buffer[i+2];        //是否打開限位開關
                                                                EEPROM_Write_Data(EEPROM_SET);
                                                        }
                                                }
                                                break;
                                        case Cmd_Run_Num:
                                                        {
                                                                if(Run_Flag==0)        //停止狀態(tài)才能更改運行次數(shù)
                                                                {
                                                                        Set_Num=RS485_Up_Num_Buffer[i+2];
                                                                        EEPROM_Write_Data(EEPROM_SET);
                                                                }
                                                        }
                                                        break;
                                        case Cmd_Version:
                                                        {
                                                                if(Run_Flag==0)        //停止狀態(tài)才能更改產品版本
                                                                {
                                                                        Version = RS485_Up_Num_Buffer[i+2];                                                                        
                                                                        EEPROM_Write_Data(EEPROM_SET);
                                                                        
                                                                        if(Version==2)
                                                                                Stable_Motor_Current=550;        //電機穩(wěn)定電流
                                                                        else if(Version==3)
                                                                                Stable_Motor_Current=800;        //電機穩(wěn)定電流
                                                                }
                                                        }
                                                        break;
                                        case Cmd_EXIT:
                                                        {
                                                                if(Run_Flag==0)        
                                                                {
                                                                        Run_Flag = 3;
                                                                }
                                                        }
                                                        break;
                                }        
                        }
                }
        }
}

4.EEPROM讀應用:在初始化時用Get_SET_Parameter函數(shù)讀取數(shù)據(jù),防止上電不充分在讀取數(shù)據(jù)前加了500MS延時,后來沒辦法在EEPROM讀取的數(shù)據(jù)錯誤時直接對變量進行賦值

void Get_SET_Parameter(void)
{
        Drive_ID[0] = EEPROM_Read_Byte_Drive(EEPROM_ID,        EEPROM_Drive_ID0);
        Drive_ID[1] = EEPROM_Read_Byte_Drive(EEPROM_ID,        EEPROM_Drive_ID1);
        
        Set_Num = EEPROM_Read_Byte_Drive(EEPROM_SET,        EEPROM_Set_Num);                //初始化運行次數(shù)        
        Hall_Open = EEPROM_Read_Byte_Drive(EEPROM_SET,        EEPROM_Hall_Open);                //是否打開霍爾電流開關        
        Motor_Open = EEPROM_Read_Byte_Drive(EEPROM_SET,        EEPROM_Motor_Open);                //是否打開霍爾電流開關        
        Limit_Flag = EEPROM_Read_Byte_Drive(EEPROM_SET,        EEPROM_Limit_Flag);                //是否打開霍爾電流開關
        
        Version = EEPROM_Read_Byte_Drive(EEPROM_SET,EEPROM_Version);
        if(Version==2)
        {
                Stable_Motor_Current=550;        //電機穩(wěn)定電流
        }
        else if(Version==3)
        {
                Stable_Motor_Current=800;        //電機穩(wěn)定電流
                Hall_Open = Close;
        }
        
        //        //設置設備編號
        Drive_ID[0] = 'G';
        Drive_ID[1] = 1;
        EEPROM_Write_Data(EEPROM_ID);
        
        //如果出現(xiàn)EEPROM錯誤,直接賦值
        if(Set_Num == 0xFF)
        {
                Set_Num = 100;                //初始化運行次數(shù)        
                Hall_Open = Open;                //是否打開霍爾電流開關        
                Motor_Open = Open;                //是否打開霍爾電流開關        
                Limit_Flag = Open;                //是否打開霍爾電流開關
                Version = 2;
                Stable_Motor_Current=550;        //電機穩(wěn)定電流
        }
}
void main()
{
        P0M1=0;P0M0=0;
        P1M1=0;P1M0=0;
        P2M1=0;P2M0=0;
        P3M1=0;P3M0=0;
        P4M1=0;P4M0=0;        
        P5M1=0;P5M0=0;

        ADC_Init();
        Cylinder_Init();
        RS485_Init();
        IIC_Init();
        OLED_Init();
        KEY_Init();        
        WS2812B_Init();
        Lock_Init();

        Delay500ms();                                                        //延時500ms,等待系統(tǒng)穩(wěn)定
        ADC_Reference = ADC_Filter_Result();        //獲取ADC偏置值
        Get_SET_Parameter();                                        //獲取EEPROM中的系統(tǒng)參數(shù)
        
        P2M1=0;P2M0=0x0E;        //P2.1/P2.2/P2.3推挽輸出                //氣缸輸出
        P1M1=0;P1M0=0x30;        //P1.4/P1.5推挽輸出                        //電機輸出
        while(1)
        {
                RS485_Data_Drive();        //RS485數(shù)據(jù)處理
                OLED_Allot();                //OLED屏幕顯示
                Mach_Run_Scan();        //電機運行掃描        
                KEY_Allot();                //按鍵掃描服務
                ADC_Allot();                //電流檢測服務
                WS2812B_Allot();        //燈
        }
}
回復

使用道具 舉報

ID:675145 發(fā)表于 2025-6-2 14:06 | 顯示全部樓層
stc15f2k60s2的工作頻率范圍在0-28M,而我的晶振是30M,大概率是這個問題了,先運行一段時間看看還會不會出現(xiàn)問題
回復

使用道具 舉報

ID:1109793 發(fā)表于 2025-6-2 15:37 | 顯示全部樓層
會不會是頻率設置不對
IAP_CONTR|=0x82;
11.0592用0X83比較好吧。
另外,為啥是|=?
IAP_CONTR=0x83;可以不
回復

使用道具 舉報

ID:1109793 發(fā)表于 2025-6-2 15:41 | 顯示全部樓層
張小不懂 發(fā)表于 2025-6-2 14:06
stc15f2k60s2的工作頻率范圍在0-28M,而我的晶振是30M,大概率是這個問題了,先運行一段時間看看還會不會出 ...

30M是0x80吧
不過用到22.1184就比較穩(wěn)定,用到30M你比較大膽
回復

使用道具 舉報

ID:1121801 發(fā)表于 2025-6-2 16:22 | 顯示全部樓層
IAP我算小白,我不明白IAP_CONTL|=0X82,為什么用"|=",直接賦值用"="不好嗎?還是有什么玄機?
回復

使用道具 舉報

ID:57657 發(fā)表于 2025-6-2 21:49 | 顯示全部樓層
EEPROM二進制1可以寫為0,反過來就不能。
只有扇區(qū)擦除,沒有字節(jié)擦除,必須擦除后才可以恢復為1,一次擦1扇區(qū)(512字節(jié)),扇區(qū)擦除的地址必須是512的倍數(shù):0,512,1024,1536等。
另外此型號可以使用unsigned char code *指針(匯編MOVC指令)讀取EEPROM數(shù)據(jù)。
回復

使用道具 舉報

ID:675145 發(fā)表于 2025-6-4 15:52 | 顯示全部樓層
xiaobendan001 發(fā)表于 2025-6-2 15:41
30M是0x80吧
不過用到22.1184就比較穩(wěn)定,用到30M你比較大膽

之前是STC15F408AS用的30M的晶振,改了單片機但是沒注意晶振,現(xiàn)在改用內部晶振24M,暫時沒問題
回復

使用道具 舉報

ID:675145 發(fā)表于 2025-6-4 16:00 | 顯示全部樓層
cyi8 發(fā)表于 2025-6-2 16:22
IAP我算小白,我不明白IAP_CONTL|=0X82,為什么用"|=",直接賦值用"="不好嗎?還是有什么玄機?

沒用玄機,我馬上改
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表