首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 单片机 >

89C52 中,AT24C02不能延续读取数据,求解

2012-12-14 
89C52 中,AT24C02不能连续读取数据,求解请高手指点一下 。。。代码如下:#include stdio.h#include Reg52.h

89C52 中,AT24C02不能连续读取数据,求解
请高手指点一下 。。。
代码如下:

#include <stdio.h>
#include <Reg52.h>
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int
#define Nop3(); _nop_();_nop_();_nop_();
#define ACK(); SDA=0;NOP_3();SCL=1;NOP_3();SCL=0;   //读24CXX时,MCU的应答信号
sbit SCL=P0^1;
sbit SDA=P0^0;
sbit lcdRS=P1^0;
sbit lcdRW=P1^1;
sbit lcdEN=P1^2;
uchar table[14];

uchar bdata EEP;
sbit EEP_7 = EEP^7;
sbit EEP_0 = EEP^0;

//延时函数
void delay(uchar ms)
{
uchar i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}

void lcd_Command(uchar cmd)
{
lcdRS=0;//高电平为数据,低电平为批令
lcdEN=0;//发送时,发出高脉冲
P0=cmd;
delay(5);
lcdEN=1;
delay(5);
lcdEN=0;
}
void lcd_init()//初始化函数
{
   lcdRW=0;//高电平为读,低电平为写
   lcd_Command(0x38);//0011 1000  设置16*2显示 5*7点阵 8位数据接口
   lcd_Command(0x0E);//0000 1110  0000 1DCB (D=1显示 0不显示 ;C=1显示光标 0不显示光标; B=1光标闪 0 不闪)
   lcd_Command(0x06);//0000 0110  0000 01NS (N=1地址自动加1,0地址减1;S=1整屏左移 0右移)
   lcd_Command(0x01);//清屏  0x08//关闭显示 0x0C 显示开及光标位置
   //lcd_Command(0x10);

}



void lcd_SendData(uchar sd)
{
lcdRS=1;//高电平为数据,低电平为批令
lcdEN=0;
P0=sd;
delay(5);
lcdEN=1;
delay(5);
lcdEN=0;
}




//I2C开始
void I2C_Start(void)
{
SDA=1;
delay(1);
SCL=1;
delay(1);
SDA=0;
delay(1);
SCL=0;

}
//I2C结束
void I2C_Stop(void)
{
SDA=0;
delay(1);
SCL=1;
delay(1);
SDA=1;
delay(1);
}

/*************************************************
* 函数功能:等待IIC的应答信号
* 函数说明:若有应答则返回1,无应答则返回0
* 入口参数:
* 出口参数:无
**************************************************/
uchar TAck(void)
{
uchar var=4;
if(SDA)
 {
 while(--var)
 {
 Nop_3();
if(!SDA)
return 1;
 }
return 0;
 }
SCL=0;
return 1;
}

//应答
  
/**********************************************************

发送应答位子函数

在 SDA 低电平期间 SCL 发生一个正脉冲

**********************************************************/
void I2C_Ack(void)
{
uchar i;
//SDA=0;
//delay(1);
SCL=1;
delay(1);
while((SDA==1)&&(i<255)) i++;
SCL=0;
delay(1);
SDA=1;
}
//NO应答
/**********************************************************

发送非应答位子函数

在 SDA 高电平期间 SCL 发生一个正脉冲

**********************************************************/
void I2C_NoAck(void)
{
SDA=1;
delay(1);
SCL=1;
delay(1);
SCL=0;
delay(1);
SDA=1;
}

//写一个字节
void Write_Byte(uchar wdata)
{
uchar i;
EEP=wdata;
for(i=0;i<8;i++)
{
SDA=EEP_7;
SCL=1;
delay(1);
EEP<<=1;
SCL=0;
delay(1);
}

SDA=1;
delay(1);
SCL=0;
}

uchar Read_Byte(void)
{
uchar i;


//SCL=0;
//delay(1);
SDA=1;
//delay(1);
EEP=0;
for(i=0;i<8;i++)
{
EEP<<=1;
SCL=1;
    delay(1);
EEP_0=SDA;
SCL=0;
delay(1);
}
return EEP;


}
void I2C_Init()
{
SDA=1;
delay(1);
SCL=1;
delay(1);
}

