3回答

0收藏

pcf8563时钟快怎么回事?ATmega128,16M晶振

其他 其他 6984 人阅读 | 3 人回复 | 2012-09-13

//--------------------------------------------
//功能描述:通过IIC总线测试PCF8563芯片设定时间、读取时间
//作者:SLJ
//--------------------------------------------
//头函数
#include <avr/io.h>
#define sbi(sfr,bit) (_SFR_BYTE(sfr)|=_BV(bit))
#define cbi(sfr,bit) (_SFR_BYTE(sfr)&=~_BV(bit))
//--------------------------------------------
#define  DATA_OFF   PORTB&=~(1<<2)
#define  DATA_ON    PORTB|=(1<<2)
#define  LCK_OFF    PORTB&=~(1<<1)
#define  LCK_ON     PORTB|=(1<<1)
//全局变量声明
uint8_t date_time[20];//---存放当前时间
                        //0   年    //1   月    //2   日
                        //3   时    //4   分    //5   秒
uint8_t temp_data[8];//存放中间变量
uint8_t dat[8];
uint8_t num;
//--------------------------------------------
uint8_t  DSY_d[]={    //字型码(段选码)0-9,低电平有效
0xC0,0xF9,0xA4,0xB0,
0x99,0x92,0x82,0xF8,
0x80,0x90};
//uint8_t  DSY_w[]={              //低电平有效
//0xfe,0xfd,0xfb,0xf7,
//0xef,0xdf,0xbf,0x7f};     //位选信号
//#define  PORT_Duan    PORTB   //数码管段显
//#define  PORT_Wei     PORTA   //数码管位显
void delay(int z)
{
while(z--)
{
uint8_t a;
for(a=0;a<150;a++);
}
}
/*void SEG_DSY( void )      
{
   
   // PORT_Wei = PORT_Wei ;     
// PORT_Duan= 0Xff;         
PORT_Duan  = DSY_d[ dat[0]];   
    PORT_Wei=0XFE;
    delay(60000);
    PORT_Duan  = DSY_d[ dat[1]];   
    PORT_Wei=0XFE;
    delay(60000);
// PORT_Wei = 0Xff;        
// PORT_Wei=~DSY_w[ num ] ;   
// if(++num==6) num = 0 ;
}*/
//延时子程序
void delay_ms1(void)
{
uint8_t i,j,m;
for(i=1;i<2;i++)
{ for(j=1;j<2;j++)
  { for(m=1;m<2;m++)
   {;}
        }
    }
}
void delay_1ms(uint8_t xtal)
{
uint8_t i;
for(i=1;i<(uint8_t)(xtal*143-2);i++)
    {;}
}
//2 延时nms
void delay_ms(uint8_t m, uint8_t fosc)
{
uint8_t i;
i=0;
while(i<m)
{
  delay_1ms(fosc);
  i++;
}
}

