对于DS1302的调试,经常遇到不能起振的问题,不能确定是硬件问题还是软件问题。
下面是我的调试步骤:
1.读写DS1302内部的RAM区域。即使32.768kHZ晶体没有起振,也可以读写RAM内容。
确定写的软件是否正确。
2.秒寄存器最高位,晶体是否起振位CH设置为0,打开32.768kHz振荡器,此时振荡器起振。
可以使用示波器测试clk输出X2,
3.在写寄存器之前,关闭写保护。
这三条满足,90%会起振。
4.DS1302需要的晶体是32.768KHz,等效串联电阻为45K欧姆,负载电容6pF.如果负载电容是12.5pF等其他值也能起振,
只是计算时间不太准确而已!
总结:
硬件起最复杂的地方开始,最复杂的解决了,其他的迎刃而解!擒贼先擒王。
软件起最简单的开始,逐渐缩小包围圈,分而治之。
DS1302 IAR AVR代码
/*---------------------------------------------------------------------------------
RTC inte
RFace
-----------------------------------------------------------------------------------*/
#define RTC_CE PORTD_PORTD3
#define RTC_IO PORTC_PORTC0
#define RTC_CLK PORTC_PORTC1
#define RTC_CE_DDR DDRD_DDD3
#define RTC_IO_DDR DDRC_DDC0
#define RTC_CLK_DDR DDRC_DDC1
#define RTC_IO_PIN PINC_PINC0
/****************************
初始化RTC 接口
*****************************/
void init_rtc(void)
{
RTC_CE=0;
RTC_IO=0;
RTC_CLK=0;
RTC_CE_DDR=SET_PIN_OUT;
RTC_IO_DDR=SET_PIN_OUT;
RTC_CLK_DDR=SET_PIN_OUT;
}
/*****************************
softTWI应用程序接口
******************************/
void stwi_delay(void)
{
__delay_cycles(5);
}
//总线上起动停止条件
void stwi_stop(void)
{
RTC_CLK=0;
stwi_delay();
RTC_CE=0;
stwi_delay();
}
//总线上起动开始条件
void stwi_start(void)
{
RTC_CLK=0;
stwi_delay();
RTC_CE=1;
stwi_delay();
}
//写一字节
void stwi_writebyte(UINT8 c)
{
UINT8 i;
for(i=0;i<8;i++)
{
if(c&0x01)
{
RTC_IO=1;
}
else
{
RTC_IO=0;
}
c>>=1;
stwi_delay();
RTC_CLK=1;//送出状态
stwi_delay();
RTC_CLK=0;//SCL处于低电平时,SDA才能改变
stwi_delay();
}
}
//读一字节 ack: true 时发ACK,false 时发NACK
void stwi_readbyte(UINT8 *c )
{
UINT8 i;
UINT8 read_data = 0x00;
RTC_IO_DDR=SET_PIN_IN;
for(i=0;i<8;i++)
{
read_data>>=1;
if(RTC_IO_PIN)
read_data|=0x80;
RTC_CLK=1;
stwi_delay();
RTC_CLK=0;
stwi_delay();
}
RTC_IO_DDR=SET_PIN_OUT;
*c=read_data;
}
/*------------------------------------------------------
RTC
-------------------------------------------------------*/
#define RTC_ADDR_SEC (0x80|(0<<1)) /**/
#define RTC_ADDR_MIN (0x80|(1<<1)) /*minute*/
#define RTC_ADDR_HOUR (0x80|(2<<1)) /**/
#define RTC_ADDR_DAY (0x80|(3<<1)) /**/
#define RTC_ADDR_MON (0x80|(4<<1)) /**/
#define RTC_ADDR_WEEK (0x80|(5<<1)) /**/
#define RTC_ADDR_YEAR (0x80|(6<<1)) /**/
#define RTC_ADDR_CTRL (0x80|(7<<1)) /**/
#define RTC_ADDR_CHG (0x80|(8<<1)) /**/
#define RTC_ADDR_MCLK (0x80|(0x1f<<1)) /**/
#define RTC_ADDR_RAM0 (0xc0|(0<<1)) /**/
#define RTC_ADDR_MRAM 0xfe /**/
/*------------------------------------------------------
RTC
-------------------------------------------------------*/
//对RTC连续的写操作
UINT8 rtc_write(UINT8 addr,UINT8 *buf,UINT8 len)
{
UINT8 i;
stwi_start();
stwi_writebyte(addr|TW_WRITE);
for(i=0;i<len;i++)
stwi_writebyte(buf[i]);
stwi_stop();
return 0;
}
//对RTC连续的读操作
UINT8 rtc_read(UINT8 addr,UINT8 *buf,UINT8 len)
{
UINT8 i;
UINT8* p=buf;
stwi_start();
stwi_writebyte(addr|TW_READ);
for(i=0;i<len-1;i++)
{
stwi_readbyte(p++);
}
stwi_readbyte(p);
stwi_stop();
return 0;
}
#ifdef DEBUG_TEST_FUNCTION
void test_rtc(void)
{
UINT8 rtc_buf[40]={0};
UINT8 uc;
UINT8 i;
UINT8 *p;
uc=0;
rtc_write(RTC_ADDR_CTRL,&uc,1);
uc=0x00;
rtc_write(RTC_ADDR_SEC,&uc,1);
p=rtc_buf;
rtc_read(RTC_ADDR_MCLK,p,8);
p=rtc_buf+8;
rtc_read(RTC_ADDR_CHG,p,1);
p=rtc_buf+9;
rtc_read(RTC_ADDR_MRAM,p,31);
for(i=0;i<40;i++)
{
printf("\r\nrtc_buf[%d]=0x%x",i,rtc_buf[i]);
}
while(1)
{
}
}
#endif