skyxjh 发表于 2010-3-2 22:18:49

AVR硬件TWI(I2C)读写PCF8563和AT24C64的源程序

//ICC-AVR application builder : 2010-2-22 13:51:50
// Target : M88
// Crystal: 8.0000Mhz

#include <iom16v.h>
#include <macros.h>
#include <eeprom.h>

#define I2C_START()                            TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWSTA)
#define I2C_STOP()                          TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWSTO)
#define I2C_ACK()                          TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWEA)
#define I2C_NAK()                          TWCR = BIT(TWINT)|BIT(TWEN)
#define I2C_CHECK_ACK(X)          {if((TWSR&0xF8)!=(X)) return 0;}
#define I2C_WRITE(X)                  TWDR = (X)
#define I2C_READ(X)                          (X) = TWDR

//TWSR&0xF8
#define START                                  0x08
#define RE_START                          0x10
#define MT_SLA_ACK                          0x18
#define MT_SLA_NAK                          0x20
#define MT_DATA_ACK                          0x28
#define MT_DATA_NAK                          0x30
#define SLA_DATA_FAIL                  0x38
#define MR_SLA_ACK                          0x40
#define MR_SLA_NAK                          0x48
#define MR_DATA_ACK                          0x50
#define MR_DATA_NAK                          0x58

#define SLA_R_24C64                          0xA1
#define SLA_W_24C64                          0xA0
#define SLA_R_PCF8563                  0xA3
#define SLA_W_PCF8563                  0xA2


unsigned char i2c_check_busy(void)
{
unsigned int overtime=0;
while(!(TWCR&BIT(TWINT)))
{
if(overtime++>1000) return 0;
}
return 1;
}


unsigned char i2c_write_n_bytes(unsigned char SLA_W, unsigned int ADDR,
                              unsigned char N, unsigned char *DAT)
{
unsigned char i;
I2C_START();
i2c_check_busy();
I2C_CHECK_ACK(START);

I2C_WRITE(SLA_W);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MT_SLA_ACK);

if(SLA_W!=SLA_W_PCF8563)
{
I2C_WRITE((unsigned char)ADDR>>8);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MT_DATA_ACK);
}
I2C_WRITE((unsigned char)ADDR);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MT_DATA_ACK);

for(i=0;i<N;i++)
{
I2C_WRITE(DAT);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MT_DATA_ACK);
}

I2C_STOP();
return 1;
}

unsigned char i2c_read_n_bytes(unsigned char SLA_R, unsigned int ADDR,
                               unsigned char N, unsigned char *DAT)
{
unsigned char i;

I2C_START();
i2c_check_busy();
I2C_CHECK_ACK(START);

I2C_WRITE((SLA_R)-1);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MT_SLA_ACK);

if(SLA_R!=SLA_R_PCF8563)
{
I2C_WRITE((unsigned char)ADDR>>8);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MT_DATA_ACK);
}
I2C_WRITE((unsigned char)ADDR);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MT_DATA_ACK);

I2C_START();
i2c_check_busy();
I2C_CHECK_ACK(RE_START);

I2C_WRITE(SLA_R);
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MR_SLA_ACK);

for(i=0;i<N-1;i++)
{
I2C_ACK();
i2c_check_busy();
I2C_CHECK_ACK(MR_DATA_ACK);
I2C_READ(DAT);
}
I2C_NAK();
i2c_check_busy();
I2C_CHECK_ACK(MR_DATA_NAK);
DAT=TWDR;

I2C_STOP();
return 1;
}

void RTC_start(void)
{
unsigned char data=0;
i2c_write_n_bytes(SLA_W_PCF8563,0,1,&data);
}

void RTC_stop(void)
{
unsigned char data=0x20;
i2c_write_n_bytes(SLA_W_PCF8563,0,1,&data);
}

void RTC_set(unsigned char yy,unsigned char mm,unsigned char dd,unsigned char da,
             unsigned char hh,unsigned char mi,unsigned char ss)
{
unsigned char time;
time=yy;//年
time=mm;//月
time=da;//星期
time=dd;//日
time=hh;//时
time=mi;//分
time=ss;//秒
RTC_stop();
i2c_write_n_bytes(SLA_W_PCF8563,2,7,time);
RTC_start();
}

void RTC_read(unsigned char *time)
{
RTC_stop();
i2c_read_n_bytes(SLA_R_PCF8563,2,7,time);
RTC_start();
time &= 0x7F;//秒
time &= 0x7F;//分
time &= 0x3F;//时
time &= 0x3F;//日
time &= 0x07;//星期
time &= 0x1F;//月
//time &= 0xFF;//年
}

void AT24C64_read(unsigned int ADDR,unsigned char N,unsigned char *DAT)
{
i2c_read_n_bytes(SLA_R_24C64,ADDR,N,DAT);
}

