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秒说明运行正常。 该程序用PROTEUS仿真通过,但写进硬件后有问题,还没找到问题所在,请各位路过的大虾帮忙测试。 用M16调试通过(头文件已改成iom16v.h),但用M88有问题(头文件改成iom88v.h),是怎么回事呢? 问题已解决,原来是板子上SDA和SCL没有外接上拉电阻,必须设置AVR的内部上拉才行。 现将完整程序共享,希望对大家有帮助。也希望阿莫加精!
//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) mark 收下了。
正好想做个试验,准备就用你的代码测试了。
谢谢! mark 谢过,顶下,有时间试下 顶下 谢谢 编译时,提示没有函数 EEPROM_WRITE(0, dat); #include <eeprom.h> 不错,谢谢!!!!!!!!!! thank you very much. 以为是直接中断处理,这还是用查询的方法, mark mark 感谢许工,已经在mega88pa上测试了铁电FM24CL64,很好用,谢谢 学习了,谢谢楼主 谢谢了,想学下, MARK MARK 回复【楼主位】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;
} 谢谢 修正该程序只能写低256字节的BUG,
将程序中的 I2C_WRITE((unsigned char)ADDR>>8); 语句
用I2C_WRITE((unsigned char)(ADDR>>8)); 替换。 不错,谢谢!!!!!!!!!! 回复【23楼】j__choi
-----------------------------------------------------------------------
#define TEXTACK()(TWSR&=0XF8)
问题出在这里,应改为:
#define TEXTACK()(TWSR&0XF8) 谢lz 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:22 编辑
将I2C_WRITE(DAT);改为I2C_WRITE(*DAT++);或者I2C_WRITE(DAT); 发现网站的BUG了,后的文本变成斜体了,而[]本身不显示了。 将I2C_WRITE(DAT);改为I2C_WRITE(*DAT++);或者I2C_WRITE(DAT[i]); 所以大家看到的源代码显示错了,{:tongue:} 再发一次源码
//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
} 看来以后源码必须用<>引用才行了。 本帖最后由 一路花开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
skyxjh 发表于 2015-1-6 13:32
再发一次源码
您好,请问有没有AVR硬件TWI(I2C)读写PCF8576DT和AT24C02的源程序 ,谢谢 用我的I2C读写函数,自己修改就可以了。 用到 参考参考。。 谢谢 {:biggrin:}{:biggrin:}{:biggrin:}{:biggrin:}{:biggrin:} 多谢分享,正在改进24CXX烧录程序中,值得参考!
页:
[1]