浮点数在E2PROM中的存取方法.docx
《浮点数在E2PROM中的存取方法.docx》由会员分享,可在线阅读,更多相关《浮点数在E2PROM中的存取方法.docx(13页珍藏版)》请在冰豆网上搜索。
浮点数在E2PROM中的存取方法
浮点数据在E2PROM中的存取方法
摘要介绍了C51语言的浮点数在E2PROM中的存取方法。
关键词浮点数非易失存储器存取方法C51编程
1引言
由于C语言的高效性和易维护性,因而C51语言在工程中得到了广泛应用。
以下所讨论的问题中的程序举例就是用C51语言编写来实现其功能和目的。
在我们设计产品的过程中,通常要将一些仪器参数保存起来,作为仪器正常工作的保障,这些浮点参数一般都保存在非易失性存储器(E2PROM)中,以防丢失。
2浮点数在E2PROM中的存取
2.1浮点数在并行E2PROM中的存取
MCS-51单片机在智能化仪器仪表的设计中得到了广泛的应用,同时C51单片机开发语言方便灵活的接口编程能力和强大的数据处理能力,在单片机的开发中占有重要地位。
其特有的浮点数处理能力为智能化仪器仪表的非线性矫正、数字化校准提供了方便。
在C51中,如果浮点数被分配在RAM存储空间,如6264、6116、62256、62128等,其数据的存取由C51自动编译完成,不必编写专门的程序。
而非易失性存储器2817A、2864等虽然硬件接口没有特殊要求,但写周期与RAM不同,因此必须为浮点数存储编写专门的存储程序。
一般情况下,用户定义的浮点数在RAM中的地址、存储方式对用户是未知的。
但是用户可以通过C51的指针实现对C51浮点数的按字节访问,C51语言的指针是它的一大特色,表现出很强的数据处理能力和灵活性。
使用指针可以有效地表示复杂的数据结构,动态分配存储器,直接处理内存地址等,简化程序设计。
浮点数在内存中的存储方式如表1所示。
地址
0
1
2
3
内容
MMMMMMMM
MMMMMMMM
EMMMMMMM
SEEEEEEE
表1浮点数在内存中的存储
其中,S符号位,1表示负,0表示正;
E阶码(在两个字节中)偏移最大为127;
M23位尾数,最高位为1。
例如浮点数变量k=-12.5的十六进制表示为:
0xC1480000,它按如下方式保存于内存RAM的连续4个字节中。
地址内容
ADD+00H0x00
ADD+01H0x00
ADD+02H0x48
ADD+03H0xC1
通过以下语句可以直接对变量进行读写操作。
floatxdatak,s;定义浮点数k,s位于外部RAM
k=-12.5;为变量k赋值为-12.5
s=k;为变量s赋值为-12.5
由于非易失性存储器2817A、2864等的读操作与RAM类似,而擦、写时间周期比随机存储器RAM要长得多,一般一个字节的擦除和写访问时间为200μS或1mS,最大的写入周期(包括擦除和写入)时间不超过10mS,典型时间为5mS。
因此在实际应用中要满足擦、写周期时间要求,应根据芯片的要求设置等待或中断、查询。
每个C51浮点数占用连续的4个字节的存储单元,浮点数的存储也必须是连续的4个字节存储单元。
以上语句不能完成浮点数在2817、2864等E2PROM中的保存,因此必须为浮点数存储编写专门的存储程序。
定义ap是指向非易失性存储器2817A、2864的指针,非易失性存储器2817A、2864分配的地址为0x2200。
利用指针将RAM中的浮点数依次取出,按字节依次连续存储在非易失性存储器2817A、2864中。
也可以使用联合(共用体)将RAM中的浮点数依次取出,按字节依次连续存储在非易失性存储器2817A、2864中。
程序执行后,浮点数s的值就自动变为-12.5,并可以由浮点变量xx直接引用或参与运算。
程序流程框图如图1所示,程序如下:
#include
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#defined2864XBYTE[0x2200]
N
Y
N
Y
N
Y
图1并行EEPROM2864程序框图
#definesXFLOAT[0x0880]
/*4*0x880=0x2200浮点数占用4个字节*/
floatxdatak=-12.5;
uchar*ap=&d2864;
uchar*k_ap=&k;
floatxdataxx;
voiddelay(uinttt)/*延迟1mS子程序*/
{
uintk;
while(tt--!
=0)
{for(k=0;k<72;k++)continue;}
}
voidwritef_P2864(uintbyte_address,floatvalue)
{uchari;
union{floata;/*定义一个联合*/
ucharb[4];
}y;
y.a=value;/*将要写入的浮点数送给联合型变量*/
for(i=0;i<4;i++)/*写浮点数的四个字节数据至指定的地址*/
{XDATA[byte_address+i]=y.b[i];delay(10);}
}
floatreadf_XDATA(uintbyte_address)
{union{floata;/*定义一个联合*/
ucharb[4];
}y;
uchari;
floatx_value;
for(i=0;i<4;i++)/*从指定的地址读四个字节的浮点数据*/
{y.b[i]=XBYTE[byte_address+i];}
x_value=y.a;/*将读出的浮点数送给浮点变量x_value*/
return(x_value);/*返回读出的浮点数值x_value至原调用程序*/
}
main()
{uchari;
for(i=0;i<4;i++)/*依次从RAM中读出四个字节的浮点数*/
{while(*ap!
=*k_ap){*ap=*k_ap;
delay(10);/*延迟10mS时间,等待单字节写入结束*/
}
ap++;/*指向EEPROM的指针变量加1*/
k_ap++;/*指向RAM的指针变量加1*/
}
xx=s;/*从EEPROM中读出浮点数*/
xx=readf_XDATA(0x2200);
}
2.2浮点数在串行E2PROM中的存取
由于串行E2PROM如24C´´系列、93C´´系列等集成电路具有体积小、功耗低、价格便宜,使用中占用系统的信号线少,接口简单、通信方便的特点,但相对工作速度慢,读写方法要稍许复杂一些,因此被广泛应用于存储数据量不太大、写入速度要求不很高的场合。
自定时写周期包括自动擦除时间不超过10mS,典型时间为5mS。
同时串行E2PROM还有一个重要的特点是所有的DIP封装的产品都是8个引脚,而且引脚输出兼容,这就使性能更新升级变得很简单而经济。
由于串行E2PROM按字节或字操作,位串行通信,因此浮点数也只能以字节或字方式进行写操作,将浮点数四个字节依次分开的方法类似于并行的E2PROM,但必须有专门的写程序进行每个字节的串行写入。
而其读操作也与并行的E2PROM截然不同,被程序重新调用之前,必须将存储在串行E2PROM中的字节用专门的读程序串行的恢复到相应RAM中,不能直接在E2PROM中进行读操作。
24C32与8031的接口电路如图2所示。
同样可定义ap是指向存储器RAM6264(0x2200)的指针,串行非易失性存储器24C08、24C32等分配的地址为0xb000。
利用指针将在RAM中的浮点数依次取出(使用联合也可以将RAM中的浮点数依次取出),然后调用专门的串行字节写入子程序按字节依次连续存储在非易失性存储器24C08、24C32等中。
由于其特点,为了调用存储的浮点参数,首先要将存储在E2PROM连续单元中的字节数据,串行的读出来恢复到RAM中,进行各种操作。
程序执行后,浮点数s的值就自动变为-12.5,并可以由浮点变量xx直接引用或参与运算。
Vcc9
24C32
1
2
VCC
图224C32与8031接口电路
下面是以图2所示的电路编写的24C32存储浮点数程序。
24C32时序如图3、图5所示,程序流程框图如图4所示。
#include
#include
#include
图324C32时序图
#include
#defined6264XBYTE[0x2200]
#definesXFLOAT[0x880]/*4*0x880=0x2200浮点数占用4个字节*/
floatxdatak=-12.5;
uchar*ap=&d6264;
uchar*k_ap=&k;
uchari,xbyte;
floatxdataxx=10;
main()
{Init24C32();
for(i=0;i<4;i++)
{xbyte=*k_ap;/*xbyte=浮点数的第i个字节值*/
write(0xb000+i,xbyte);/*串行E2PROM字节写子程序*/
delay(720);/*延迟数10mS的时间,等待自定时写周期结束*/
k_ap++;
}
for(i=0;i<4;i++)
N
Y
N
Y
N
Y
N
Y
图4串行EEPROM24c32程序框图
{xbyte=read(0xb000+i);
/*串行E2PROM字节读子程序读浮点数第i个字节*/
*ap=xbyte;
/*将字节值放入RAM中*/
ap++;
}
xx=s;
}
write(addr,value)、read(addr)分别为单字节串行E2PROM存储、读取子程序。
Init24C32()
{SDA=1;/*SDA设定为“1”电平*/
SCL=1;/*SCL设定为“1”电平*/
}
voiddelay(uchartt)/*tt=72,延迟1mS*/
{
uchark;
for(k=0;k
}
voidSendAcknowledge(bitack)
{SDA=ack;/*设定SDA为要传送的确认信号*/
SCL=1;delay
(1);/*SCL作“1”到“0”的变化(即产生SCL下降沿)*/
SCL=0;
}
voidStart()
{SDA=1;
SCL=1;delay
(1);/*SDA和SCL先置为“1”电平,并延迟数μS的时间*/
SDA=0;delay
(1);/*SDA必须先清为“0”电平,并延迟数μS的时间*/
SCL=0;/*SCL才可以清为“0”电平*/
}
voidStop()
{SDA=0;delay
(1);/*SDA清为“0”电平,并延迟数μS的时间*/
SCL=1;delay
(1);/*SCL必须先置为“1”电平,并延迟数μS的时间*/
图5串行E2PROM启动和停止时序
SDA=1;/*SDA才可以置为“1”电平*/
}
voidwrite(uintaddr,ucharvalue)/*写字节数据到指定的地址*/
{Start();/*传送起始信号*/
SendByte(0xA0);/*传送从地址0xA0*/
SendByte(addr>>8);/*先传送地址高字节,再传送地址低字节*/
SedByte(addr&0xff);
SendByte(value);/*再将数据写入指定的地址内*/
Stop();/*传送停止信号*/
}
ucharread(uintaddr)/*从指定的地址读字节数据*/
{uchartemp;
start();/*传送起始信号*/
SendByte(0xA0);/*传送从地址0xA0*/
SendByte(addr>>8);/*先传送地址高字节,再传送地址低字节*/
SedByte(addr&0xff);
Start();/*再一次传送起始信号*/
SendByte(0xA1);/*传送从地址0xA1,即“读出”的从地址*/
temp=ReceiveByte();/*接收从EEPROM读出的数据,并暂存至temp变量*/
SendAcknowledge
(1);/*传送确认信号等于“1”电平*/
Stop();/*传送停止信号*/
return(temp);/*返回读出值temp至原调用程序*/
}
bitSendByte(ucharbytedata)/*传送一个字节数据的子程序*/
{uchari;
bitack;/*ack为“确认标志变量”*/
SDA=1;/*SDA先置为“1”电平*/
for(i=0;i<8;i++)/*要传送一个Byte数据,所以要执行8次*/
{if(bytedata&0x80)SDA=1;/*如果最高位为“1”,置SDA=“1”*/
elseSDA=0;/*否则清SDA=“0”*/
bytedata<<=1;delay
(1);/*每传送1位,则将待传数据左移1位*/
SCL=1;delay
(1);/*SCL作“1”到“0”的变化(即产生SCL下降沿)*/
SCL=0;delay
(1);
}
SDA=1;delay
(1);/*SDA和SCL先置为“1”电平,以让确认信号出现*/
SCL=1;delay
(1);
ack=SDA;/*读取确认信号*/
SCL=0;delay
(1);/*将SCL恢复为“0”电平*/
return(ack);/*返回确认信号(ack)至原调程序*/
}
ucharReceiveByte()/*读取一个字节数据的子程序*/
{uchari,bytedata=0;/*定义循环变量、读取的数据变量及初始化*/
for(i=0;i<8;i++)/*读取8个位,循环作8次*/
{SCL=1;delay
(1);/*SCL必须先置为“1”电平,并延迟数μS的时间*/
byteData<<=1;/*先将数据变量左移1位*/
if(SDA)bytedata|=0x01;/*如果SDA=“1”,则接收数据加1(bit0置“1”)*/
SCL=0;delay
(1);/*否则左移一位,bit0会自动清为0*/
}
return(bytedata);/*返回读到的数据至原调用程序*/
}
3结论
对于字节数据和字型数据的存取操作相对比较容易,而对C51浮点数的E2PROM存取操作则比较复杂,以上的方法在产品的设计过程中有切实的实用价值。
参考文献
马忠梅.单片机C语言应用程序设计.北京:
北京航空航天大学出版,2007.