void AT24C64_write(unsigned int ADDR,unsigned char N,unsigned char *DAT)
{
i2c_write_n_bytes(SLA_W_24C64,ADDR,N,DAT);
}


void delay(unsigned int x)
{
int i,j;
for(j=0;j<x;j++)
for(i=0;i<1141;i++);
}

void main(void)
{
unsigned char DATA;

DDRD|=3;//RED ON
PORTD|=1;

TWBR = 2;//Bit rate 250kHz
TWSR = 1;

RTC_set(0x10,0x03,0x02,0x02,0x22,0x25,50);
delay(1000);
RTC_read(DATA);

AT24C64_write(0,7,DATA);
delay(10);
AT24C64_read(0,7,DATA);

EEPROM_WRITE(0, DATA);

PORTD&=~1;
PORTD|=2;//GREEN ON
}

注:
主函数里为测试程序,绿灯亮后,读出M88的EEPROM内容,与设置时间比较,增加1秒说明运行正常。

skyxjh 发表于 2010-3-2 22:23:24

该程序用PROTEUS仿真通过,但写进硬件后有问题,还没找到问题所在,请各位路过的大虾帮忙测试。

skyxjh 发表于 2010-3-3 22:59:19

用M16调试通过(头文件已改成iom16v.h),但用M88有问题(头文件改成iom88v.h),是怎么回事呢?

skyxjh 发表于 2010-3-5 23:26:22

问题已解决,原来是板子上SDA和SCL没有外接上拉电阻,必须设置AVR的内部上拉才行。

skyxjh 发表于 2010-3-5 23:43:28

现将完整程序共享,希望对大家有帮助。也希望阿莫加精!

//ICC-AVR application builder : 2010-2-22 13:51:50
// Target : M88
// Crystal: 8.0000Mhz

#include <iom88v.h>
#include <macros.h>
#include <eeprom.h>

//I2C(TWI)基本指令
#define I2C_START()                            TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWSTA)
#define I2C_STOP()                          TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWSTO)
#define I2C_ACK()                          TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWEA)
#define I2C_NAK()                          TWCR = BIT(TWINT)|BIT(TWEN)
#define I2C_CHECK_STATUS(X)          {while(!(TWCR&BIT(TWINT))); if((TWSR&0xF8)!=(X)) return 0;}
#define I2C_WRITE(X)                  TWDR = (X)
#define I2C_READ(X)                          (X) = TWDR

//TWSR&0xF8 状态码
#define START                                  0x08
#define RE_START                          0x10
#define MT_SLA_ACK                          0x18
#define MT_SLA_NAK                          0x20
#define MT_DATA_ACK                          0x28
#define MT_DATA_NAK                          0x30
#define SLA_DATA_FAIL                  0x38
#define MR_SLA_ACK                          0x40
#define MR_SLA_NAK                          0x48
#define MR_DATA_ACK                          0x50
#define MR_DATA_NAK                          0x58

//器件地址及参数
#define SLA_R_24C64                          0xA1
#define SLA_W_24C64                          0xA0
#define PAGE_SIZE_24C64                  32
#define NUM_PAGE_24C64                  256

#define SLA_R_PCF8563                  0xA3
#define SLA_W_PCF8563                  0xA2
#define PAGE_SIZE_PCF8563          16
#define NUM_PAGE_PCF8563          1

//毫秒级延时
void delay_ms(unsigned int x)
{
int i,j;
for(j=0;j<x;j++)
for(i=0;i<1141;i++);
}

/************************************************************************
I2C主机写N字节数据到从器件
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_W:          从器件写地址
ADDR:          从器件内部写数据起始地址
N:                  写数据字节数
DAT:          源数据起始地址
************************************************************************/
unsigned char i2c_write_n_bytes(unsigned char SLA_W, unsigned int ADDR,
                              unsigned int N, unsigned char *DAT)
{
unsigned int i;
I2C_START();
I2C_CHECK_STATUS(START);

I2C_WRITE(SLA_W);
I2C_NAK();
I2C_CHECK_STATUS(MT_SLA_ACK);

if(SLA_W!=SLA_W_PCF8563)
{
I2C_WRITE((unsigned char)ADDR>>8);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);
}
I2C_WRITE((unsigned char)ADDR);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);

for(i=0;i<N;i++)
{
I2C_WRITE(DAT);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);
}

I2C_STOP();
return 1;
}

/************************************************************************
I2C主机从从器件读N字节数据
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_R:          从器件读地址
ADDR:          从器件内部读数据起始地址
N:                  读数据字节数
DAT:          目标数据起始地址
************************************************************************/
unsigned char i2c_read_n_bytes(unsigned char SLA_R, unsigned int ADDR,
                               unsigned int N, unsigned char *DAT)
{
unsigned int i;

I2C_START();
I2C_CHECK_STATUS(START);

I2C_WRITE((SLA_R)-1);
I2C_NAK();
I2C_CHECK_STATUS(MT_SLA_ACK);

if(SLA_R!=SLA_R_PCF8563)
{
I2C_WRITE((unsigned char)ADDR>>8);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);
}
I2C_WRITE((unsigned char)ADDR);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);