void I2C_WriteStr(uchar *str,uchar address)
{
uchar i;
i=sizeof(str);
I2C_Start();//开始信号
Write_Byte(0xa0);//写器件地址
I2C_Ack();//应答
Write_Byte(address);//写起始地址
I2C_Ack();
for(i=0;i<14;i++)
{
Write_Byte(i);//写数据N
I2C_Ack();
}

I2C_Stop();//结束信号

}

void I2C_ReadStr(uchar str[],uchar address,uchar len)
{
uchar i;
I2C_Start();
Write_Byte(0xa0);//写器件地址及方向
I2C_Ack();
Write_Byte(address);  //起始地址
I2C_Ack();

//I2C_Start();//再次发送开始信号
//Write_Byte(0xa1);//发送器件地址及方向(读取)
//I2C_Ack();

for(i=0;i<8;i++)
{
I2C_Start();//再次发送开始信号
    Write_Byte(0xa1);//发送器件地址及方向(读取)
    I2C_Ack();
str[i]=Read_Byte();
I2C_Ack();
I2C_Stop();
}
I2C_Stop();

}

void main(void)
{

uchar temp,t;
    lcd_init();//初始化函数
I2C_Init();
I2C_WriteStr(table,1);
delay(250);
    I2C_ReadStr(table,1,10);
for(t=0;t<8;t++)
{
lcd_SendData(0x30+table[t]);
}

   /*
   
I2C_Start();
Write_Byte(0xa0);//写器件地址及方向
I2C_Ack();
Write_Byte(0);  //起始地址
I2C_Ack();
 */
I2C_Start();//再次发送开始信号
Write_Byte(0xa1);//发送器件地址及方向(读取)
I2C_Ack();
      
temp=Read_Byte();
   //I2C_Stop();

   //I2C_Start();
//Write_Byte(0xa1);//发送器件地址及方向(读取)

I2C_Ack(); 
t=Read_Byte();
I2C_Stop();

lcd_SendData(0x30+temp);
lcd_SendData(0x30+t);
lcd_SendData('1');


while(1)
{
;
}
}


[最优解释]
好混乱
1. 你主程序中根本就没连续去读写,都是单个读写的

2. 你的连续读写子函数有点不合理,读写数量应该放在函数参数中

    I2C_Start();//再次发送开始信号
    Write_Byte(0xa1);//发送器件地址及方向(读取)    
    I2C_Ack();
这个最好也放在子函数中,这样你主函数中调用连续读写会方便一点   

 给一个完整一点的你参考下






//iic.h

//for EEPROM

#ifndef _IIC_H_
#define _IIC_H_

#include "macro.h"
#include <stdint.h>
#include "DrvGPIO.h"
#include <stdlib.h>

//定义页长度
#define PAGELEN 32

//定义地址位数,如果是16位地址,移除下面定义
//#define ADDRESS_8BITS


#define SDA1E_GPA,10
#define SCL1E_GPA,11

void delay(void);
void delay_ms(unsigned long ms);
void I2C_Start();
void I2C_Stop();
bool Test_Ack();
void SendData(uint8_t buffer);

bool I2C_WriteNByte(uint8_t sla,uint16_t addr,uint8_t *s,uint16_t n);
bool I2C_ReadNByte(uint8_t sla,uint16_t addr,uint8_t *p,uint16_t n);
bool ReadPByte(uint8_t sla,uint16_t addr,uint8_t *p,uint16_t n);
bool WritePByte(uint8_t sla,uint16_t addr,uint8_t *p,uint16_t n);


uint32_t geteepsize(void);

#endif

  








//FileName:
//Device:
//Interface:
//BaseFile:
//Description: HY3116的驱动(iic接口)


#include "iic.h"
#include "global.h"

#define _nop_()__NOP()

void SDA_H(void)
{
DrvGPIO_SetBit(SDA1);
}
void SDA_L(void)
{
DrvGPIO_ClrBit(SDA1);
}
void SCL_H(void)
{
DrvGPIO_SetBit(SCL1);
}
void SCL_L(void)
{
DrvGPIO_ClrBit(SCL1);
}
uint8_t GetSDA(void)
{
return DrvGPIO_GetBit(SDA1);
}
void delay(void)
{
  uint8_t i;
  for(i=100;i>0;i--){__NOP();}
}

