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)
{
;
}
}
//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
}
}
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) { ; } }
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)
{
;
}
}