I2C_START();
I2C_CHECK_STATUS(RE_START);

I2C_WRITE(SLA_R);
I2C_NAK();
I2C_CHECK_STATUS(MR_SLA_ACK);

if(N>1)
{
for(i=0;i<N-1;i++)
{
   I2C_ACK();
   I2C_CHECK_STATUS(MR_DATA_ACK);
   I2C_READ(DAT);
}
}
I2C_NAK();
I2C_CHECK_STATUS(MR_DATA_NAK);
DAT=TWDR;

I2C_STOP();
return 1;
}


/************************************************************************
I2C主机检测从器件忙
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_W:           从器件写地址
器件忙返回 1,否则返回 0,用于判断EEPROM是否编程完成
************************************************************************/
unsigned char i2c_check_busy(unsigned char SLA_W)
{
unsigned char retv=0;
I2C_START();
I2C_CHECK_STATUS(START);
I2C_WRITE(SLA_W);
I2C_NAK();
while(!(TWCR&BIT(TWINT)));
if((TWSR&0xF8)!=MT_SLA_ACK)retv=1;
I2C_STOP();
return retv;
}

/************************************************************************
I2C主机写N字节数据到从器件(EEPROM)
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_W:           从器件写地址
PAGE_SIZE: EEPROM页大小(单位:字节)
NUM_PAGE:EEPROM总页数
ADDR:           从器件内部写数据起始地址
N:                   写数据字节数
DAT:           源数据起始地址
************************************************************************/
void SEEPROM_write_n_bytes(unsigned char SLA_W,unsigned int PAGE_SIZE,unsigned int NUM_PAGE,
                           unsigned int ADDR,unsigned int N,unsigned char *DAT)
{
unsigned int PAGE,END_PAGE,NBYTES,i;
END_PAGE=(ADDR+N)/PAGE_SIZE;
if(END_PAGE>NUM_PAGE-1)
{
//not enough memory
return;
}
PAGE=ADDR/PAGE_SIZE;
NBYTES=(PAGE+1)*PAGE_SIZE-ADDR;
NBYTES=(ADDR+N)-(END_PAGE*PAGE_SIZE);

if(NBYTES)
{
i2c_write_n_bytes(SLA_W,ADDR,NBYTES,DAT);
//delay_ms(10);//仿真时用延时代替器件忙检测
while(i2c_check_busy(SLA_W));//器件忙检测
}
if(END_PAGE>PAGE)
{
i=0;
while(END_PAGE>++PAGE)
{
   i2c_write_n_bytes(SLA_W,(PAGE*PAGE_SIZE),PAGE_SIZE,(DAT+NBYTES+(i++)*PAGE_SIZE));
   //delay_ms(10);//仿真时用延时代替器件忙检测
   while(i2c_check_busy(SLA_W));//器件忙检测
}
if(NBYTES)
{
   i2c_write_n_bytes(SLA_W,(PAGE*PAGE_SIZE),NBYTES,(DAT+NBYTES+i*PAGE_SIZE));
   //delay_ms(10);//仿真时用延时代替器件忙检测
   while(i2c_check_busy(SLA_W));//器件忙检测
}
}
}

/************************************************************************
I2C主机从从器件(EEPROM)读N字节数据
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_R:           从器件读地址
PAGE_SIZE: EEPROM页大小(单位:字节)
NUM_PAGE:EEPROM总页数
ADDR:           从器件内部读数据起始地址
N:                   读数据字节数
DAT:           目标数据起始地址
************************************************************************/
void SEEPROM_read_n_bytes(unsigned char SLA_R,unsigned int PAGE_SIZE,unsigned int NUM_PAGE,
                           unsigned int ADDR,unsigned int N,unsigned char *DAT)
{
unsigned int PAGE,END_PAGE,NBYTES,i;
END_PAGE=(ADDR+N)/PAGE_SIZE;
if(END_PAGE>NUM_PAGE-1)
{
//not enough memory
return;
}
PAGE=ADDR/PAGE_SIZE;
NBYTES=(PAGE+1)*PAGE_SIZE-ADDR;
NBYTES=(ADDR+N)-(END_PAGE*PAGE_SIZE);

if(NBYTES)
{
i2c_read_n_bytes(SLA_R,ADDR,NBYTES,DAT);
}
if(END_PAGE>PAGE)
{
i=0;
while(END_PAGE>++PAGE)
{
   i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),PAGE_SIZE,(DAT+NBYTES+(i++)*PAGE_SIZE));
}
if(NBYTES)
{
   i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),NBYTES,(DAT+NBYTES+i*PAGE_SIZE));
}
}
}

