一:问题描述
之前用的单片机是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(); //灯
}
} |