搜索
bottom↓
回复: 41

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

[复制链接]

出0入0汤圆

发表于 2010-3-2 22:18:49 | 显示全部楼层 |阅读模式
//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[N-1]=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[7];
time[6]=yy;//年
time[5]=mm;//月
time[4]=da;//星期
time[3]=dd;//日
time[2]=hh;//时
time[1]=mi;//分
time[0]=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[0] &= 0x7F;//秒
time[1] &= 0x7F;//分
time[2] &= 0x3F;//时
time[3] &= 0x3F;//日
time[4] &= 0x07;//星期
time[5] &= 0x1F;//月
//time[6] &= 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[7];

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秒说明运行正常。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2010-3-2 22:23:24 | 显示全部楼层
该程序用PROTEUS仿真通过,但写进硬件后有问题,还没找到问题所在,请各位路过的大虾帮忙测试。

出0入0汤圆

 楼主| 发表于 2010-3-3 22:59:19 | 显示全部楼层
用M16调试通过(头文件已改成iom16v.h),但用M88有问题(头文件改成iom88v.h),是怎么回事呢?

出0入0汤圆

 楼主| 发表于 2010-3-5 23:26:22 | 显示全部楼层
问题已解决,原来是板子上SDA和SCL没有外接上拉电阻,必须设置AVR的内部上拉才行。

出0入0汤圆

 楼主| 发表于 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[N-1]=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[2],i;
END_PAGE=(ADDR+N)/PAGE_SIZE;
if(END_PAGE>NUM_PAGE-1)
{
  //not enough memory
  return;
}
PAGE=ADDR/PAGE_SIZE;
NBYTES[0]=(PAGE+1)*PAGE_SIZE-ADDR;
NBYTES[1]=(ADDR+N)-(END_PAGE*PAGE_SIZE);