//PCF8563时钟停止指令
void PCF8563_stop(void)
{
unsigned char stopcode=0x20;
i2c_write_n_bytes(SLA_W_PCF8563,0,1,&stopcode);
}

//PCF8563时钟启动指令
void PCF8563_start(void)
{
unsigned char startcode=0x00;
i2c_write_n_bytes(SLA_W_PCF8563,0,1,&startcode);
}

/************************************************************************
PCF8563时钟设置
编程:许工 QQ11520389
时间:2010.03.05
参数说明:(BCD码)
yy:年(0x00到0x99)
mm:       月(0x01到0x12)
dd:       日(0x01到0x31)
hh:       时(0x00到0x23)
mi:       分(0x00到0x59)
ss:       秒(0x00到0x59)
da:       星期(0x01到0x07)
************************************************************************/
void PCF8563_set(unsigned char yy,unsigned char mm,unsigned char dd,
unsigned char da,unsigned char hh,unsigned char mi,unsigned char ss)
{
unsigned char time;
time=yy;//年
time=mm;//月
time=da;//星期
time=dd;//日
time=hh;//时
time=mi;//分
time=ss;//秒
PCF8563_stop();
i2c_write_n_bytes(SLA_W_PCF8563,2,7,time);
PCF8563_start();
}

/************************************************************************
PCF8563时钟读取
编程:许工 QQ11520389
时间:2010.03.05
参数说明:(BCD码)
time:          存放读出时间的数组名
time:年(0x00到0x99)
time:月(0x01到0x12)
time:日(0x01到0x31)
time:时(0x00到0x23)
time:分(0x00到0x59)
time:秒(0x00到0x59)
time:星期(0x01到0x07)
************************************************************************/
void PCF8563_read(unsigned char *time)
{
i2c_read_n_bytes(SLA_R_PCF8563,2,7,time);
//time       //年
time &= 0x1F;//月
time &= 0x07;//星期
time &= 0x3F;//日
time &= 0x3F;//时
time &= 0x7F;//分
time &= 0x7F;//秒
}


void main(void)
{
unsigned char dat;
unsigned int i;

DDRD|=3;//RED ON
PORTD|=1;

DDRC&=~(BIT(PC4)|BIT(PC5));//Pull up the pin SDA and SCL
PORTC|=BIT(PC4)|BIT(PC5);

TWCR=0;
TWBR=12; //set bit rate
TWSR=0; //set prescale
/*
PCF8563_set(0x10,0x03,0x04,0x04,0x11,0x25,0x45);
delay_ms(1000);
PCF8563_read(dat);
//*/
//*
for(i=0;i<132;i++) dat=i;
for(i=0;i<2;i++)
SEEPROM_write_n_bytes(SLA_W_24C64,PAGE_SIZE_24C64,NUM_PAGE_24C64,i*66+4,66,dat);
//*/
//*
for(i=0;i<132;i++) dat=255;
SEEPROM_read_n_bytes(SLA_R_24C64,PAGE_SIZE_24C64,NUM_PAGE_24C64,4,132,dat);
//*/
EEPROM_WRITE(0, dat);

PORTD&=~1;
PORTD|=2;//GREEN ON
}

该程序同时也提供给大家一种调试程序的方法,充分利用AVR内置的EEPROM,只要一根下载线就可以完成程序的调试。主程序里的测试程序也给大家一种调试技巧,只要添加或删除一个“/”符号就可以屏蔽或启用一段代码。


硬件I2C(TWI)读写PCF8563和24CXX程序ourdev_536707.rar(文件大小:2K) (原文件名:I2C.rar)

shooly 发表于 2010-3-11 15:39:49

mark

zjczm 发表于 2010-3-24 21:33:34

收下了。
正好想做个试验,准备就用你的代码测试了。
谢谢!

hzn1948 发表于 2010-3-25 08:21:37

mark

shaoye 发表于 2010-4-9 15:49:28

谢过,顶下,有时间试下

sky_walker 发表于 2010-4-10 09:59:00

顶下

hailin0716 发表于 2010-4-11 21:36:34

谢谢

ylshu 发表于 2010-5-10 16:53:54

编译时,提示没有函数 EEPROM_WRITE(0, dat);

skyxjh 发表于 2010-5-10 18:25:42

#include <eeprom.h>

hpdell 发表于 2010-8-11 16:54:13

不错,谢谢!!!!!!!!!!

shouqiang_zhang 发表于 2010-8-12 07:31:26

thank you very much.

cyr_hongfeng 发表于 2010-8-12 20:22:42

以为是直接中断处理,这还是用查询的方法,

zengyi703 发表于 2010-8-13 11:03:26

mark

swustlx86 发表于 2010-8-13 13:07:55

mark

tdmi 发表于 2010-8-13 15:56:43

