|
本程序参考了应用示例,注意由于PCF8563的晶振启动较慢,所以开机一定要加延时,否则肯定不稳定:
#include<avr/io.h>
#define uint unsigned int
#define uchar unsigned char
#define PCF8536_ADDR 0XA2
//#define TW_ACK 1
//#define TW_NACK 0
#define TW_READ 1
#define TW_WRITE 0
#define TW_START 0x08
#define TW_REP_START 0x10
/* Master Transmitter */
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MT_DATA_NACK 0x30
#define TW_MT_ARB_LOST 0x38
/* Master Receiver */
#define TW_MR_ARB_LOST 0x38
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_MR_DATA_NACK 0x58
/* Slave Transmitter */
#define TW_ST_SLA_ACK 0xA8
#define TW_ST_ARB_LOST_SLA_ACK 0xB0
#define TW_ST_DATA_ACK 0xB8
#define TW_ST_DATA_NACK 0xC0
#define TW_ST_LAST_DATA 0xC8
/* Slave Receiver */
#define TW_SR_SLA_ACK 0x60
#define TW_SR_ARB_LOST_SLA_ACK 0x68
#define TW_SR_GCALL_ACK 0x70
#define TW_SR_ARB_LOST_GCALL_ACK 0x78
#define TW_SR_DATA_ACK 0x80
#define TW_SR_DATA_NACK 0x88
#define TW_SR_GCALL_DATA_ACK 0x90
#define TW_SR_GCALL_DATA_NACK 0x98
#define TW_SR_STOP 0xA0
/* Misc */
#define TW_NO_INFO 0xF8
#define TW_BUS_ERROR 0x00
/*
* The lower 3 bits of TWSR are reserved on the ATmega163.
* The 2 LSB carry the prescaler bits on the newer ATmegas.
*/
#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3))
#define TW_STATUS (TWSR & TW_STATUS_MASK)
#define max 3
uchar lcdbuf[]={0x18,0xDB,0x8C,0X89,0X4B,0X29,0X28,0X9B,0X08,0X09,0X60,};
//从0~9是对的
uchar g_aTimeBin[7];//时钟/日历bcd格式缓冲区
uchar displaybuf[7];
/************************延时函数***********************/
void delay1(uint us)
{
while(us--);
}
void delay2(uint ms)
{
uint i,j;
for(i=0;i<ms;i++)
for(j=0;j<10;j++)
delay1(1);
}
/**********************端口初始化***************************/
void port_init(void)
{
DDRC=_BV(PC0)|_BV(PC1)|_BV(PC2);
PORTC|=_BV(PC0)|_BV(PC2)|_BV(PC4)|_BV(PC5);
}
/***************************lcd操作部分**********************/
void lcd_clk(void)
{
asm volatile ("cbi 0x08,2"::);
asm volatile ("sbi 0x08,2"::);
}
void sendbyte(uchar date)
{
uchar t;
for(t=0;t<8;t++)
{
if((date>>t)&0x01)
{
asm volatile ("sbi 0x08,1"::);
lcd_clk();
}
else
{
asm volatile ("cbi 0x08,1"::);
lcd_clk();
}
}
}
void displaylcd(uchar *buff)//一次发送7个字节显示lcd
{
uchar m;
for(m=0;m<7;m++)
sendbyte(buff[m]);
}
/*************atmega主模式TWI 操作部分*****开始**************/
void twi_init(void)
{
TWCR= 0X00; //disable twi
TWBR= 0x20; //set bit rate
TWSR=0x00; //set prescale
TWAR= 0x00; //set slave address
TWCR= 0x04; //enable twi
}
/*************PCF8536 操作********************开始**************/
uchar write_8563(uchar addr,uchar *buf,uchar num )
{
uchar twst,i,n=0x00,rv=0x01;
restart:
if(n++>=max)
goto error;
begin:
TWCR = _BV(TWINT)|_BV(TWSTA)|_BV(TWEN);//发送开始信号
while((TWCR&_BV(TWINT))==0x00);//等待发送完毕
switch((twst=TW_STATUS))
{
case TW_REP_START://有可能出现
case TW_START://0x08
break;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
TWDR=PCF8536_ADDR|TW_WRITE;//发送SLAV+W
TWCR=_BV(TWINT)|_BV(TWEN);//清TWINT,开始传输
while((TWCR&_BV(TWINT))==0x00);//等待传输完毕
switch((twst = TW_STATUS))
{
case TW_MT_SLA_ACK: //0x18
break;
case TW_MT_SLA_NACK://器件忙,有可能处于内部写周期
goto restart;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
TWDR=addr|TW_WRITE;//发送addr+W
TWCR=_BV(TWINT)|_BV(TWEN);//清TWINT,开始传输
while((TWCR & _BV(TWINT))==0x00);//等待传输完毕
switch((twst=TW_STATUS))
{
case TW_MT_DATA_ACK://0x28
break;
case TW_MT_DATA_NACK://器件忙,有可能处于内部写周期
goto restart;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
for(i=0;i<num;i++)
{
TWDR=*buf|TW_WRITE;
TWCR=_BV(TWINT)|_BV(TWEN);//清TWINT,开始传输
while((TWCR&_BV(TWINT))==0x00);//等待传输完毕
switch((twst=TW_STATUS))
{
case TW_MT_DATA_ACK://0x28
break;
case TW_MT_DATA_NACK://器件忙,有可能处于内部写周期
goto restart;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
buf++;
}
quit:
TWCR=_BV(TWINT)|_BV(TWSTO)|_BV(TWEN);//发送停止信号
return rv;// 正确返回1
error:
rv=0x0; //错误返回0
goto quit;
}
uchar read_8563(uchar addr,uchar *buf,uchar num)
{
uchar twst,i,n=0x00,rv=0x01;
restart:
if(n++>=max)
goto error;
begin:
TWCR=_BV(TWINT)|_BV(TWSTA)|_BV(TWEN);//发送开始信号
while((TWCR&_BV(TWINT))==0x00);//等待发送完毕
switch((twst = TW_STATUS))
{
case TW_REP_START://有可能出现
case TW_START: //0x08
break;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
TWDR=PCF8536_ADDR|TW_WRITE;//发送SLAV+W
TWCR=_BV(TWINT)|_BV(TWEN);//清TWINT,开始传输
while((TWCR&_BV(TWINT))==0x0);//等待传输完毕
switch((twst = TW_STATUS))
{
case TW_MT_SLA_ACK: //0x18
break;
case TW_MT_SLA_NACK://器件忙,有可能处于内部写周期
goto restart;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
TWDR=addr|TW_WRITE;//发送addr+W
TWCR=_BV(TWINT)|_BV(TWEN);//清TWINT,开始传输
while((TWCR & _BV(TWINT))==0x00);//等待传输完毕
switch((twst=TW_STATUS))
{
case TW_MT_DATA_ACK: //0x28
break;
case TW_MT_DATA_NACK://器件忙,有可能处于内部写周期
goto restart;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
TWCR=_BV(TWINT)|_BV(TWSTA)|_BV(TWEN);//发送(重新)开始信号
while((TWCR&_BV(TWINT))==0x00);//等待发送完毕
switch((twst=TW_STATUS))
{
case TW_REP_START://正确的状态 ,0x10
break;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
TWDR=PCF8536_ADDR|TW_READ;//发送SLAV+R
TWCR=_BV(TWINT)|_BV(TWEN);//清TWINT,开始传输
while((TWCR&_BV(TWINT))==0x00);//等待传输完毕
switch((twst=TW_STATUS))
{
case TW_MR_SLA_ACK: //0x40
break;
case TW_MR_SLA_NACK://器件忙,有可能处于内部写周期
goto restart;
case TW_MR_ARB_LOST:
goto begin;
default:
goto error;
}
for(i=0;i<num;i++)
{
if(i==(num-1))
{
TWCR=_BV(TWINT)|_BV(TWEN);//清TWINT,最后一个字节,开始传输(无应答)
}
else
{
TWCR=_BV(TWINT)|_BV(TWEN)|_BV(TWEA) ;//清TWINT,开始传输(有应答)
}
while((TWCR&_BV(TWINT))==0x00);//等待传输完毕
switch((twst=TW_STATUS))
{
case TW_MR_DATA_NACK:
case TW_MR_DATA_ACK:
*buf=TWDR;
buf++;
break;
default:
goto error;
}
}
quit:
TWCR=_BV(TWINT)|_BV(TWSTO)|_BV(TWEN);//发送停止信号
return rv; //正确返回1
error:
rv=0x00; //错误返回0
goto quit;
}
/*-------------------------------------------------------------------------
功能:将读出的时间数据的无关位屏蔽掉
说明:PCF8563时钟寄存器的有些无关位的状态是不定的,所以应该将无效位屏蔽掉
---------------------------------------------------------------------------*/
void Data_ajust(void)
{
g_aTimeBin[0]=g_aTimeBin[0]&0x7f;//秒时间无效位的屏蔽
g_aTimeBin[1]=g_aTimeBin[1]&0x7f;//分钟时间无效位的屏蔽
g_aTimeBin[2]=g_aTimeBin[2]&0x3f;//小时时间无效位的屏蔽
g_aTimeBin[3]=g_aTimeBin[3]&0x3f;
g_aTimeBin[4]=g_aTimeBin[4]&0x07;
g_aTimeBin[5]=g_aTimeBin[5]&0x1f;
g_aTimeBin[6]=g_aTimeBin[6]&0xff;
}
/*************************主函数*************************/
int main(void)
{
//MCUCR=0;
delay2(6000);//PCF8663的晶振启动时间慢
port_init();
twi_init();
uchar g_aTimeBuf[16]={0,0,0x30,0x10,0x08,0x11,0x06,0x11,0x06,0x80,0x80,0x80,0x80,0x00,0x00,0x00};
//写入2006年11月11日,9:20:30,其他功能无效
//uchar *buf1[7]={0xff,0xff,0xff,0xff,0xff,0xff,0xff};//清屏
//displaylcd(buf1);
write_8563(0x00,g_aTimeBuf,16);
while(1)
{
uchar z;
read_8563(0x02,g_aTimeBin,7);
Data_ajust();
displaybuf[0]=0xff;
displaybuf[1]=g_aTimeBin[0]&0x0f;//取秒低四位
displaybuf[2]=(g_aTimeBin[0]>>4)&0x0f;//取秒高四位
displaybuf[3]=g_aTimeBin[1]&0x0f;//取分钟低四位
displaybuf[4]=(g_aTimeBin[1]>>4)&0x0f;//取分钟高四位
displaybuf[5]=g_aTimeBin[2]&0x0f;//取小时低四位
displaybuf[6]=(g_aTimeBin[2]>>4)&0x0f;//取小时高四位
for(z=1;z<7;z++)
displaybuf[z]=lcdbuf[displaybuf[z]];
displaylcd(displaybuf);
delay2(400);
}
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|