//--------------------------------------------
//转BCD码子程序
int8_t _BCD(int8_t input)
{
uint8_t temp,result1=0;
temp=input/10;
result1|=(temp<<4);
temp=input%10;
temp&=(0x0f);
result1|=temp;
return result1;
}
//--------------------------------------------
//BCD码转
int8_t BCD_(int8_t input)
{
uint8_t temp,result1;
result1=0;
temp=(input>>4)*10;
result1=temp+(input&0x0f);
return result1;
}
//--------------------------------------------
//IIC写操作子程序;address_device为器件地址:0xa2,address_reg,data_package为写的数据
void TWI_WRITE(uint8_t address_device,uint8_t address_reg1, uint8_t data_package)
{
//TWI预分频为4分频
sbi(TWSR,TWPS0);
cbi(TWSR,TWPS1);
TWBR=0x40;//SCL频率92160HZ
begin:
TWCR=_BV(TWEN)|_BV(TWSTA)|_BV(TWINT);
while(!(TWCR&_BV(TWINT)))//等待TWINT置位,TWINT置位表示开始信号发送完毕
  ;
if(((TWSR&0xF8)!=0x08)&((TWSR&0xF8)!=0x10))//检查状态寄存器,如果状态字不是START或RESTART,重新发送开始信号
  goto begin;
TWDR=address_device;//将器件地址写入到TWDR寄存器,TWINT位清零,启动发送地址
    TWDR=address_device;
TWCR=_BV(TWEN)|_BV(TWINT);
while(!(TWCR&_BV(TWINT)))//等待TWINT置位,TWINT置位表示总线命令SLA+W已发出,及收到应答信号ACK/NACK
  ;
if((TWSR&0xF8)!=0x18)//检查TWI状态寄存器,如果状态字不是地址ACK,重新发送开始信号
  goto begin;
TWDR=address_reg1;//写寄存器地址
TWDR=address_reg1;
TWCR=_BV(TWEN)|_BV(TWINT);
while(!(TWCR&_BV(TWINT)))//等待TWINT置位,TWINT置位表示总线命令SLA+W已发出,及收到应答信号ACK/NACK
  ;
if((TWSR&0xF8)!=0x28)//检查TWI状态寄存器,如果状态字不是地址ACK,重新发送开始信号
  goto begin;
TWDR=data_package;//将数据载入到TWDR寄存器,TWINT位清零,启动发送地址
TWDR=data_package;
TWCR=_BV(TWINT)|_BV(TWEN);
while(!(TWCR&_BV(TWINT)))//等待TWINT置位,TWINT置位表示总线数据已发出,及收到应答信号ACK/NACK
;  
if((TWSR&0xF8)!=0x28)//检查TWI状态寄存器,如果状态字不是数据ACK,重新发送开始信号
  goto begin;
TWCR=_BV(TWINT)|_BV(TWSTO)|_BV(TWEN);//发送STOP信号
delay_ms(2,8);
delay_ms(2,8);
delay_ms(2,8);
}
//-------------------------------------------
//IIC读操作,address_device为器件地址:0xa2+1,address_reg1为寄存器地址,
uint8_t TWI_READ(uint8_t address_device,uint8_t address_reg1)
{
uint8_t result1=0;
sbi(TWSR,TWPS0);//TWI预分频为4分频
cbi(TWSR,TWPS1);
TWBR=0x02;//SCL频率92160HZ
begin:
//delay_ms(2,8);
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);//发送开始信号
while(!(TWCR&(1<<TWINT)))//等待开始信号发送完毕
  ;
if(((TWSR&0xF8)!=0x08)&((TWSR&0xF8)!=0x10))//检查TWI状态寄存器,如果状态字不是START或RESTART,重新发送开始信号
  goto begin;
TWDR=address_device;//发器件写地址,TWINT位清零,启动发送
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)))//等待TWINT置位,TWINT置位表示总线命令SLA+W已发出,及收到应答信号ACK/NACK
  ;
if((TWSR&0xF8)!=0x18)//检查TWI状态寄存器,如果状态字不是地址ACK,重新发送开始信号
  goto begin;
TWDR=address_reg1;//写寄存器地址,TWINT位清零,启动发送
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)))//等待TWINT置位,TWINT置位表示总线数据已发出,及收到应答信号ACK/NACK
  ;
if((TWSR&0xF8)!=0x28)//检查TWI状态寄存器,如果状态字不是数据ACK,重新发送开始信号
  goto begin;
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);//发送开始信号
while(!(TWCR&(1<<TWINT)))//等待TWINT置位,TWINT置位表示开始信号发送完毕
  ;
if(((TWSR&0xF8)!=0x08)&((TWSR&0xF8)!=0x10))//检查TWI状态寄存器,如果状态字不是START或RESTART,重新发送开始信号
  goto begin;
TWDR=address_device+1;//读器件地址写入到TWDR寄存器,TWINT位清零,启动发送
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)))//等待TWINT置位,TWINT置位表示总线命令SLA+W已发出,及收到应答信号ACK/NACK
  ;
if((TWSR&0xF8)!=0x40)//检查TWI状态寄存器,如果状态字不是地址ACK,重新发送开始信号
  goto begin;
TWCR=(1<<TWINT)|(1<<TWEN);//发送NACK信号
while(!(TWCR&(1<<TWINT)))
  ;
if((TWSR&0xF8)!=0x58)
  goto begin;