感谢许工,已经在mega88pa上测试了铁电FM24CL64,很好用,谢谢

tongyf 发表于 2010-11-18 15:52:12

学习了,谢谢楼主

chenxiongwei 发表于 2010-12-7 16:59:40

谢谢了,想学下,

kazuyuki 发表于 2010-12-7 17:53:36

MARK

411412 发表于 2010-12-7 19:17:24

MARK

j__choi 发表于 2010-12-11 22:13:22

回复【楼主位】skyxjh 许工
-----------------------------------------------------------------------

徐工你好,小弟刚刚学习avr单片机,最近也写了一个ds1307的程序,调了几天还是不行,徐工能帮我改改嘛?小弟感激不尽啊!我目前找出的原因是读DS1307时发送STAR信号之后老是出错。
#include<iom128v.h>
#include<macros.h>
#define IIC_START()TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
#define IIC_STOP()   TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
#define IIC_WAIT()   while(!(TWCR&(1<<TWINT)))
#define TEXTACK()(TWSR&=0XF8)
#define SETACK()   (TWCR|=(1<<TWEA))
//#define IIC_ACK()    TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA)
//#define IIC_NONEACK()TWCR=(1<<TWINT)|(1<<TWEN)
#define STAR0X08    //STAR信号发送完毕状态
#define RESTAR 0X10
#define MT_SLA_ACK   0X18//从器件地址发送,返回ACK
#define MY_SLA_NOACK 0X20//从器件地址发送,但是返回noACK
#define MT_DATA_ACK0X28   //数据已发送,返回ack
#define MT_DATA_NOACK0X30//数据已发送,返回noack
#define MR_SLA_ACK    0X40
#define MR_SLA_NOACK    0X48
#define MR_DATA_ACK    0X50
#define MR_DATA_NOACK    0X58
#define WriteDeviceAddress 0xd0
#define ReadDviceAddress 0xd1

unsigned char tab[]={0x20,0x12,0x14,0x16,0x04,0x17,0x11};
unsigned char tabb[];
unsigned char rtc_address[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06};

unsigned char IICWrite(unsigned char ad,unsigned char da)
{
IIC_START();
IIC_WAIT();
if(TEXTACK()!=STAR)
{
return 0;
}
TWDR=WriteDeviceAddress;
TWCR=(1<<TWINT)|(1<<TWEN);
IIC_WAIT();
if(TEXTACK()!=MT_SLA_ACK)
{
return 0;
}
TWDR=ad;
TWCR=(1<<TWINT)|(1<<TWEN);
IIC_WAIT();
if(TEXTACK()!=MT_DATA_ACK)
{
return 0;
}
TWDR=da;
TWCR=(1<<TWINT)|(1<<TWEN);
IIC_WAIT();
if(TEXTACK()!=MT_DATA_ACK)
{
return 0;
}
IIC_STOP();
return 1;
}


//读一个字节
unsigned char IICREAD (unsigned int ad)
{
unsigned char dat;
IIC_START();
IIC_WAIT();
if(TEXTACK()!=STAR)
{
return 1;
}
TWDR=WriteDeviceAddress;
TWCR=(1<<TWINT)|(1<<TWEN);
IIC_WAIT();
if(TEXTACK()!=MT_SLA_ACK)
{
return 0;
}
TWDR=ad;
TWCR=(1<<TWINT)|(1<<TWEN);
IIC_WAIT();
if(TEXTACK()!=MT_DATA_ACK)
{
return 0;
}
IIC_START();
IIC_WAIT();
if(TEXTACK()!=RESTAR)
{
return 0;
}
TWDR=ReadDviceAddress;
TWCR=(1<<TWINT)|(1<<TWEN);
IIC_WAIT();
if(TEXTACK()!=MR_SLA_ACK)
{
return 0;
}

TWCR=(1<<TWINT)|(1<<TWEN);
IIC_WAIT();
if(TEXTACK()!=MR_DATA_NOACK)
{
return 0;
}
dat=TWDR;
IIC_STOP();
return dat;
}


void Set_RTC(void)
{
unsigned char i,*p;
p=rtc_address;
for(i=0;i<7;i++)
{
IICWrite(*p,tab);
p++;
}
}


void Read_RTC(void)
{
unsigned char i,*p;
p=rtc_address;
for(i=0;i<7;i++)
{
tabb=IICREAD(*p);
p++;
}
}

void TWI_INIT()
{
DDRD=0XFF;
PORTD=0X00;
   TWCR=0X00;
   TWBR=0X20;
TWSR=0;
TWCR=0X44;
}

hailin0716 发表于 2010-12-13 19:09:44

谢谢

skyxjh 发表于 2011-10-12 12:19:03

修正该程序只能写低256字节的BUG,
将程序中的 I2C_WRITE((unsigned char)ADDR>>8); 语句
用I2C_WRITE((unsigned char)(ADDR>>8)); 替换。

