单片机中如何实现永久保存某一程序中的数据?
我想用AT89S52做一个密码锁,但是不知道如何实现将原始密码永久保存,我知道程序的数据都是保存在RAM中,但是RAM断电后数据就会消失了……有没有一种特殊的存储器或寄存...
我想用AT89S52做一个密码锁,但是不知道如何实现将原始密码永久保存,我知道程序的数据都是保存在RAM中,但是RAM断电后数据就会消失了……有没有一种特殊的存储器或寄存器可以实现这个功能呀?就算有,我又得如何用C语言对一个特定的地址进行操作呢?在标准C里面我从来没这么用过……抑或是要用到其他芯片?小弟初学者……见笑了,望各路高人指点。。
展开
4个回答
展开全部
可以外接EEPROM 24C02,下面的程序你可以参考,改动后使用,我试过,读写都正常
;**************************************************/
#define uchar unsigned char
#define uint unsigned int
#define Slaw 0x0a; //写命令字
#define Slar 0xa1; //读命令字
#include "reg52.h"
#include "intrins.h"
sbit Scl=P3^6; //串行时钟
sbit Sda=P3^7; //串行数据
bit Rec; //接收到数据的标志
uchar RecBuf[3]; //接收缓冲区
#define Hidden 0x10; //消隐字符在字形码表中的位置
uchar code BitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB};
uchar code DispTab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xFF};
uchar DispBuf[6]; //6字节的显示缓冲区
uchar code TH0Val=63266/256;
uchar code TL0Val=63266%256;//当晶振为11.0592时,定时2.5ms的定时器初值
//以下是中断程序,用于显示
void Timer0() interrupt 1
{ uchar tmp;
static uchar dCount; //计数器,显示程序通过它得知现正显示哪个数码管
TH0=TH0Val;
TL0=TL0Val;
tmp=BitTab[dCount]; //根据当前的计数值取位值
P2=P2|0xfc; //P2与11111100B相或,将高6位置1
P2=P2&tmp; //P2与取出的位值相与,将某一位清零
tmp=DispBuf[dCount]; //根据当前的计数值取显示缓冲待显示值
tmp=DispTab[tmp]; //取字形码
P0=tmp; //送出字形码
dCount++; //计数值加1
if(dCount==6) //如果计数值等于6,则让其回0
dCount=0;
}
/*发送起始条件*/
void Start(void) /*起始条件*/
{
Sda=1;
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Sda=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
}
void Stop(void) /*停止条件*/
{
Sda=0;
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Sda=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
}
void Ack(void) /*应答位*/
{
Sda=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=0;
}
void NoAck(void) /*反向应答位*/
{
Sda=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=0;
}
void Send(uchar Data) /*发送数据子程序,Data为要求发送的数据*/
{
uchar BitCounter=8; /*位数控制*/
uchar temp; /*中间变量控制*/
do
{
temp=Data;
Scl=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
if((temp&0x80)==0x80)/* 如果最高位是1*/
Sda=1;
else
Sda=0;
Scl=1;
temp=Data<<1; /*RLC*/
Data=temp;
BitCounter--;
}while(BitCounter);
Scl=0;
}
uchar Read(void) /*读一个字节的数据,并返回该字节值*/
{
uchar temp=0;
uchar temp1=0;
uchar BitCounter=8;
Sda=1;
do{
Scl=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
if(Sda) /*如果Sda=1;*/
temp=temp|0x01; /*temp的最低位置1*/
else
temp=temp&0xfe; /*否则temp的最低位清0*/
if(BitCounter-1)
{ temp1=temp<<1;
temp=temp1;
}
BitCounter--;
}while(BitCounter);
return(temp);
}
void WrToROM(uchar Data[],uchar Address,uchar Num)
{
uchar i=0;
uchar *PData;
PData=Data;
Start();
Send(0xa0);
Ack();
Send(Address);
Ack();
for(i=0;i<Num;i++)
{
Send(*(PData+i));
Ack();
}
Stop();
}
void RdFromROM(uchar Data[],uchar Address,uchar Num)
{
uchar i=0;
uchar *PData;
PData=Data;
for(i=0;i<Num;i++)
{
Start();
Send(0xa0);
Ack();
Send(Address+i);
Ack();
Start();
Send(0xa1);
Ack();
*(PData+i)=Read();
Scl=0;
NoAck();
Stop();
}
}
void Recive() interrupt 4 //串行中断程序
{ static uchar Count=0;
if(TI)
{ TI=0;
return; //如果是发送中断,直接退出
}
RI=0; //清RI标志
RecBuf[Count]=SBUF;
Count++;
Rec=0;
if(Count>=3)
{ Count=0;
Rec=1; //置位标志
}
}
void Init()
{ TMOD=0x21;
RI=0;
TH1=0xfd;
TL1=0xfd;
PCON|=0x80;
TR1=1;
SCON=0x50;
TH0=TH0Val;
TL0=TL0Val;
ET0=1; //开T0中断
EA=1; //开总中断
ES=1;
TR0=1; //T0开始运行
TR1=1;
}
void Calc(uchar Dat1,uchar Dat2) //第一个参数放在第1、2位,第二个参数放入第5、6位
{ DispBuf[0]=Dat1/16;
DispBuf[1]=Dat1%16;
DispBuf[4]=Dat2/16;
DispBuf[5]=Dat2%16;
}
void main()
{ uchar RomDat[4];
Init(); //初始化
DispBuf[2]=Hidden;
DispBuf[3]=Hidden;
for(;;)
{
Calc(RecBuf[1],RomDat[0]); //分别显示地址和数据
if(Rec) //接收到数据
{ Rec=0; //清除标志
if(RecBuf[0]==0) //第一种功能,写入
{ RomDat[0]=RecBuf[2];
WrToROM(RomDat,RecBuf[1],1);
SBUF=RomDat[0];
}
else
{ RdFromROM(RomDat,RecBuf[1],1);
SBUF=RomDat[0];
}
}
}
}
;**************************************************/
#define uchar unsigned char
#define uint unsigned int
#define Slaw 0x0a; //写命令字
#define Slar 0xa1; //读命令字
#include "reg52.h"
#include "intrins.h"
sbit Scl=P3^6; //串行时钟
sbit Sda=P3^7; //串行数据
bit Rec; //接收到数据的标志
uchar RecBuf[3]; //接收缓冲区
#define Hidden 0x10; //消隐字符在字形码表中的位置
uchar code BitTab[]={0x7F,0xBF,0xDF,0xEF,0xF7,0xFB};
uchar code DispTab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xFF};
uchar DispBuf[6]; //6字节的显示缓冲区
uchar code TH0Val=63266/256;
uchar code TL0Val=63266%256;//当晶振为11.0592时,定时2.5ms的定时器初值
//以下是中断程序,用于显示
void Timer0() interrupt 1
{ uchar tmp;
static uchar dCount; //计数器,显示程序通过它得知现正显示哪个数码管
TH0=TH0Val;
TL0=TL0Val;
tmp=BitTab[dCount]; //根据当前的计数值取位值
P2=P2|0xfc; //P2与11111100B相或,将高6位置1
P2=P2&tmp; //P2与取出的位值相与,将某一位清零
tmp=DispBuf[dCount]; //根据当前的计数值取显示缓冲待显示值
tmp=DispTab[tmp]; //取字形码
P0=tmp; //送出字形码
dCount++; //计数值加1
if(dCount==6) //如果计数值等于6,则让其回0
dCount=0;
}
/*发送起始条件*/
void Start(void) /*起始条件*/
{
Sda=1;
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Sda=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
}
void Stop(void) /*停止条件*/
{
Sda=0;
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Sda=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
}
void Ack(void) /*应答位*/
{
Sda=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=0;
}
void NoAck(void) /*反向应答位*/
{
Sda=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=0;
}
void Send(uchar Data) /*发送数据子程序,Data为要求发送的数据*/
{
uchar BitCounter=8; /*位数控制*/
uchar temp; /*中间变量控制*/
do
{
temp=Data;
Scl=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
if((temp&0x80)==0x80)/* 如果最高位是1*/
Sda=1;
else
Sda=0;
Scl=1;
temp=Data<<1; /*RLC*/
Data=temp;
BitCounter--;
}while(BitCounter);
Scl=0;
}
uchar Read(void) /*读一个字节的数据,并返回该字节值*/
{
uchar temp=0;
uchar temp1=0;
uchar BitCounter=8;
Sda=1;
do{
Scl=0;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
Scl=1;
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
if(Sda) /*如果Sda=1;*/
temp=temp|0x01; /*temp的最低位置1*/
else
temp=temp&0xfe; /*否则temp的最低位清0*/
if(BitCounter-1)
{ temp1=temp<<1;
temp=temp1;
}
BitCounter--;
}while(BitCounter);
return(temp);
}
void WrToROM(uchar Data[],uchar Address,uchar Num)
{
uchar i=0;
uchar *PData;
PData=Data;
Start();
Send(0xa0);
Ack();
Send(Address);
Ack();
for(i=0;i<Num;i++)
{
Send(*(PData+i));
Ack();
}
Stop();
}
void RdFromROM(uchar Data[],uchar Address,uchar Num)
{
uchar i=0;
uchar *PData;
PData=Data;
for(i=0;i<Num;i++)
{
Start();
Send(0xa0);
Ack();
Send(Address+i);
Ack();
Start();
Send(0xa1);
Ack();
*(PData+i)=Read();
Scl=0;
NoAck();
Stop();
}
}
void Recive() interrupt 4 //串行中断程序
{ static uchar Count=0;
if(TI)
{ TI=0;
return; //如果是发送中断,直接退出
}
RI=0; //清RI标志
RecBuf[Count]=SBUF;
Count++;
Rec=0;
if(Count>=3)
{ Count=0;
Rec=1; //置位标志
}
}
void Init()
{ TMOD=0x21;
RI=0;
TH1=0xfd;
TL1=0xfd;
PCON|=0x80;
TR1=1;
SCON=0x50;
TH0=TH0Val;
TL0=TL0Val;
ET0=1; //开T0中断
EA=1; //开总中断
ES=1;
TR0=1; //T0开始运行
TR1=1;
}
void Calc(uchar Dat1,uchar Dat2) //第一个参数放在第1、2位,第二个参数放入第5、6位
{ DispBuf[0]=Dat1/16;
DispBuf[1]=Dat1%16;
DispBuf[4]=Dat2/16;
DispBuf[5]=Dat2%16;
}
void main()
{ uchar RomDat[4];
Init(); //初始化
DispBuf[2]=Hidden;
DispBuf[3]=Hidden;
for(;;)
{
Calc(RecBuf[1],RomDat[0]); //分别显示地址和数据
if(Rec) //接收到数据
{ Rec=0; //清除标志
if(RecBuf[0]==0) //第一种功能,写入
{ RomDat[0]=RecBuf[2];
WrToROM(RomDat,RecBuf[1],1);
SBUF=RomDat[0];
}
else
{ RdFromROM(RomDat,RecBuf[1],1);
SBUF=RomDat[0];
}
}
}
}
光点科技
2023-08-15 广告
2023-08-15 广告
通常情况下,我们会按照结构模型把系统产生的数据分为三种类型:结构化数据、半结构化数据和非结构化数据。结构化数据,即行数据,是存储在数据库里,可以用二维表结构来逻辑表达实现的数据。最常见的就是数字数据和文本数据,它们可以某种标准格式存在于文件...
点击进入详情页
本回答由光点科技提供
展开全部
如果你的电脑有eeprom,那么就可以可以将这些数据存在这里。如果没有,你可以外接EEPROM,如AT24CX系列,其中X对应的容量
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
有些单片机内部提供ROM和RAM,ROM是只读存储器,RAM是随机存储器,一般在程序code代码(用于烧写bin或者hex文件)存储于ROM(ROM、PROM、EPROM但是都是需要专门的烧写软件进行烧写擦除)而在程序运行过程中出现的data 数据(如C代码运行的堆栈),局部变量,全局变量等放入RAM中执行,一旦掉电RAM中的数据将遗失,那么要想存储你在程序运行时动态产生的数据,必须外扩一个可读可写的存储,使用EEPROM(如I2C通信方式AT24CXXX),可实现动态保存你的数据。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
可以使用24cXX 或93CXX 等 FLASH 存储器如24C16,93C46。很便宜1-2元一片。
呵呵,不知道你说的永久是多久,FLASH只能保存几十到一百来年(厂家说的,谁知道呢)。
呵呵,不知道你说的永久是多久,FLASH只能保存几十到一百来年(厂家说的,谁知道呢)。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询