TWCR=(1<<TWSTO)|(1<<TWEN);//发送STOP信号
result1=TWDR;//将TWDR寄存器的数据读入
//delay_ms(2,8);
//delay_ms(2,8);
delay_ms(2,8);
return result1;
}
//--------------------------------------------
//8563操作子程序,包括写控制字和时间校准,转换成BCD码在程序中完成
void CALENDAR_WRITE(uint8_t year,uint8_t month,uint8_t date,uint8_t hour,uint8_t minute,uint8_t second)
{
    uint8_t temp=0;
    TWI_WRITE(0xa2,0x00,0x20);//写控制字,寄存器锁定
temp=_BCD(second)&0x7f;//写秒
TWI_WRITE(0xa2,0x02,temp);
TWI_WRITE(0xa2,0x03,_BCD(minute));//写分钟
TWI_WRITE(0xa2,0x04,_BCD(hour));//写小时
TWI_WRITE(0xa2,0x05,_BCD(date));//写日期
temp=_BCD(month)&0x7f;//写月
TWI_WRITE(0xa2,0x07,temp);
TWI_WRITE(0xa2,0x08,_BCD(year));//写年
TWI_WRITE(0xa2,0x00,0x00);//写控制字,重新启动时钟
}
//--------------------------------------------
//读8563,返回BCD码数组
void CALENDAR_READ(void)
{ uint8_t temp;
TWI_WRITE(0xa2,0x00,0x20);//写控制字,时钟停止运行
//----------
temp=TWI_READ(0xa2,0x08);//读年
temp=BCD_(temp);
date_time[0]=temp;
//----------
temp=TWI_READ(0xa2,0x07);//读月
temp&=0x1F;//将5、6、7屏蔽
temp=BCD_(temp);
date_time[1]=temp;
//----------
temp=TWI_READ(0xa2,0x05);//读日
temp&=0x3F;//将6、7屏蔽
temp=BCD_(temp);
date_time[2]=temp;
//----------
temp=TWI_READ(0xa2,0x04);//读时
temp&=0x3F;//将6、7屏蔽
temp=BCD_(temp);
date_time[3]=temp;
//----------
temp=TWI_READ(0xa2,0x03);//读分
temp&=0x7F;//将7屏蔽
temp=BCD_(temp);
date_time[4]=temp;
//----------
temp=TWI_READ(0xa2,0x02);//读秒
temp&=0x7F;//将7屏蔽
temp=BCD_(temp);
date_time[5]=temp;
//----------
TWI_WRITE(0xa2,0x00,0x00);//写控制字,重新启动时钟
}
//--------------------------------------------

void segvalue(void)
{  
   dat[0]=date_time[5]%10 ;//秒
   dat[1]=date_time[5]/10 ; //十秒
   
  
  
   dat[2]=date_time[4]%10; //分
   
   dat[3]=date_time[4]/10 ; //十分
   
   
   dat[4]=date_time[3]%10;  //时
   
   dat[5]=date_time[3]/10 ; //十时
   dat[6]=date_time[0]%10;  //时
   
   dat[7]=date_time[0]/10 ; //十时
   
   
}
void write_164(uint8_t data_164)//写一位数据164
{
uint8_t i;
for(i=0;i<8;i++)
{
  LCK_OFF;
        LCK_ON;
  
  if(data_164&0x01)
  {
   DATA_ON;
  }
  else DATA_OFF;
     data_164=data_164>>1;
     LCK_ON;
}
}

//主程序
int main(void)
{  
    DDRA=0XFF;
DDRB=0XFF;
DDRC=0XFF;
    //CALENDAR_WRITE(12,9,13,10,34,0);  //时间初始化2009年8月6日14时36分
while(1)
{  
    CALENDAR_READ();

    segvalue();
   
//  SEG_DSY();

/*LCK_OFF;
LCK_ON;
DATA_ON;
LCK_OFF;
LCK_ON;
DATA_OFF;
LCK_OFF;
LCK_ON;
DATA_OFF;

LCK_OFF;
LCK_ON;
DATA_ON;

LCK_OFF;
LCK_ON;
DATA_ON;

LCK_OFF;
LCK_ON;
DATA_ON;

LCK_OFF;
LCK_ON;
DATA_ON;

LCK_OFF;
LCK_ON;
DATA_ON;*/
write_164(DSY_d[ dat[7]]);
write_164(DSY_d[ dat[6]]);
write_164(DSY_d[ dat[5]]);
write_164(DSY_d[ dat[4]]);
write_164(DSY_d[ dat[3]]);
write_164(DSY_d[ dat[2]]);
write_164(DSY_d[ dat[1]]);
write_164(DSY_d[ dat[0]]);
delay(6000);

}  
}

分享到:
回复

使用道具 举报

回答|共 3 个

倒序浏览

沙发

小鸟_愤怒

发表于 2012-9-13 14:31:31 | 只看该作者

求助问题最好不要贴大段的代码,把问题描述的更明白,更细致这样也许能更快得到回应。不能指望人家都去验证你的代码,也许有高手正好用过,这种可能性还是很低。所以最好自己把程序Debug一遍碰到具体的不懂之处再求助
静心  简单  认真  专注
板凳

陈克雄

发表于 2012-10-13 23:13:32 | 只看该作者

沙发说得对
地板

小马哈

发表于 2012-10-25 20:24:57 | 只看该作者

问题描述不清楚,无法回答。时钟快,快多少?什么情况下快?外围电路如何接的?电压多少,晶振如何?等等。
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条