qmsolo2004 发表于 2011-12-14 19:39:54

不错,谢谢!!!!!!!!!!

skyxjh 发表于 2012-1-13 20:17:08

回复【23楼】j__choi
-----------------------------------------------------------------------

#define TEXTACK()(TWSR&=0XF8)   

问题出在这里,应改为:

#define TEXTACK()(TWSR&0XF8)

monlika 发表于 2012-1-14 08:09:16

谢lz

一路花开1994 发表于 2015-1-6 12:00:24

skyxjh 发表于 2010-3-5 23:43
现将完整程序共享,希望对大家有帮助。也希望阿莫加精!

//ICC-AVR application builder : 2010-2-22 13:5 ...

AVR硬件TWI(I2C)读写PCF8563和AT24C64的源程序
出现了operands of=have illegal type 'unsigned char'and pointer to 'unsigned char'错误,

skyxjh 发表于 2015-1-6 13:11:53

本帖最后由 skyxjh 于 2015-1-6 13:22 编辑

将I2C_WRITE(DAT);改为I2C_WRITE(*DAT++);或者I2C_WRITE(DAT);

skyxjh 发表于 2015-1-6 13:26:13

发现网站的BUG了,后的文本变成斜体了,而[]本身不显示了。

skyxjh 发表于 2015-1-6 13:28:20

将I2C_WRITE(DAT);改为I2C_WRITE(*DAT++);或者I2C_WRITE(DAT[i]);

skyxjh 发表于 2015-1-6 13:29:57

所以大家看到的源代码显示错了,{:tongue:}

skyxjh 发表于 2015-1-6 13:32:16

再发一次源码
//ICC-AVR application builder : 2010-2-22 13:51:50
// Target : M88
// Crystal: 8.0000Mhz

#include <iom88v.h>
#include <macros.h>
#include <eeprom.h>

//I2C(TWI)基本指令
#define I2C_START()                            TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWSTA)
#define I2C_STOP()                          TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWSTO)
#define I2C_ACK()                          TWCR = BIT(TWINT)|BIT(TWEN)|BIT(TWEA)
#define I2C_NAK()                          TWCR = BIT(TWINT)|BIT(TWEN)
#define I2C_CHECK_STATUS(X)          {while(!(TWCR&BIT(TWINT))); if((TWSR&0xF8)!=(X)) return 0;}
#define I2C_WRITE(X)                  TWDR = (X)
#define I2C_READ(X)                          (X) = TWDR

//TWSR&0xF8 状态码
#define START                                  0x08
#define RE_START                          0x10
#define MT_SLA_ACK                          0x18
#define MT_SLA_NAK                          0x20
#define MT_DATA_ACK                          0x28
#define MT_DATA_NAK                          0x30
#define SLA_DATA_FAIL                  0x38
#define MR_SLA_ACK                          0x40
#define MR_SLA_NAK                          0x48
#define MR_DATA_ACK                          0x50
#define MR_DATA_NAK                          0x58

//器件地址及参数
#define SLA_R_24C64                          0xA1
#define SLA_W_24C64                          0xA0
#define PAGE_SIZE_24C64                  32
#define NUM_PAGE_24C64                  256

#define SLA_R_PCF8563                  0xA3
#define SLA_W_PCF8563                  0xA2
#define PAGE_SIZE_PCF8563          16
#define NUM_PAGE_PCF8563          1

//毫秒级延时
void delay_ms(unsigned int x)
{
int i,j;
for(j=0;j<x;j++)
for(i=0;i<1141;i++);
}

/************************************************************************
I2C主机写N字节数据到从器件
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_W:          从器件写地址
ADDR:          从器件内部写数据起始地址
N:                  写数据字节数
DAT:          源数据起始地址
************************************************************************/
unsigned char i2c_write_n_bytes(unsigned char SLA_W, unsigned int ADDR,
                              unsigned int N, unsigned char *DAT)
{
unsigned int i;
I2C_START();
I2C_CHECK_STATUS(START);

I2C_WRITE(SLA_W);
I2C_NAK();
I2C_CHECK_STATUS(MT_SLA_ACK);

if(SLA_W!=SLA_W_PCF8563)
{
I2C_WRITE((unsigned char)(ADDR>>8));
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);
}
I2C_WRITE((unsigned char)ADDR);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);

for(i=0;i<N;i++)
{
I2C_WRITE(DAT);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);
}

I2C_STOP();
return 1;
}