//不精确
void delay_ms(uint32_t ms)
{
uint8_t i;
while(ms>0)
{
for(i=0;i<125;i++)
{
__NOP();
}
ms--;
}
}


/*********************************************************
**名称:I2C_Start
**功能:启动I2C
**输入:无
**返回:无
*********************************************************/
void I2C_Start()
{
    SDA_H();
    delay();
    SCL_H();
    delay();
    SDA_L();
    delay();
    SCL_L();
}

/**********************************************************
**名称:I2C_Stop
**功能:停止I2C
**输入:无
**返回:无
**********************************************************/
void I2C_Stop()
{
    SDA_L();
    delay();
delay();
    SCL_H();
    delay();
delay();
    SDA_H();
    delay();
delay();
}




/**********************************************************
**名称:Ack
**功能:应答信号
**输入:无
**返回:无
**********************************************************/
void Ack()
{
    SDA_L();
    delay();
    SCL_H();
    delay();
    SCL_L();
    delay();
    SDA_H();
    delay();
}



/********************************************************
**名称:NoAck
**功能:发送非应答信号
**输入:无
**返回:无
********************************************************/
void NoAck()
{
    SDA_H();
    delay();
delay();
    SCL_H();
    delay();
delay();
    SCL_L();
    delay();
delay();
    SDA_L();
    delay();
delay();
}




/********************************************************
**名称:Test_Ack()
**功能:检测应答位
**输入:无
**返回:flag,有应答时flag为0,无应答时flag为1
*********************************************************/
bool Test_Ack()
{
bool flag;
    SCL_L();
    SDA_H();//读入数据
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    SCL_H();
    _nop_();_nop_();_nop_();_nop_();


    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    if(GetSDA()==0)
            flag=true;
    else        flag=false;
    SCL_L();
    return(flag);
}



/********************************************************
**名称:SendData()        
**功能:发送一字节数据
**输入:buffer
**返回:
*******************************************************/
void SendData(uint8_t buffer)
{
    uint8_t BitCnt=8;//一字节8位
    uint8_t temp=0;
    do
    {
        temp=buffer;
        SCL_L();
        delay();
        if((temp&0x80)==0) //
                SDA_L();
        else
                SDA_H();
        delay();
        SCL_H();
    //    temp=_crol_(buffer,1);//rl buff
   //     buffer=temp;
        buffer<<=1;
        BitCnt--;
    }
    while(BitCnt);
    SCL_L();
}

/**************************************************************
**名称:uint ReceiveData()
**功能:接收一字节数据
**输入:
**返回:ucReceData
**说明:将接收的数据存放在ucReceData中
**************************************************************/
uint8_t ReceiveData()
{
uint8_t ucReceData=0;
    uint8_t BitCnt=8;
    SDA_H();//读入数据
    do
    {
        SCL_L();
        delay();
        SCL_H();
        delay();
        if(GetSDA()==1)
                ucReceData=ucReceData
[其他解释]
 是程序不完整,楼上很详细···  
[其他解释]
自己顶,请多多指教呀
[其他解释]
AT24C02的PAGE大小是8BYTE,也就是你指定一次内存地址,可以从这个地址连续向后读取8字节数据,如果你读多了,会绕回刚才的这个地址的
[其他解释]
自己顶下,请 各位指点
[其他解释]
0x01;
//        else
//                ucReceData=ucReceData&0x0fe;
        if(BitCnt-1)
        {
                ucReceData<<=1;


        }
        BitCnt--;
    }
    while(BitCnt);
    SCL_L();
    return(ucReceData);
}

