本帖最后由 bmfw 于 2015-1-20 16:45 编辑
近几日在研究I2C总线,发现程序可以正确读写PCF8563,把程序修改后读写24C256时,只有在0X0000地址可以正确读写,其它地址都无**确显示,不太明白,附上有关程序,望各位老大抽空看看,指点一下
#define PCF8563Addr 0xa2
#define AT24C256Addr 0xa6
#define DELAY5US nop();nop();nop();nop();nop()
/*端口位定义*/
sbit SDA=P2^2; /*模拟I2C数据传送位*/
sbit SCL=P2^7; /*模拟I2C时钟控制位*/
/*状态标志*/
bit ack;//应答标志位
/////////////////////////////////////////////////
//////I2C总线驱动子程序开始//////////////////////
/****启动I2C总线,即发送I2C起始条件**************/
static void Start_I2C()
{
SDA=1; //发送起始条件的数据信号
nop();
SCL=1; //起始条件建立时间大于4.7us
DELAY5US;
SDA=0; //发送起始信号*/
DELAY5US; // 起始条件锁定时间大于4.7μs
SCL=0; //钳住I2C总线,准备发送或接收数据
nop();nop();
}
/****结束I2C总线,即发送I2C结束条件**************/
static void Stop_I2C()
{
SDA=0; //发送结束条件的数据信号
nop(); //发送结束条件的时钟信号
SCL=1; //结束条件建立时间大于4.7μs
DELAY5US;
SDA=1; //发送I2C总线结束信号
DELAY5US;
}
/****向I2C总线发送一个字节,并请求应答,若收到应答则返回1*/
static void SendByte_I2C(uchar Byte)
{
uchar data i;
for(i=0;i<8;i++)//要传送的数据长度为8位
{
if((Byte<<i)&0x80){SDA=1;}else{SDA=0;}//判断发送位
nop();
SCL=1;//置时钟线为高,通知被控器开始接收数据位
DELAY5US;//保证时钟高电平周期大于4.7μs
SCL=0;
}
nop();nop();
SDA=1;//8位发送完后释放数据线,准备接收应答位
nop();nop();
SCL=1;
nop();nop();nop();
if(SDA==1){ack=0;}else{ack=1;}//判断是否接收到应答信号
SCL=0;
nop();nop();
}
/****从总线接收一个字节,并返回该字节,不回,****/
/****送应答信号,调用前保证SDA=1*****************/
static uchar RcvByte_I2C()
{
uchar data Data,i;
Data=0;
SDA=1;//置数据线为输入方式
for(i=0;i<8;i++)
{
nop();
SCL=0;//置时钟线为低,准备接收数据位
DELAY5US;
SCL=1;//置时钟线为高使数据线上数据有效
nop();nop();
Data=Data<<1;
if(SDA==1)Data=Data+1; //读数据位,接收的数据位放入retc中
nop();nop();
}
SCL=0;
nop();nop();
return(Data);
}
/****向I2C总线发送应答信号**********************/
static void Ack_I2C(bit a)
{
if(a==0){SDA=0;}else{SDA=1;}
nop();nop();nop();
SCL=1;
DELAY5US;
SCL=0;//清时钟线,钳住I2C总线以便继续接收
nop();nop();
}
//////I2C总线驱动子程序结束//////////////////////
//////8位地址驱动子程序开始//////////////////////
/****向pAddr器件内的Addr地址发送Data数据********/
static bit ISendByte(uchar pAddr,uchar Addr,uchar Data)
{
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0);//发送器件物理地址
SendByte_I2C(Addr);if(ack==0)return(0);//发送单元地址
SendByte_I2C(Data);if(ack==0)return(0);//发送数据
Stop_I2C();//结束总线
return(1);
}
/****向pAddr器件内的Addr地址开始发送Num数据*****/
static bit ISendStr(uchar pAddr,uchar Addr,uchar *s,uchar Num)
{
uchar data i;
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0);//发送器件物理地址
SendByte_I2C(Addr);if(ack==0)return(0);//发送器件单元地址
for(i=0;i<Num;i++)
{
SendByte_I2C(*s);if(ack==0)return(0);//发送数据
s++;
}
Stop_I2C();//结束总线
return(1);
}
/****从pAddr器件内的Addr地址接收一个字节的数据**/
static bit IRcvByt(uchar pAddr,uchar Addr,uchar *c)
{
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0); //发送器件物理地址
SendByte_I2C(Addr);if(ack==0)return(0);//发送器件单元地址
Start_I2C();//启动总线
SendByte_I2C(pAddr+1);if(ack==0)return(0);//发送单元地址
*c=RcvByte_I2C();//读取数据
Ack_I2C(1);//发送非就答位
Stop_I2C();//结束总线
return(1);
}
//////8位地址驱动子程序结束//////////////////////
//////以上程序参考了周立功单片机的有关程序
///////////////////////////////////////////////////////////
/////与PCF8563配套的有关程序开始///////////////////////////
/****PCF8563初始化******************************/
/*****读取PCF8563上的状态字进行判断,若没有初化过,则对其初化.....
******初化为日期20010525 时间09-00-00 星期5*****/
void IniPcf8563()
{
uchar data i,dat;
uchar code IniDat[13]={0x00,0x00,0x56,0x59,0x12,0x12,0x01,0x01,0x15,0X00,0X00,0X00,0X00};
///////////////////////控制 控制 秒 分 时 日 星期 月 年 分报警时报警日报警星期报警
/*定义为2001年5月25日星期五8:30分,前两个0是控制寄存器的命令,(前两字节是状态字)*/
//发送PCF8563的地址,调试提示,总线出错把0CH寄存器,用做初化标记
IRcvStr(PCF8563Addr,0x0c,&i,1);
if(i==0)return;//判断是否初化过
for(i=1;i<13;i++)
{
dat=IniDat;
ISendStr(PCF8563Addr,i,&dat,1);
}
}
/****从8位pAddr器件内的Addr地址接收Num个字节的数据*/
bit IRcvStr(uchar pAddr,uchar Addr,uchar *s,uchar Num)
{
uchar data i;
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0);//发送器件物理地址
SendByte_I2C(Addr);if(ack==0)return(0);//发送器件单元地址
Start_I2C();//启动总线
SendByte_I2C(pAddr+1);if(ack==0)return(0);//发送读单元地址命令
for(i=0;i<Num-1;i++)
{
*s=RcvByte_I2C();
Ack_I2C(0);//发送就答位
s++;
}
*s=RcvByte_I2C();
Ack_I2C(1);//发送非应位
Stop_I2C();//结束总线
return(1);
}
/////与PCF8563配套的有关程序结束///////////////////////////
//////16位地址驱动子程序开始/////////////////////
/****向pAddr器件内的Addr16位地址发送Data数据********/
static bit I16SendByte(uchar pAddr,uint16 Addr,uchar Data)
{
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0);//发送器件物理地址
SendByte_I2C(Addr>>8);if(ack==0)return(0);//发送单元地址高8位
SendByte_I2C(Addr&0xff);if(ack==0)return(0);//发送单元地址低8位
SendByte_I2C(Data);if(ack==0)return(0);//发送数据
Stop_I2C();//结束总线
return(1);
}
/****向pAddr器件内的Addr16位地址开始发送Num数据*****/
static bit I16SendStr(uchar pAddr,uint16 Addr,uchar *s,uchar Num)
{
uchar data i;
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0);//发送器件物理地址
SendByte_I2C(Addr/256);if(ack==0)return(0);//发送单元地址高8位
SendByte_I2C(Addr%256);if(ack==0)return(0);//发送单元地址低8位
for(i=0;i<Num;i++)
{
SendByte_I2C(*s);if(ack==0)return(0);//发送数据
s++;
}
Stop_I2C();//结束总线
return(1);
}
/****从pAddr器件内的Addr16位地址接收一个字节的数据**/
bit I16RcvByt(uchar pAddr,uint16 Addr,uchar *c)
{
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0); //发送器件物理地址
SendByte_I2C(Addr>>8);if(ack==0)return(0);//发送单元地址高8位
SendByte_I2C(Addr&0xff);if(ack==0)return(0);//发送单元地址低8位
Start_I2C();//启动总线
SendByte_I2C(pAddr+1);if(ack==0)return(0);//发送单元地址
*c=RcvByte_I2C();//读取数据
Ack_I2C(1);//发送非就答位
Stop_I2C();//结束总线
return(1);
}
//////16位地址驱动子程序结束/////////////////////
/////与AT24C256配套的有关程序开始//////////////////////////
void IniAT24C256()
{//在主程序中初始化几个数据,然后进行读,
uchar data Dat;
uchar code IniAT24C256[9]={0x20,0x15,0x01,0x14,0x10,0x56,0x55,0x19,0x99};
I16SendByte(AT24C256Addr,0x0000,0x69);//在0X0000发送数据0X69
Dat=IniAT24C256[0];
I16SendStr(AT24C256Addr,0x0001,&Dat,1);//在0X0001发送数据0X20
I16SendByte(AT24C256Addr,0x0002,0x34);//在0X0002发送数据0X34
}
/****从16位pAddr器件内的Addr16位地址接收Num个字节的数据*/
bit I16RcvStr(uchar pAddr,uint16 Addr,uchar *s,uchar Num)
{
uchar data i;
Start_I2C();//启动总线
SendByte_I2C(pAddr);if(ack==0)return(0);//发送器件物理地址
SendByte_I2C(Addr/256);if(ack==0)return(0);//发送单元地址高8位
SendByte_I2C(Addr%256);if(ack==0)return(0);//发送单元地址低8位
Start_I2C();//启动总线
SendByte_I2C(pAddr+1);if(ack==0)return(0);//发送读单元地址命令
for(i=0;i<Num-1;i++)
{
*s=RcvByte_I2C();
Ack_I2C(0);//发送就答位
s++;
}
*s=RcvByte_I2C();
Ack_I2C(1);//发送非应位
Stop_I2C();//结束总线
return(1);
}
/////与AT24C256配套的有关程序结束//////////////////////////
main()
{
uchar data TimeRam[7];//定义时间缓冲区
uchar data DataRam[3;//定义AT24C256测试数据缓冲区
IniPcf8563();//初始化8563
IniAT24C256();//初始化AT24C256
while(1)
{
IRcvStr(PCF8563Addr,0x02,TimeRam,7);//从0x02开始读取时间数据
...... /////显示时间数据
I16RcvStr(AT24C256Addr,0x0000,DataRam,3);//从0X0000 开始读3个数据
......////显示测试数据
}
}
|