/************************************************************************
I2C主机从从器件读N字节数据
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_R:          从器件读地址
ADDR:          从器件内部读数据起始地址
N:                  读数据字节数
DAT:          目标数据起始地址
************************************************************************/
unsigned char i2c_read_n_bytes(unsigned char SLA_R, unsigned int ADDR,
                               unsigned int N, unsigned char *DAT)
{
unsigned int i;

I2C_START();
I2C_CHECK_STATUS(START);

I2C_WRITE((SLA_R)-1);
I2C_NAK();
I2C_CHECK_STATUS(MT_SLA_ACK);

if(SLA_R!=SLA_R_PCF8563)
{
I2C_WRITE((unsigned char)(ADDR>>8));
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);
}
I2C_WRITE((unsigned char)ADDR);
I2C_NAK();
I2C_CHECK_STATUS(MT_DATA_ACK);

I2C_START();
I2C_CHECK_STATUS(RE_START);

I2C_WRITE(SLA_R);
I2C_NAK();
I2C_CHECK_STATUS(MR_SLA_ACK);

if(N>1)
{
for(i=0;i<N-1;i++)
{
   I2C_ACK();
   I2C_CHECK_STATUS(MR_DATA_ACK);
   I2C_READ(DAT);
}
}
I2C_NAK();
I2C_CHECK_STATUS(MR_DATA_NAK);
DAT=TWDR;

I2C_STOP();
return 1;
}


/************************************************************************
I2C主机检测从器件忙
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_W:           从器件写地址
器件忙返回 1,否则返回 0,用于判断EEPROM是否编程完成
************************************************************************/
unsigned char i2c_check_busy(unsigned char SLA_W)
{
unsigned char retv=0;
I2C_START();
I2C_CHECK_STATUS(START);
I2C_WRITE(SLA_W);
I2C_NAK();
while(!(TWCR&BIT(TWINT)));
if((TWSR&0xF8)!=MT_SLA_ACK)retv=1;
I2C_STOP();
return retv;
}

/************************************************************************
I2C主机写N字节数据到从器件(EEPROM)
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_W:           从器件写地址
PAGE_SIZE: EEPROM页大小(单位:字节)
NUM_PAGE:EEPROM总页数
ADDR:           从器件内部写数据起始地址
N:                   写数据字节数
DAT:           源数据起始地址
************************************************************************/
void SEEPROM_write_n_bytes(unsigned char SLA_W,unsigned int PAGE_SIZE,unsigned int NUM_PAGE,
                           unsigned int ADDR,unsigned int N,unsigned char *DAT)
{
unsigned int PAGE,END_PAGE,NBYTES,i;
END_PAGE=(ADDR+N)/PAGE_SIZE;
if(END_PAGE>NUM_PAGE-1)
{
//not enough memory
return;
}
PAGE=ADDR/PAGE_SIZE;
NBYTES=(PAGE+1)*PAGE_SIZE-ADDR;
NBYTES=(ADDR+N)-(END_PAGE*PAGE_SIZE);

if(NBYTES)
{
i2c_write_n_bytes(SLA_W,ADDR,NBYTES,DAT);
//delay_ms(10);//仿真时用延时代替器件忙检测
while(i2c_check_busy(SLA_W));//器件忙检测
}
if(END_PAGE>PAGE)
{
i=0;
while(END_PAGE>++PAGE)
{
   i2c_write_n_bytes(SLA_W,(PAGE*PAGE_SIZE),PAGE_SIZE,(DAT+NBYTES+(i++)*PAGE_SIZE));
   //delay_ms(10);//仿真时用延时代替器件忙检测
   while(i2c_check_busy(SLA_W));//器件忙检测
}
if(NBYTES)
{
   i2c_write_n_bytes(SLA_W,(PAGE*PAGE_SIZE),NBYTES,(DAT+NBYTES+i*PAGE_SIZE));
   //delay_ms(10);//仿真时用延时代替器件忙检测
   while(i2c_check_busy(SLA_W));//器件忙检测
}
}
}

/************************************************************************
I2C主机从从器件(EEPROM)读N字节数据
编程:许工 QQ11520389
时间:2010.03.05
参数说明:
SLA_R:           从器件读地址
PAGE_SIZE: EEPROM页大小(单位:字节)
NUM_PAGE:EEPROM总页数
ADDR:           从器件内部读数据起始地址
N:                   读数据字节数
DAT:           目标数据起始地址
************************************************************************/
void SEEPROM_read_n_bytes(unsigned char SLA_R,unsigned int PAGE_SIZE,unsigned int NUM_PAGE,
                           unsigned int ADDR,unsigned int N,unsigned char *DAT)
{
unsigned int PAGE,END_PAGE,NBYTES,i;
END_PAGE=(ADDR+N)/PAGE_SIZE;
if(END_PAGE>NUM_PAGE-1)
{
//not enough memory
return;
}
PAGE=ADDR/PAGE_SIZE;
NBYTES=(PAGE+1)*PAGE_SIZE-ADDR;
NBYTES=(ADDR+N)-(END_PAGE*PAGE_SIZE);

if(NBYTES)
{
i2c_read_n_bytes(SLA_R,ADDR,NBYTES,DAT);
}
if(END_PAGE>PAGE)
{
i=0;
while(END_PAGE>++PAGE)
{
   i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),PAGE_SIZE,(DAT+NBYTES+(i++)*PAGE_SIZE));
}
if(NBYTES)
{
   i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),NBYTES,(DAT+NBYTES+i*PAGE_SIZE));
}
}
}