bool I2C_WriteNByte(uint8_t sla,uint16_t addr,uint8_t *s,uint16_t n)
{
    uint16_t i;
uint8_t suba;
uint8_t subab;
DrvGPIO_ClrBit(EEP_WP);
suba=(addr>>8);//地址高8位
subab=addr&0x00ff;//地址低8位
    I2C_Start();
    SendData(sla);
    if(Test_Ack()==false)        return(false);
#ifndef ADDRESS_8BITS
    SendData(suba);
if(Test_Ack()==false)        return(false);
#endif

    SendData(subab);
    if(Test_Ack()==false)        return(false);

    for(i=0;i<n;i++)
    {
        SendData(*(s+i));
        if(Test_Ack()==false)return(false);
    }
    I2C_Stop();
delay_ms(7);

DrvGPIO_SetBit(EEP_WP);

    return(true);
}

bool I2C_ReadNByte(uint8_t sla,uint16_t addr,uint8_t *p,uint16_t n)
{
    uint16_t i;
uint8_t suba;
uint8_t subab;
suba=(addr>>8);
subab=addr&0x00ff;
    I2C_Start();
    SendData(sla);
    if(Test_Ack()==false){return false;}
#ifndef ADDRESS_8BITS
    SendData(suba);
    if(Test_Ack()==false){return false;}
#endif

SendData(subab);
    if(Test_Ack()==false){return false;}

    I2C_Start();
    SendData(sla+1);
    if(Test_Ack()==false){return false;}
    for(i=0;i<n-1;i++)
    {
            *(p+i)=ReceiveData();
            Ack();
    }
    *(p+n-1)=ReceiveData();
        
    NoAck();
    I2C_Stop();
delay_ms(7);
    return true;
}

