硬件I2C(TWI)读写PCF8563和24CXX程序

//ICC-AVR application builder : 2010-3-5 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 
} 


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值