//PCF8563时钟停止指令
void PCF8563_stop(void)
{
unsigned char stopcode=0x20;
i2c_write_n_bytes(SLA_W_PCF8563,0,1,&stopcode);
}

//PCF8563时钟启动指令
void PCF8563_start(void)
{
unsigned char startcode=0x00;
i2c_write_n_bytes(SLA_W_PCF8563,0,1,&startcode);
}

/************************************************************************
PCF8563时钟设置
编程:许工 QQ11520389
时间:2010.03.05
参数说明:(BCD码)
yy:年(0x00到0x99)
mm:       月(0x01到0x12)
dd:       日(0x01到0x31)
hh:       时(0x00到0x23)
mi:       分(0x00到0x59)
ss:       秒(0x00到0x59)
da:       星期(0x01到0x07)
************************************************************************/
void PCF8563_set(unsigned char yy,unsigned char mm,unsigned char dd,
unsigned char da,unsigned char hh,unsigned char mi,unsigned char ss)
{
unsigned char time;
time=yy;//年
time=mm;//月
time=da;//星期
time=dd;//日
time=hh;//时
time=mi;//分
time=ss;//秒
PCF8563_stop();
i2c_write_n_bytes(SLA_W_PCF8563,2,7,time);
PCF8563_start();
}

/************************************************************************
PCF8563时钟读取
编程:许工 QQ11520389
时间:2010.03.05
参数说明:(BCD码)
time:          存放读出时间的数组名
time:年(0x00到0x99)
time:月(0x01到0x12)
time:日(0x01到0x31)
time:时(0x00到0x23)
time:分(0x00到0x59)
time:秒(0x00到0x59)
time:星期(0x01到0x07)
************************************************************************/
void PCF8563_read(unsigned char *time)
{
i2c_read_n_bytes(SLA_R_PCF8563,2,7,time);
//time       //年
time &= 0x1F;//月
time &= 0x07;//星期
time &= 0x3F;//日
time &= 0x3F;//时
time &= 0x7F;//分
time &= 0x7F;//秒
}


void main(void)
{
unsigned char dat;
unsigned int i;

DDRD|=3;//RED ON
PORTD|=1;

DDRC&=~(BIT(PC4)|BIT(PC5));//Pull up the pin SDA and SCL
PORTC|=BIT(PC4)|BIT(PC5);

TWCR=0;
TWBR=12; //set bit rate
TWSR=0; //set prescale
/*
PCF8563_set(0x10,0x03,0x04,0x04,0x11,0x25,0x45);
delay_ms(1000);
PCF8563_read(dat);
//*/
//*
for(i=0;i<132;i++) dat=i;
for(i=0;i<2;i++)
SEEPROM_write_n_bytes(SLA_W_24C64,PAGE_SIZE_24C64,NUM_PAGE_24C64,i*66+4,66,dat);
//*/
//*
for(i=0;i<132;i++) dat=255;
SEEPROM_read_n_bytes(SLA_R_24C64,PAGE_SIZE_24C64,NUM_PAGE_24C64,4,132,dat);
//*/
EEPROM_WRITE(0, dat);

PORTD&=~1;
PORTD|=2;//GREEN ON
}

skyxjh 发表于 2015-1-6 13:34:20

看来以后源码必须用<>引用才行了。

一路花开1994 发表于 2015-1-6 13:38:06

本帖最后由 一路花开1994 于 2015-1-6 13:39 编辑

skyxjh 发表于 2010-3-5 23:43
现将完整程序共享,希望对大家有帮助。也希望阿莫加精!

//ICC-AVR application builder : 2010-2-22 13:5 ...

出现了operands of=have illegal type 'arrary 132 of unsigned charr'and'unsigned char'   ,lvalue required

一路花开1994 发表于 2015-1-6 13:52:06

skyxjh 发表于 2015-1-6 13:32
再发一次源码

您好,请问有没有AVR硬件TWI(I2C)读写PCF8576DT和AT24C02的源程序 ,谢谢

skyxjh 发表于 2015-1-7 20:24:35

用我的I2C读写函数,自己修改就可以了。

waymcu 发表于 2015-9-12 22:53:18

用到 参考参考。。

d2016p 发表于 2016-7-10 20:22:33

谢谢 {:biggrin:}{:biggrin:}{:biggrin:}{:biggrin:}{:biggrin:}

BS_good200xy 发表于 2017-6-26 21:31:26

多谢分享,正在改进24CXX烧录程序中,值得参考!
页: [1]
查看完整版本: AVR硬件TWI(I2C)读写PCF8563和AT24C64的源程序