将一个float型数据存到AT24C02中,再读出到串口显示,为啥串口显示的是一个错误的数呀?是我程序哪有问题吗?请各位大神指点。谢谢
#include<reg51.h>
#include <stdio.h>
#define write_c02 0xa0
#define read_c02 0xa1
typedef unsigned char uchar;
typedef unsigned int uint;
sbit sda = P2^0;
sbit scl = P2^1;
/*********延时**************/
void delay() //约5us
{
;;
}
void delayms(uint xms) //延时X毫秒
{
uchar x,y;
for(x=xms;x>0;x--)
for(y=110;y>0;y--);
}
/**********I2C子程序***************/
void i2c_init() //I2C初始化
{
sda=1;
delay();
scl=1;
delay();
}
void start() //启动I2C
{
sda=1;
scl=1;
delay(); //在scl为高电平时,sda一个下降沿为启动信号
sda=0;
delay();
}
void stop() //停止I2C
{
sda=0;
scl=1;
delay();
sda=1; //在scl为高电平时,sda一个上升沿为停止信号
delay();
}
void ack() //应答信号0
{
uchar i=0; //等待变量
scl=1; //在scl为高电平期间等待应答
delay();
while((sda=1)&&i<250)//若为应答0即退出,从机向主机发送应答信号
i++;
scl=0; //应答之后将scl拉低
delay();
}
void nack() //非应答
{
scl=1; //在scl为高电平期间,由主机向从机发送一个1;非应答信号
delay();
sda=1;
scl=0; //应答之后将scl拉低
delay();
}
void send_byte(uchar date) //写一个字节
{
uchar i , temp;
temp=date; //存入要写入的数据,即要发送到sda上的数据
for(i=0;i<8;i++)
{
temp<<=1;
scl=0; //只有在scl为低电平时,才允许sda上的数据变化
delay();
sda=CY; //将CY里的数据发送到sda数据线上
delay();
scl=1; //在scl为高电平时,不允许sda上的数据变化,使数据稳定
delay();
scl=0; //允许sda数据线的数据变化,等待下一个数据的传输
delay();
}//发送完一个字节数据后主机要等待从机的应答
scl=0;//允许sda变化
delay();
sda=1;//sda拉高等待应答,当sda=0时,表示从机应答
delay();
}
uchar read_byte() //读一个字节数据
{
uchar i,j,k;
scl=0; //读之前先允许sda变化
delay(); //等待数据
for(i=0;i<8;i++)
{
scl=1; //不允许sda变化
delay();
j=sda; //读出sda上的数据
k=(k<<1)|j;//将数据通过|运算存入K中
delay();
scl=0; //允许sda变化等待下一位数据的到来
delay();
}
delay();
return k; //返回读出的数据
}
/*****************从AT24C02中存取数据***********************/
void write_at24c02(uchar address,uchar date)//在at24c02中的指定地址写入数据、
{
start(); //启动I2C
send_byte(write_c02); //写入期间地址和写操作
ack(); //从机应答0
send_byte(address);//写入写数据的单元地址
ack();
send_byte(date);//在指定地址中写入数据
ack();
stop(); //停止I2C
}
uchar read_at24c02(uchar address)//在at24c02的指定地址中读出写入的数据
{
uchar dat; //用来存储读出的数据
start(); //启动I2C
send_byte(write_c02);//写入at24c02期间地址和写操作
ack();
send_byte(address); //写入要读取at24c02的数据的单元地址
ack();
start(); //再次启动I2C
send_byte(read_c02);//写入at24c02期间地址和读操作
ack();
dat=read_byte();//读出指定地址中的数据
nack();//主机发出非应答1
stop();//停止I2C
return dat;
}
/**********************从AT24C02中存取float型数据****************************/
void write_f_rom(uchar address,float date)//将系数存入AT24C02
{
unsigned long d;
unsigned char d0,d1,d2,d3;
d=(unsigned long)(date);
d0=(unsigned char)(d>>24);
d1=(unsigned char)((d&0x00ff0000)>>16);
d2=(unsigned char)((d&0x0000ff00)>>8);
d3=(unsigned char)(d%256);
delayms(10);
write_at24c02(address,d0);
delayms(10);
write_at24c02(address+0x01,d1);
delayms(10);
write_at24c02(address+0x02,d2);
delayms(10);
write_at24c02(address+0x03,d3);
delayms(10);
}
float read_f_rom(unsigned char address) //从AT24C02中读取数据
{
unsigned char i;
float date;
unsigned char c[4];
unsigned long d[4];
for(i=0;i<4;i++)
{
read_at24c02(address+i);
c[i]=read_at24c02(address+i);
}
for(i=0;i<4;i++)
{
d[i]=(unsigned long)c[i];
}
date=((float)((long)((d[0]<<24)+(d[1]<<16)+(d[2]<<8)+d[3])));
return date;
}
/******************串口初始化**********************/
void uart_init(void) //串口的初始化
{
TMOD=0x20;//即0010 0000,定时器/计数器1,工作方式2
TH1=0xfd;//设置波特率为9600
TL1=0xfd;
TR1=1;//启动定时器/计数器1
SCON=0x50; //0101 0000.串口工作方式1,允许串行控制
PCON=0x00;//设置SMOD=0
IE=0x90; //CPU允许中断,串行允许中断
TI=1;//直接使用printf必须加入此句才能实现发送
ES=1;//开串口中断
EA=1;//开总中断
}
void main()
{
// uchar i;
float shuju=1.1;
float shuju1;
i2c_init();
uart_init();
start();
while(1)
{
write_f_rom(0x00,shuju);
delayms(100);
shuju1=read_f_rom(0x00);
delayms(100);
printf("%.1f\n",shuju1);
delayms(200);
}
}
|