/**************************************************************************
Name:
Return:
Parameter:
Description: 当读/写的字节数可能超过一页时,用这个
***************************************************************************/
bool ReadPByte(uint8_t sla,uint16_t addr,uint8_t *p,uint16_t n)
{
uint16_t i;
uint16_t newadd;
bool t=true;
i=addr%PAGELEN;
i=PAGELEN-i;
newadd=addr+i;
if(I2C_ReadNByte(sla,addr,p,i)==false)t=false;
p+=i;
n-=i;
i=n/PAGELEN;
if(i<=0)return t;
for(;i!=0;i--)
{
if(I2C_ReadNByte(sla,newadd,p,PAGELEN)==false)t=false;
p+=PAGELEN;
newadd+=PAGELEN;
}
i=n%PAGELEN;
if(i>0)if(I2C_ReadNByte(sla,newadd,p,i)==false)t=false;
return t;
}
bool WritePByte(uint8_t sla,uint16_t addr,uint8_t *p,uint16_t n)
{
uint16_t i;
uint16_t newadd;


bool t=true;
i=addr%PAGELEN;
i=PAGELEN-i;
newadd=addr+i;
if(I2C_WriteNByte(sla,addr,p,i)==false)t=false;
p+=i;
n-=i;//剩余字节数
i=n/PAGELEN;
if(n<=0)return t;
for(;i!=0;i--)
{
if(I2C_WriteNByte(sla,newadd,p,PAGELEN)==false)t=false;
p+=PAGELEN;
newadd+=PAGELEN;
}
i=n%PAGELEN;
if(i>0)if(I2C_WriteNByte(sla,newadd,p,i)==false)t=false;
return t;

//获取EEPROM的大小
//原理过程
//1.读取0x0000出的数据并保存D0
//2.读取0xffff处的数据并保存DX
//3.写入一个!=DX并且!=D0的数DC至0xffff
//4.再读取0xffff的数,如果该数==DC并且0x0000中的数还是==D0则是64K否则再测试地址0x7fff
//!如果SIZE小于512字节则返回0,因为256字节的EEPROM地址只有8位,如果要检测则需要调整地址位数
//这里为简化处理,256及256以下的EEPROM直接返回0
uint32_t geteepsize(void)
{
uint16_t addr=0xffff;
uint8_t d00;//存放EEPROM中原0x0000地址内的数据
uint8_t dx0;//测试字节(EEPROM中最后一个字节)的数据
uint8_t d01;//0x0000处第二次读取的值
uint8_t dx1;//测试字节的第二次读数
uint8_t test;
I2C_ReadNByte(0xa0,0x00,&d00,1);
for(addr=0xffff;addr>=511;addr>>=1)
{
I2C_ReadNByte(0xa0,addr,&dx0,1);
if(d00!=0x71&&dx0!=0x71)
test=0x71;
else if(d00!=0xe6&&dx0!=0xe6)
test=0xe6;
else test=0x3c;

I2C_WriteNByte(0xa0,addr,&test,1);
delay_ms(7);
I2C_ReadNByte(0xa0,addr,&dx1,1);
I2C_ReadNByte(0xa0,0x00,&d01,1);//看看是不是写最后一个字节时回滚到第一个字节
if(dx1==test&&d01==d00)
{
I2C_WriteNByte(0xa0,0,&d00,1);//将2个地方的数据写回去,这样EEPROM的数据就不会变化
delay_ms(10);
I2C_WriteNByte(0xa0,addr,&dx0,1);
return addr+1;
}
}
return 0;
}
void clr_rom(void)
{
uint32_t i;
uint8_t temp[PAGELEN];
for(i=0;i<PAGELEN;i++)temp[i]=0;
for(i=0;i<ESIZE;i+=PAGELEN)
{
I2C_WriteNByte(0xa0,i,temp,PAGELEN);
delay_ms(7);//页面写入时间大约需要5ms
}
}


     
[其他解释]
是程序不完整,楼上很详细···
[其他解释]
请问一下:AT24C02是在上升沿将数据读出还是在高电平的时候?

[其他解释]
引用:
AT24C02的PAGE大小是8BYTE,也就是你指定一次内存地址,可以从这个地址连续向后读取8字节数据,如果你读多了,会绕回刚才的这个地址的

是上升沿时呀
[其他解释]
该回复于2012-11-09 13:05:14被版主删除
[其他解释]
引用:
请高手指点一下 。。。
代码如下:



C/C++ code



123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828……

主函数内,我读了呀

void main(void) {       uchar temp,t;     lcd_init();//初始化函数     I2C_Init();     I2C_WriteStr(table,1); //写EEPROM    delay(250);     I2C_ReadStr(table,1,10); //读EEPROM    for(t=0;t<8;t++)     {         lcd_SendData(0x30+table[t]);     }      /*以下全部为测试          I2C_Start();     Write_Byte(0xa0);//写器件地址及方向     I2C_Ack();     Write_Byte(0);  //起始地址     I2C_Ack();      */        I2C_Start();//再次发送开始信号     Write_Byte(0xa1);//发送器件地址及方向(读取)     I2C_Ack();               temp=Read_Byte();    //I2C_Stop();      //I2C_Start(); //  Write_Byte(0xa1);//发送器件地址及方向(读取)           I2C_Ack();      t=Read_Byte();     I2C_Stop();       lcd_SendData(0x30+temp);     lcd_SendData(0x30+t);         lcd_SendData('1');         while(1)     {     ;     } }




引用:
请高手指点一下 。。。
代码如下:



C/C++ code



123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828……

void main(void)
{

uchar temp,t;
        lcd_init();//初始化函数
I2C_Init();//I2C初始化
I2C_WriteStr(table,1);//写EEPROM
delay(250);
    I2C_ReadStr(table,1,10);//读EEPROM到TABLE内
for(t=0;t<8;t++)
{
lcd_SendData(0x30+table[t]);//显示
}

//begin 以下是读不出来后,写的测试

   /*
   
I2C_Start();
Write_Byte(0xa0);//写器件地址及方向
I2C_Ack();
Write_Byte(0);  //起始地址
I2C_Ack();
 */
I2C_Start();//再次发送开始信号
Write_Byte(0xa1);//发送器件地址及方向(读取)
I2C_Ack();
      
temp=Read_Byte();
   //I2C_Stop();

   //I2C_Start();
//Write_Byte(0xa1);//发送器件地址及方向(读取)

I2C_Ack(); 
t=Read_Byte();
I2C_Stop();

lcd_SendData(0x30+temp);
lcd_SendData(0x30+t);
lcd_SendData('1');
//end 测试结束

while(1)
{
;
}
}

[其他解释]
Write_Byte(0xa1);
检查一下AT24C02的地址是否为A1
[其他解释]
该回复于2012-11-19 12:58:11被版主删除
[其他解释]
引用:
自己顶下,请 各位指点
是的,只能读取一个字节,后面的就没有了,AT24C02按页无法读取!!

热点排行