久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

標題: 關于單片機EEPROM讀數據偶爾不正確的情況 [打印本頁]

作者: 張小不懂    時間: 2025-6-2 11:06
標題: 關于單片機EEPROM讀數據偶爾不正確的情況
一:問題描述
之前用的單片機是stc15w408a都是正常的,因為FLASH太小又需要增加其他功能費不得不改成stc15f2k60s2,但是EEPROM代碼是差不多的。從原來保存在2,3扇區變成了0,1扇區(stc15f2k60s2只有0,1這兩個扇區)
換完芯片后EEPROM讀取大部分時候是正常的,隨機出現讀出來的數據是0xff,而且第0扇區和第1扇區隨機出現,讀取異常后無論如何重新上電都是異常的需要重新寫入

二:看代碼:
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)        //清空某個扇區
{
        
        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)        //讀某個扇區數據
{
        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)//往某個扇區寫數據
{
        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);//讀某個扇區數據
extern void EEPROM_Write_Data(u8 ADDRH);
        
#endif

3.EEPROM寫應用:設備通過RS485進行參數設置時才會用到寫EEPROM,一般情況不會隨意修改
void RS485_RX_Drive()        //RS485接收底層函數
{
        u8 i;
        
        send_cnt++;    //只要有數據接收,send_cnt每次都被串口中斷清零
        if(send_cnt>200)   //延時一段時間,確認緩沖區沒有繼續接收數據
        {
                send_cnt=0;
                RS485_Busy=0;
                RxLen=0;
                for(i=0;i<7;i++)
                {
                        //檢驗數據頭(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)        //停止狀態才能更改運行次數
                                                                {
                                                                        Set_Num=RS485_Up_Num_Buffer[i+2];
                                                                        EEPROM_Write_Data(EEPROM_SET);
                                                                }
                                                        }
                                                        break;
                                        case Cmd_Version:
                                                        {
                                                                if(Run_Flag==0)        //停止狀態才能更改產品版本
                                                                {
                                                                        Version = RS485_Up_Num_Buffer[i+2];                                                                        
                                                                        EEPROM_Write_Data(EEPROM_SET);
                                                                        
                                                                        if(Version==2)
                                                                                Stable_Motor_Current=550;        //電機穩定電流
                                                                        else if(Version==3)
                                                                                Stable_Motor_Current=800;        //電機穩定電流
                                                                }
                                                        }
                                                        break;
                                        case Cmd_EXIT:
                                                        {
                                                                if(Run_Flag==0)        
                                                                {
                                                                        Run_Flag = 3;
                                                                }
                                                        }
                                                        break;
                                }        
                        }
                }
        }
}

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

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);                //初始化運行次數        
        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;        //電機穩定電流
        }
        else if(Version==3)
        {
                Stable_Motor_Current=800;        //電機穩定電流
                Hall_Open = Close;
        }
        
        //        //設置設備編號
        Drive_ID[0] = 'G';
        Drive_ID[1] = 1;
        EEPROM_Write_Data(EEPROM_ID);
        
        //如果出現EEPROM錯誤,直接賦值
        if(Set_Num == 0xFF)
        {
                Set_Num = 100;                //初始化運行次數        
                Hall_Open = Open;                //是否打開霍爾電流開關        
                Motor_Open = Open;                //是否打開霍爾電流開關        
                Limit_Flag = Open;                //是否打開霍爾電流開關
                Version = 2;
                Stable_Motor_Current=550;        //電機穩定電流
        }
}
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,等待系統穩定
        ADC_Reference = ADC_Filter_Result();        //獲取ADC偏置值
        Get_SET_Parameter();                                        //獲取EEPROM中的系統參數
        
        P2M1=0;P2M0=0x0E;        //P2.1/P2.2/P2.3推挽輸出                //氣缸輸出
        P1M1=0;P1M0=0x30;        //P1.4/P1.5推挽輸出                        //電機輸出
        while(1)
        {
                RS485_Data_Drive();        //RS485數據處理
                OLED_Allot();                //OLED屏幕顯示
                Mach_Run_Scan();        //電機運行掃描        
                KEY_Allot();                //按鍵掃描服務
                ADC_Allot();                //電流檢測服務
                WS2812B_Allot();        //燈
        }
}

作者: 張小不懂    時間: 2025-6-2 14:06
stc15f2k60s2的工作頻率范圍在0-28M,而我的晶振是30M,大概率是這個問題了,先運行一段時間看看還會不會出現問題
作者: xiaobendan001    時間: 2025-6-2 15:37
會不會是頻率設置不對
IAP_CONTR|=0x82;
11.0592用0X83比較好吧。
另外,為啥是|=?
IAP_CONTR=0x83;可以不
作者: xiaobendan001    時間: 2025-6-2 15:41
張小不懂 發表于 2025-6-2 14:06
stc15f2k60s2的工作頻率范圍在0-28M,而我的晶振是30M,大概率是這個問題了,先運行一段時間看看還會不會出 ...

30M是0x80吧
不過用到22.1184就比較穩定,用到30M你比較大膽
作者: cyi8    時間: 2025-6-2 16:22
IAP我算小白,我不明白IAP_CONTL|=0X82,為什么用"|=",直接賦值用"="不好嗎?還是有什么玄機?
作者: npn    時間: 2025-6-2 21:49
EEPROM二進制1可以寫為0,反過來就不能。
只有扇區擦除,沒有字節擦除,必須擦除后才可以恢復為1,一次擦1扇區(512字節),扇區擦除的地址必須是512的倍數:0,512,1024,1536等。
另外此型號可以使用unsigned char code *指針(匯編MOVC指令)讀取EEPROM數據。
作者: 張小不懂    時間: 2025-6-4 15:52
xiaobendan001 發表于 2025-6-2 15:41
30M是0x80吧
不過用到22.1184就比較穩定,用到30M你比較大膽

之前是STC15F408AS用的30M的晶振,改了單片機但是沒注意晶振,現在改用內部晶振24M,暫時沒問題
作者: 張小不懂    時間: 2025-6-4 16:00
cyi8 發表于 2025-6-2 16:22
IAP我算小白,我不明白IAP_CONTL|=0X82,為什么用"|=",直接賦值用"="不好嗎?還是有什么玄機?

沒用玄機,我馬上改




歡迎光臨 (http://m.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 国产网址 | 成人在线视频免费观看 | 亚洲一区二区三区免费视频 | 国产午夜精品久久 | xxxx色| 成人一区二区在线 | 免费av网址在线观看 | 亚洲免费二区 | 在线视频一区二区三区 | 在线性视频 | 狠狠干网| 涩涩久久| 日韩成人在线免费观看 | 中文字幕一区二区在线播放 | 看黄网站在线观看 | 亚洲二区视频 | 中文字幕有码在线 | 国产第一福利 | 波多野结衣久久 | 最新日韩在线 | 一级片免费视频 | 欧美九九九 | 精品少妇| 日本一级大毛片a一 | 久久黄色影院 | 亚洲精品久久久久avwww潮水 | 91精品久久久久 | 国产深夜福利 | 午夜视频在线免费观看 | 六月婷婷在线 | 日韩视频第一页 | 欧美精品在线看 | 日本黄页视频 | 中文字幕在线一区 | 国产精品成人在线 | 国产日韩一区二区 | 国产成人三级一区二区在线观看一 | 国产精品毛片va一区二区三区 | 日韩在线视频免费 | 色接久久 | 狠狠操av|