一:問題描述
之前用的單片機是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(); //燈
}
} |