if(NBYTES[0])
{
  i2c_write_n_bytes(SLA_W,ADDR,NBYTES[0],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[0]+(i++)*PAGE_SIZE));
   //delay_ms(10);//仿真时用延时代替器件忙检测
   while(i2c_check_busy(SLA_W));//器件忙检测
  }
  if(NBYTES[1])
  {
   i2c_write_n_bytes(SLA_W,(PAGE*PAGE_SIZE),NBYTES[1],(DAT+NBYTES[0]+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[2],i;
END_PAGE=(ADDR+N)/PAGE_SIZE;
if(END_PAGE>NUM_PAGE-1)
{
  //not enough memory
  return;
}
PAGE=ADDR/PAGE_SIZE;
NBYTES[0]=(PAGE+1)*PAGE_SIZE-ADDR;
NBYTES[1]=(ADDR+N)-(END_PAGE*PAGE_SIZE);

if(NBYTES[0])
{
  i2c_read_n_bytes(SLA_R,ADDR,NBYTES[0],DAT);
}
if(END_PAGE>PAGE)
{
  i=0;
  while(END_PAGE>++PAGE)
  {
   i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),PAGE_SIZE,(DAT+NBYTES[0]+(i++)*PAGE_SIZE));
  }
  if(NBYTES[1])
  {
   i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),NBYTES[1],(DAT+NBYTES[0]+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[7];
time[6]=yy;//年
time[5]=mm;//月
time[4]=da;//星期
time[3]=dd;//日
time[2]=hh;//时
time[1]=mi;//分
time[0]=ss;//秒
PCF8563_stop();
i2c_write_n_bytes(SLA_W_PCF8563,2,7,time);
PCF8563_start();
}

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


void main(void)
{
unsigned char dat[132];
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)

出0入0汤圆

发表于 2010-3-11 15:39:49 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-24 21:33:34 | 显示全部楼层
收下了。
正好想做个试验,准备就用你的代码测试了。
谢谢!

出0入0汤圆

发表于 2010-3-25 08:21:37 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-9 15:49:28 | 显示全部楼层
谢过,顶下,有时间试下

出0入0汤圆

发表于 2010-4-10 09:59:00 | 显示全部楼层
顶下

出0入0汤圆

发表于 2010-4-11 21:36:34 | 显示全部楼层
谢谢

出0入0汤圆

发表于 2010-5-10 16:53:54 | 显示全部楼层
编译时,提示没有函数 EEPROM_WRITE(0, dat);

出0入0汤圆

 楼主| 发表于 2010-5-10 18:25:42 | 显示全部楼层
#include <eeprom.h>

出0入0汤圆

发表于 2010-8-11 16:54:13 | 显示全部楼层
不错,谢谢!!!!!!!!!!

出0入0汤圆

发表于 2010-8-12 07:31:26 | 显示全部楼层
thank you very much.

出0入0汤圆

发表于 2010-8-12 20:22:42 | 显示全部楼层
以为是直接中断处理,这还是用查询的方法,

出0入0汤圆

发表于 2010-8-13 11:03:26 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-13 13:07:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-13 15:56:43 | 显示全部楼层
感谢许工,已经在mega88pa上测试了铁电FM24CL64,很好用,谢谢

出0入0汤圆

发表于 2010-11-18 15:52:12 | 显示全部楼层
学习了,谢谢楼主

出0入0汤圆

发表于 2010-12-7 16:59:40 | 显示全部楼层
谢谢了,想学下,

出0入0汤圆

发表于 2010-12-7 17:53:36 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-12-7 19:17:24 | 显示全部楼层
MARK

出0入0汤圆

发表于 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 STAR  0X08    //STAR信号发送完毕状态
#define RESTAR 0X10
#define MT_SLA_ACK   0X18  //从器件地址发送,返回ACK
#define MY_SLA_NOACK 0X20  //从器件地址发送,但是返回noACK
#define MT_DATA_ACK  0X28   //数据已发送,返回ack
#define MT_DATA_NOACK  0X30  //数据已发送,返回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;
}

出0入0汤圆

发表于 2010-12-13 19:09:44 | 显示全部楼层
谢谢

出0入0汤圆

 楼主| 发表于 2011-10-12 12:19:03 | 显示全部楼层
修正该程序只能写低256字节的BUG,
将程序中的 I2C_WRITE((unsigned char)ADDR>>8); 语句
用  I2C_WRITE((unsigned char)(ADDR>>8)); 替换。

出0入0汤圆

发表于 2011-12-14 19:39:54 | 显示全部楼层
不错,谢谢!!!!!!!!!!

出0入0汤圆

 楼主| 发表于 2012-1-13 20:17:08 | 显示全部楼层
回复【23楼】j__choi
-----------------------------------------------------------------------

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

问题出在这里,应改为:

#define TEXTACK()  (TWSR&0XF8)

出0入0汤圆

发表于 2012-1-14 08:09:16 | 显示全部楼层
谢lz

出0入0汤圆

发表于 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'错误,

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2015-1-6 13:11:53 | 显示全部楼层
本帖最后由 skyxjh 于 2015-1-6 13:22 编辑

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

出0入0汤圆

 楼主| 发表于 2015-1-6 13:26:13 | 显示全部楼层
发现网站的BUG了,[i]后的文本变成斜体了,而[]本身不显示了。

出0入0汤圆

 楼主| 发表于 2015-1-6 13:28:20 | 显示全部楼层
将I2C_WRITE(DAT);改为I2C_WRITE(*DAT++);或者I2C_WRITE(DAT[i]);

出0入0汤圆

 楼主| 发表于 2015-1-6 13:29:57 | 显示全部楼层
所以大家看到的源代码显示错了,

出0入0汤圆

 楼主| 发表于 2015-1-6 13:32:16 | 显示全部楼层
再发一次源码
  1. //ICC-AVR application builder : 2010-2-22 13:51:50
  2. // Target : M88
  3. // Crystal: 8.0000Mhz

  4. #include <iom88v.h>
  5. #include <macros.h>
  6. #include <eeprom.h>

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

  15. //TWSR&0xF8 状态码
  16. #define START                                  0x08
  17. #define RE_START                          0x10
  18. #define MT_SLA_ACK                          0x18
  19. #define MT_SLA_NAK                          0x20
  20. #define MT_DATA_ACK                          0x28
  21. #define MT_DATA_NAK                          0x30
  22. #define SLA_DATA_FAIL                  0x38
  23. #define MR_SLA_ACK                          0x40
  24. #define MR_SLA_NAK                          0x48
  25. #define MR_DATA_ACK                          0x50
  26. #define MR_DATA_NAK                          0x58

  27. //器件地址及参数
  28. #define SLA_R_24C64                          0xA1
  29. #define SLA_W_24C64                          0xA0
  30. #define PAGE_SIZE_24C64                  32
  31. #define NUM_PAGE_24C64                  256

  32. #define SLA_R_PCF8563                  0xA3
  33. #define SLA_W_PCF8563                  0xA2
  34. #define PAGE_SIZE_PCF8563          16
  35. #define NUM_PAGE_PCF8563          1

  36. //毫秒级延时
  37. void delay_ms(unsigned int x)
  38. {
  39. int i,j;
  40. for(j=0;j<x;j++)
  41.   for(i=0;i<1141;i++);
  42. }

  43. /************************************************************************
  44. I2C主机写N字节数据到从器件
  45. 编程:许工 QQ11520389
  46. 时间:2010.03.05
  47. 参数说明:
  48. SLA_W:          从器件写地址
  49. ADDR:          从器件内部写数据起始地址
  50. N:                  写数据字节数
  51. DAT:          源数据起始地址
  52. ************************************************************************/
  53. unsigned char i2c_write_n_bytes(unsigned char SLA_W, unsigned int ADDR,
  54.                                 unsigned int N, unsigned char *DAT)
  55. {
  56. unsigned int i;
  57. I2C_START();
  58. I2C_CHECK_STATUS(START);

  59. I2C_WRITE(SLA_W);
  60. I2C_NAK();
  61. I2C_CHECK_STATUS(MT_SLA_ACK);

  62. if(SLA_W!=SLA_W_PCF8563)
  63. {
  64.   I2C_WRITE((unsigned char)(ADDR>>8));
  65.   I2C_NAK();
  66.   I2C_CHECK_STATUS(MT_DATA_ACK);
  67. }
  68. I2C_WRITE((unsigned char)ADDR);
  69. I2C_NAK();
  70. I2C_CHECK_STATUS(MT_DATA_ACK);

  71. for(i=0;i<N;i++)
  72. {
  73.   I2C_WRITE(DAT[i]);
  74.   I2C_NAK();
  75.   I2C_CHECK_STATUS(MT_DATA_ACK);
  76. }

  77. I2C_STOP();
  78. return 1;
  79. }

  80. /************************************************************************
  81. I2C主机从从器件读N字节数据
  82. 编程:许工 QQ11520389
  83. 时间:2010.03.05
  84. 参数说明:
  85. SLA_R:          从器件读地址
  86. ADDR:          从器件内部读数据起始地址
  87. N:                  读数据字节数
  88. DAT:          目标数据起始地址
  89. ************************************************************************/
  90. unsigned char i2c_read_n_bytes(unsigned char SLA_R, unsigned int ADDR,
  91.                                unsigned int N, unsigned char *DAT)
  92. {
  93. unsigned int i;

  94. I2C_START();
  95. I2C_CHECK_STATUS(START);

  96. I2C_WRITE((SLA_R)-1);
  97. I2C_NAK();
  98. I2C_CHECK_STATUS(MT_SLA_ACK);

  99. if(SLA_R!=SLA_R_PCF8563)
  100. {
  101.   I2C_WRITE((unsigned char)(ADDR>>8));
  102.   I2C_NAK();
  103.   I2C_CHECK_STATUS(MT_DATA_ACK);
  104. }
  105. I2C_WRITE((unsigned char)ADDR);
  106. I2C_NAK();
  107. I2C_CHECK_STATUS(MT_DATA_ACK);

  108. I2C_START();
  109. I2C_CHECK_STATUS(RE_START);

  110. I2C_WRITE(SLA_R);
  111. I2C_NAK();
  112. I2C_CHECK_STATUS(MR_SLA_ACK);

  113. if(N>1)
  114. {
  115.   for(i=0;i<N-1;i++)
  116.   {
  117.    I2C_ACK();
  118.    I2C_CHECK_STATUS(MR_DATA_ACK);
  119.    I2C_READ(DAT[i]);
  120.   }
  121. }
  122. I2C_NAK();
  123. I2C_CHECK_STATUS(MR_DATA_NAK);
  124. DAT[N-1]=TWDR;

  125. I2C_STOP();
  126. return 1;
  127. }


  128. /************************************************************************
  129. I2C主机检测从器件忙
  130. 编程:许工 QQ11520389
  131. 时间:2010.03.05
  132. 参数说明:
  133. SLA_W:           从器件写地址
  134. 器件忙返回 1,否则返回 0,用于判断EEPROM是否编程完成
  135. ************************************************************************/
  136. unsigned char i2c_check_busy(unsigned char SLA_W)
  137. {
  138. unsigned char retv=0;
  139. I2C_START();
  140. I2C_CHECK_STATUS(START);
  141. I2C_WRITE(SLA_W);
  142. I2C_NAK();
  143. while(!(TWCR&BIT(TWINT)));
  144. if((TWSR&0xF8)!=MT_SLA_ACK)  retv=1;
  145. I2C_STOP();
  146. return retv;
  147. }

  148. /************************************************************************
  149. I2C主机写N字节数据到从器件(EEPROM)
  150. 编程:许工 QQ11520389
  151. 时间:2010.03.05
  152. 参数说明:
  153. SLA_W:           从器件写地址
  154. PAGE_SIZE: EEPROM页大小(单位:字节)
  155. NUM_PAGE:  EEPROM总页数
  156. ADDR:           从器件内部写数据起始地址
  157. N:                   写数据字节数
  158. DAT:           源数据起始地址
  159. ************************************************************************/
  160. void SEEPROM_write_n_bytes(unsigned char SLA_W,unsigned int PAGE_SIZE,unsigned int NUM_PAGE,
  161.                            unsigned int ADDR,unsigned int N,unsigned char *DAT)
  162. {
  163. unsigned int PAGE,END_PAGE,NBYTES[2],i;
  164. END_PAGE=(ADDR+N)/PAGE_SIZE;
  165. if(END_PAGE>NUM_PAGE-1)
  166. {
  167.   //not enough memory
  168.   return;
  169. }
  170. PAGE=ADDR/PAGE_SIZE;
  171. NBYTES[0]=(PAGE+1)*PAGE_SIZE-ADDR;
  172. NBYTES[1]=(ADDR+N)-(END_PAGE*PAGE_SIZE);

  173. if(NBYTES[0])
  174. {
  175.   i2c_write_n_bytes(SLA_W,ADDR,NBYTES[0],DAT);
  176.   //delay_ms(10);//仿真时用延时代替器件忙检测
  177.   while(i2c_check_busy(SLA_W));//器件忙检测
  178. }
  179. if(END_PAGE>PAGE)
  180. {
  181.   i=0;
  182.   while(END_PAGE>++PAGE)
  183.   {
  184.    i2c_write_n_bytes(SLA_W,(PAGE*PAGE_SIZE),PAGE_SIZE,(DAT+NBYTES[0]+(i++)*PAGE_SIZE));
  185.    //delay_ms(10);//仿真时用延时代替器件忙检测
  186.    while(i2c_check_busy(SLA_W));//器件忙检测
  187.   }
  188.   if(NBYTES[1])
  189.   {
  190.    i2c_write_n_bytes(SLA_W,(PAGE*PAGE_SIZE),NBYTES[1],(DAT+NBYTES[0]+i*PAGE_SIZE));
  191.    //delay_ms(10);//仿真时用延时代替器件忙检测
  192.    while(i2c_check_busy(SLA_W));//器件忙检测
  193.   }
  194. }
  195. }

  196. /************************************************************************
  197. I2C主机从从器件(EEPROM)读N字节数据
  198. 编程:许工 QQ11520389
  199. 时间:2010.03.05
  200. 参数说明:
  201. SLA_R:           从器件读地址
  202. PAGE_SIZE: EEPROM页大小(单位:字节)
  203. NUM_PAGE:  EEPROM总页数
  204. ADDR:           从器件内部读数据起始地址
  205. N:                   读数据字节数
  206. DAT:           目标数据起始地址
  207. ************************************************************************/
  208. void SEEPROM_read_n_bytes(unsigned char SLA_R,unsigned int PAGE_SIZE,unsigned int NUM_PAGE,
  209.                            unsigned int ADDR,unsigned int N,unsigned char *DAT)
  210. {
  211. unsigned int PAGE,END_PAGE,NBYTES[2],i;
  212. END_PAGE=(ADDR+N)/PAGE_SIZE;
  213. if(END_PAGE>NUM_PAGE-1)
  214. {
  215.   //not enough memory
  216.   return;
  217. }
  218. PAGE=ADDR/PAGE_SIZE;
  219. NBYTES[0]=(PAGE+1)*PAGE_SIZE-ADDR;
  220. NBYTES[1]=(ADDR+N)-(END_PAGE*PAGE_SIZE);

  221. if(NBYTES[0])
  222. {
  223.   i2c_read_n_bytes(SLA_R,ADDR,NBYTES[0],DAT);
  224. }
  225. if(END_PAGE>PAGE)
  226. {
  227.   i=0;
  228.   while(END_PAGE>++PAGE)
  229.   {
  230.    i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),PAGE_SIZE,(DAT+NBYTES[0]+(i++)*PAGE_SIZE));
  231.   }
  232.   if(NBYTES[1])
  233.   {
  234.    i2c_read_n_bytes(SLA_R,(PAGE*PAGE_SIZE),NBYTES[1],(DAT+NBYTES[0]+i*PAGE_SIZE));
  235.   }
  236. }
  237. }

  238. //PCF8563时钟停止指令
  239. void PCF8563_stop(void)
  240. {
  241. unsigned char stopcode=0x20;
  242. i2c_write_n_bytes(SLA_W_PCF8563,0,1,&stopcode);
  243. }

  244. //PCF8563时钟启动指令
  245. void PCF8563_start(void)
  246. {
  247. unsigned char startcode=0x00;
  248. i2c_write_n_bytes(SLA_W_PCF8563,0,1,&startcode);
  249. }

  250. /************************************************************************
  251. PCF8563时钟设置
  252. 编程:许工 QQ11520389
  253. 时间:2010.03.05
  254. 参数说明:(BCD码)
  255. yy:  年(0x00到0x99)
  256. mm:         月(0x01到0x12)
  257. dd:         日(0x01到0x31)
  258. hh:         时(0x00到0x23)
  259. mi:         分(0x00到0x59)
  260. ss:         秒(0x00到0x59)
  261. da:         星期(0x01到0x07)
  262. ************************************************************************/
  263. void PCF8563_set(unsigned char yy,unsigned char mm,unsigned char dd,
  264. unsigned char da,unsigned char hh,unsigned char mi,unsigned char ss)
  265. {
  266. unsigned char time[7];
  267. time[6]=yy;//年
  268. time[5]=mm;//月
  269. time[4]=da;//星期
  270. time[3]=dd;//日
  271. time[2]=hh;//时
  272. time[1]=mi;//分
  273. time[0]=ss;//秒
  274. PCF8563_stop();
  275. i2c_write_n_bytes(SLA_W_PCF8563,2,7,time);
  276. PCF8563_start();
  277. }

  278. /************************************************************************
  279. PCF8563时钟读取
  280. 编程:许工 QQ11520389
  281. 时间:2010.03.05
  282. 参数说明:(BCD码)
  283. time:          存放读出时间的数组名
  284. time[6]:  年(0x00到0x99)
  285. time[5]:  月(0x01到0x12)
  286. time[3]:  日(0x01到0x31)
  287. time[2]:  时(0x00到0x23)
  288. time[1]:  分(0x00到0x59)
  289. time[0]:  秒(0x00到0x59)
  290. time[4]:  星期(0x01到0x07)
  291. ************************************************************************/
  292. void PCF8563_read(unsigned char *time)
  293. {
  294. i2c_read_n_bytes(SLA_R_PCF8563,2,7,time);
  295. //time[6]       //年
  296. time[5] &= 0x1F;//月
  297. time[4] &= 0x07;//星期
  298. time[3] &= 0x3F;//日
  299. time[2] &= 0x3F;//时
  300. time[1] &= 0x7F;//分
  301. time[0] &= 0x7F;//秒
  302. }


  303. void main(void)
  304. {
  305. unsigned char dat[132];
  306. unsigned int i;

  307. DDRD|=3;//RED ON
  308. PORTD|=1;

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

  311. TWCR=0;
  312. TWBR=12; //set bit rate
  313. TWSR=0; //set prescale
  314. /*
  315. PCF8563_set(0x10,0x03,0x04,0x04,0x11,0x25,0x45);
  316. delay_ms(1000);
  317. PCF8563_read(dat);
  318. //*/
  319. //*
  320. for(i=0;i<132;i++) dat[i]=i;
  321. for(i=0;i<2;i++)
  322. SEEPROM_write_n_bytes(SLA_W_24C64,PAGE_SIZE_24C64,NUM_PAGE_24C64,i*66+4,66,dat);
  323. //*/
  324. //*
  325. for(i=0;i<132;i++) dat[i]=255;
  326. SEEPROM_read_n_bytes(SLA_R_24C64,PAGE_SIZE_24C64,NUM_PAGE_24C64,4,132,dat);
  327. //*/
  328. EEPROM_WRITE(0, dat);

  329. PORTD&=~1;
  330. PORTD|=2;//GREEN ON
  331. }
复制代码

出0入0汤圆

 楼主| 发表于 2015-1-6 13:34:20 | 显示全部楼层
看来以后源码必须用<>引用才行了。

出0入0汤圆

发表于 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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2015-1-6 13:52:06 | 显示全部楼层


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

出0入0汤圆

 楼主| 发表于 2015-1-7 20:24:35 | 显示全部楼层
用我的I2C读写函数,自己修改就可以了。

出0入0汤圆

发表于 2015-9-12 22:53:18 | 显示全部楼层
用到 参考参考。。

出0入0汤圆

发表于 2016-7-10 20:22:33 | 显示全部楼层
谢谢

出0入4汤圆

发表于 2017-6-26 21:31:26 | 显示全部楼层
多谢分享,正在改进24CXX烧录程序中,值得参考!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 22:33

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表