This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

msp430f149 外接时钟芯片PCF8563问题

Other Parts Discussed in Thread: PCF8574, MSP430F149

请问为什么我跑程序后不管是读秒,读分,读时都是0x01,然后就不动了,用的是PCF8563,希望发现问题的朋友给下建议,谢谢!

程序如下
#include "msp430.h"
#define uchar unsigned char
#define uint unsigned int
#define PCF8563_RTC 0xA3 /* 定义器件地址 */
#define SDA_1 P3OUT |= BIT1 //SDA = 1
#define SDA_0 P3OUT &=~ BIT1 //SDA = 0
#define SCL_1 P3OUT |= BIT3 //SCL = 1
#define SCL_0 P3OUT &=~ BIT3 //SCL = 0
#define DIR_IN P3DIR &=~ BIT1 //I/O口为输入
#define DIR_OUT P3DIR |= BIT1 //I/0口为输出
#define SDA_IN ((P3IN >> 6) & 0x01) //Read SDA
//#define SDA_IN (P3IN & 0x01) //Read SDA

#define over_time 255 /*应答超时门限*/
unsigned char sec;
unsigned char min;
unsigned char hour;
unsigned char month;
unsigned char day;
//unsigned char week;
unsigned char year;
void Delay();
void iic_start(void);
void iic_stop(void);
void iic_ack();
void iic_Send_byte(uchar WriteData);
uchar rev(void);
void iic_send_add_byte(uchar add,uchar bat);
uchar iic_rec_add_byte(uchar add);
void time_init();
void pcf_init();
uchar bcd_dec(uchar bat);
void delay_kk(uint k);
uchar sec1,min1,hour1,day1,month1,year1; //PCF8563读出的变量和代转换成的十进制变量
void chushi(void);
void DelayNus(uint n);
void chushi(void)
{
uchar i;
//unsigned char g,s;

//WDTCTL = WDTPW + WDTHOLD; //关狗
/*------选择系统主时钟为8MHz-------*/
BCSCTL1 &= ~XT2OFF; //打开XT2高频晶体振荡器
do
{
IFG1 &= ~OFIFG; //清除晶振失败标志
for (i = 0xFF; i > 0; i--); //等待8MHz晶体起振
}
while ((IFG1 & OFIFG)); //晶振失效标志仍然存在?
BCSCTL2 |= SELM_2 + SELS; //MCLK和SMCLK选择高频晶振
TACTL |= TASSEL_2 + ID_3; //计数时钟选择SMLK=8MHz,1/8分频后为1MHz
}
void main()
{
WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer
chushi();
//uchar sec1,min1,hour1,day1,month1,year1; //PCF8563读出的变量和代转换成的十进制变量
//LCD1602_Init();
iic_send_add_byte(0x00,0x20); // 关闭时钟
//delay_kk(1000);
DelayNus(6);
time_init(); //时钟芯片初始时间设置
pcf_init();
DelayNus(6);
//delay_kk(1000);
while(1)
{
sec=0x7f&iic_rec_add_byte(0x02); //读取秒
min=0x7f&iic_rec_add_byte(0x03); //读取分钟
hour=0x3f&iic_rec_add_byte(0x04); //读取小时
day=0x3f&iic_rec_add_byte(0x05); //读取天数
month=0x1f&iic_rec_add_byte(0x07); //读取月
year=0xff&iic_rec_add_byte(0x08); //读取年
sec1=bcd_dec(sec); //将读取的BCD码秒转换成十进制秒以便运算
min1=bcd_dec(min);
hour1=bcd_dec(hour);
day1=bcd_dec(day);
month1=bcd_dec(month);
year1=bcd_dec(year);
//display_time(sec1,min1,hour1,dat1,moom1,year1); //LCD1602显示时间
}
}

/*******************************************
函数名称:DelayNus
功 能:实现N个微秒的延时
参 数:n--延时长度
返回值 :无
说明 :定时器A的计数时钟是1MHz,CPU主频8MHz
所以通过定时器延时能够得到极为精确的
us级延时
********************************************/
void DelayNus(uint n)
{
CCR0 = n;
TACTL |= MC_1; //增计数到CCR0
while(!(TACTL & BIT0)); //等待
TACTL &= ~MC_1; //停止计数
TACTL &= ~BIT0; //清除中断标志
}

//-----------延时用于稳定-------------
void delay_kk(uint k)
{
while(k--);
}

void Delay() //略微延时 6us约>4.7us
{
_NOP();
_NOP();
_NOP();
_NOP();
_NOP();
_NOP();
}


/**--------------------------------------------------------------------------------
调用方式:void Start(void) ﹫2002/01/2 40 4
函数说明:私有函数,I2C专用,起始条件函数
数据线下降沿而时钟线为高电平时为起始条件
---------------------------------------------------------------------------------*/
void iic_start(void)
{
DIR_OUT;
SDA_1;
SCL_1;
DelayNus(6); //INI
SDA_0;
DelayNus(6); //START
SCL_0;

}


/**--------------------------------------------------------------------------------
调用方式:void Stop(void) ﹫2001/07/0 4
函数说明:私有函数,I2C专用,结束条件函数
数据线上降沿而时钟线为高电平时为结束条件
---------------------------------------------------------------------------------*/
void iic_stop(void)
{
DIR_OUT;
SCL_0;
SDA_0;
DelayNus(6);
SCL_1;
DelayNus(6); //INI
SDA_1; //STOP
DelayNus(6);
}

void iic_ack() //应答信号
{

/*DIR_OUT; //把P3.3设为输出
SDA_1;
SCL_0;
DelayNus(6);
SDA_0; //置SDA为高电平 发出应答信号
DelayNus(6); //时钟低电平周期大于4μs
SCL_1;
DelayNus(6);
SCL_0; //清时钟线,钳住I2C总线以便继续接收
DelayNus(6);
SDA_1;*/
uchar i=0;
SCL_1;
DelayNus(6);
while((P3OUT==BIT1)&&(i<255))
i++;
SCL_0;
DelayNus(6);
}

/**--------------------------------------------------------------------------------
调用方式:Sendbyte(unsigned char WriteData) ﹫2001/07/0 5
函数说明:私有函数,I2C专用,发送一字节
---------------------------------------------------------------------------------*/
void iic_Send_byte(uchar WriteData)
{
unsigned char i;
for (i=0; i<8; i++)
{

DIR_OUT; //把P3.1设为输出
if (((WriteData >> 7) & 0x01) == 0x01) //输出8位到RTC
{
SDA_1;
}
else
{
SDA_0;
}
DelayNus(6);
SCL_1; //时钟高电平
WriteData = WriteData << 1; //待发数据左移一位
DelayNus(6); //保证时钟高电平周期大于4μs
SCL_0; //时钟置为低电平,发送一位
DelayNus(6);
}

DIR_IN; //把P3.3设为输入
DelayNus(6);
SCL_0; //置时钟为低电平
DelayNus(6);
}

uchar rev(void)
{
//unsigned errtime=over_time; /*因故障接收方无ACK,超时值为255。*/
SDA_1; //置高数据线 准备接收应答位
DelayNus(6); //时钟低电平周期大于4μs
SCL_1;
DelayNus(6);
DIR_IN; //把P3.3设为输入

//while (SDA_IN == 0x01) /*此语句可有可无*/
//{
// errtime--;
//if (!errtime)
// {
// Stop();
// return 0x00;
// }
//}*/

SCL_0;
DelayNus(6);
return(0x01); //返回应答信号
}

void iic_send_add_byte(uchar add,uchar bat) //向某个地址发送某数据
{
iic_start();
iic_Send_byte(0xa3);
iic_ack();
iic_Send_byte(add);
iic_ack();
iic_Send_byte(bat);
iic_ack();
iic_stop();
}


uchar iic_rec_add_byte(uchar add) //从某个地址读出数据
{
uchar temp;
iic_start();
iic_Send_byte(0xa2);
iic_ack();
iic_Send_byte(add);
iic_ack();
iic_start();
iic_Send_byte(0xa3);
iic_ack();
temp=rev();
iic_stop();
return temp;
}

//-----------时间预设定值---------
void time_init()
{
iic_send_add_byte(0x02,0x50); //0秒
iic_send_add_byte(0x03,0x59); //0分钟
iic_send_add_byte(0x04,0x23); //0小时
iic_send_add_byte(0x05,0x26); //26号
iic_send_add_byte(0x07,0x05); //5月 20世纪的
iic_send_add_byte(0x08,0x14); //2014年
}

//----------------PCF8563初始化-----------------
void pcf_init()
{
iic_send_add_byte(0x00,0x00); //启动时钟
}


//----------------BCD转10进制-----------
uchar bcd_dec(uchar bat)
{
uchar temp1,temp2,tol;
temp1=bat&0x0f;
temp2=(bat&0xf0)>>4;
tol=temp2*10+temp1;
return tol;
}

  • 您可以在 www.ti.com/.../slaa443.pdf 下载例程参考一下

    fet140_i2c_02.c I2C, Master Interface to PCF8574, Read/Write
  • 您好,我也参考过这个例程,但我用的是msp430f149  ,可是这里面一些关于I2C的宏定义用不了,只能在MSP430x15x和 MSP430x16x 里能用。

  • 这种问题一般是时序问题,建议先用逻辑分析仪或者带存储的示波器观察一下时序

  • 您好,现在可以可以读秒 读分钟了,但是读到的秒不是从0开始的,是从80多开始往0度,初始的分钟也是85,秒跟分钟不是0~59BCD码吗,为什么会出现80多,我检查了一下读写程序,没发现什么错误,您遇见过这种情况吗?程序如下:


    #include "msp430.h"

    #define PCF8563_RTC 0xA2 /* 定义器件地址 */
    #define SDA_1 P3OUT |= BIT1 //SDA = 1
    #define SDA_0 P3OUT &=~ BIT1 //SDA = 0
    #define SCL_1 P3OUT |= BIT3 //SCL = 1
    #define SCL_0 P3OUT &=~ BIT3 //SCL = 0
    #define DIR_IN P3DIR &=~ BIT1 //I/O口为输入
    #define DIR_OUT P3DIR |= BIT1 //I/0口为输出
    #define SDA_IN ((P3IN >> 1) & 0x01) //Read SDA

    #define over_time 255 /*应答超时门限*/

    unsigned char Seconds;
    unsigned char Minutes;
    unsigned char hour;
    unsigned char month;
    unsigned char day;
    unsigned char week;
    unsigned char year;
    unsigned char shiwei;
    unsigned char Seconds1;
    unsigned char Minutes1;
    unsigned char hour1;
    unsigned char month1;
    unsigned char day1;
    unsigned char week1;
    unsigned char year1;
    unsigned char shiwei1;
    unsigned char temp1;
    unsigned char temp2;
    unsigned int tol;


    /****************************************************************************
    * 名称:Sys_Ini()
    * 功能:系统初始化
    * 入口参数:无
    * 出口参数:无
    ****************************************************************************/
    void Sys_Ini(void)
    {
    unsigned int i;
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT


    BCSCTL1 &= ~XT2OFF; // XT2on
    do
    {
    IFG1 &= ~OFIFG; // Clear OSCFault flag
    for (i = 0xFF; i > 0; i--); // Time for flag to set
    }
    while ((IFG1 & OFIFG)); // OSCFault flag still set?
    BCSCTL2 |= SELM_2 + SELS + DIVS_3;// MCLK/8 = SMCLK = XT2/8 (safe)


    P3DIR |= 0xff; // P4 output
    //P5DIR |= 0x0f;

    }

    /****************************************************************************
    * 名称:Delay1us()
    * 功能:us单位的延时函数
    * 入口参数:us
    * 出口参数:无
    ****************************************************************************/
    void Delay1us(unsigned char us)
    {
    unsigned char i;
    while (us)
    {
    for(i=0;i<20;i++)
    ;
    --us;
    }
    }
    /****************************************************************************
    * 名称:DelayMS()
    * 功能:ms级单位的延时函数
    * 入口参数:dly
    * 出口参数:无
    ****************************************************************************/
    void DelayMS(unsigned int dly)//延时1ms
    { unsigned int i;

    for(; dly>0; dly--)
    for(i=0; i<1135; i++);
    }

    /*********************************************************************************
    * 名称:Delay()
    * 功能:短软件延时
    * 入口参数:n 延时参数 : 1us
    * 出口参数:无
    **********************************************************************************/
    void Delay(unsigned int n)
    {
    unsigned int i;
    for (i=0; i<n;i++);
    }

    /**--------------------------------------------------------------------------------
    调用方式:void Init(void) ﹫2002/01/2 40 4
    函数说明:私有函数,I2C专用,I2C初始化函数
    ---------------------------------------------------------------------------------*/
    void Init(void)
    {
    SDA_1; //拉高数据线
    Delay(5);
    SCL_1; //时钟保持高电平
    Delay(5);
    }

    /**--------------------------------------------------------------------------------
    调用方式:void Start(void) ﹫2002/01/2 40 4
    函数说明:私有函数,I2C专用,起始条件函数
    数据线下降沿而时钟线为高电平时为起始条件
    ---------------------------------------------------------------------------------*/
    void Start(void)
    {
    DIR_OUT;
    SDA_1;
    SCL_1;
    Delay(5); //INI
    SDA_0;
    Delay(5); //START
    SCL_0;

    }
    /**------------------------------------------------------------------------------*/

    /**--------------------------------------------------------------------------------
    调用方式:void Stop(void) ﹫2001/07/0 4
    函数说明:私有函数,I2C专用,结束条件函数
    数据线上降沿而时钟线为高电平时为结束条件
    ---------------------------------------------------------------------------------*/
    void Stop(void)
    {
    DIR_OUT;
    SCL_0;
    SDA_0;
    Delay(5);
    SCL_1;
    Delay(5); //INI
    SDA_1; //STOP
    Delay(5);
    }

    /**--------------------------------------------------------------------------------
    调用方式:SendByte(unsigned char WriteData) ﹫2001/07/0 5
    函数说明:私有函数,I2C专用,发送一字节
    ---------------------------------------------------------------------------------*/
    void SendByte(unsigned char WriteData)
    {
    unsigned char i;
    for (i=0; i<8; i++)
    {

    DIR_OUT; //把P4.7设为输出
    if (((WriteData >> 7) & 0x01) == 0x01) //输出8位到RTC
    {
    SDA_1;
    }
    else
    {
    SDA_0;
    }
    Delay(5);
    SCL_1; //时钟高电平
    WriteData = WriteData << 1; //待发数据左移一位
    Delay(5); //保证时钟高电平周期大于4μs
    SCL_0; //时钟置为低电平,发送一位
    Delay(5);
    }

    DIR_IN; //把P4.7设为输入
    Delay(5);
    SCL_0; //置时钟为低电平
    Delay(5);
    }

    /**--------------------------------------------------------------------------------
    调用方式:unsigned char ReadByte(void) ﹫2001/07/0 5
    函数说明:私有函数,I2C专用,接收一字节
    ---------------------------------------------------------------------------------*/
    unsigned char ReceiveByte(void)
    {
    unsigned char i;
    unsigned char TempBit = 0;
    unsigned char TempData = 0;
    SDA_1; //拉高数据线
    Delay(5);
    DIR_IN; //把P4.7设为输入
    for (i=0; i<8; i++) //主机接收8位
    {
    SCL_1; //置时钟为高电平
    Delay(5); //时钟低电平周期大于4.7μs

    if (SDA_IN == 0x01 ) //判断输入最低位是否为1
    {
    TempBit = 1;
    }
    else
    {
    TempBit = 0;
    }

    TempData = (TempData << 1) | TempBit; //数据左移一位且接收1位数据
    SCL_0; // 置时钟为低电平
    Delay(5);
    }

    DIR_OUT; //把P4.7设为输出
    return(TempData); //返回接收的数据
    }
    /**--------------------------------------------------------------------------------
    调用方式:unsigned char ReceiveAck(void) ﹫2001/07/0 4
    函数说明:私有函数,I2C专用,等待从器件接收方的应答
    ---------------------------------------------------------------------------------*/
    unsigned char ReceiveAck(void)
    {
    //unsigned errtime=over_time; /*因故障接收方无ACK,超时值为255。*/
    SDA_1; //置高数据线 准备接收应答位
    Delay(5); //时钟低电平周期大于4μs
    SCL_1;
    Delay(5);
    DIR_IN; //把P4.7设为输入

    //while (SDA_IN == 0x01) /*此语句可有可无*/
    //{
    // errtime--;
    //if (!errtime)
    // {
    // Stop();
    // return 0x00;
    // }
    //}*/

    SCL_0;
    Delay(5);
    return(0x01); //返回应答信号
    }


    /**--------------------------------------------------------------------------------
    调用方式:void Acknowledge(void) ﹫2001/07/0 4
    函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,应答信号。
    --------------------------------------------------------------------------------*/
    void Acknowledge(void)
    {
    DIR_OUT; //把P4.7设为输出
    SDA_1;
    SCL_0;
    Delay(5);
    SDA_0; //置SDA为高电平 发出应答信号
    Delay(5); //时钟低电平周期大于4μs
    SCL_1;
    Delay(5);
    SCL_0; //清时钟线,钳住I2C总线以便继续接收
    Delay(5);
    SDA_1;
    }

    /**--------------------------------------------------------------------------------
    调用方式:void Acknowledge(void) ﹫2001/07/0 4
    函数说明:私有函数,I2C专用,主器件为接收方,从器件为发送方时,非应答信号(拒绝应答)。
    --------------------------------------------------------------------------------*/
    void NAcknowledge(void)
    {
    DIR_OUT; //把P4.7设为输出
    SDA_0;
    SCL_0;
    Delay(5);
    SDA_1; //置SDA为高电平 发出应答信号
    Delay(5);
    SCL_1;
    Delay(5); //时钟低电平周期大于4μs
    SCL_0; //清时钟线,钳住I2C总线以便继续接收
    Delay(5);
    SDA_0;
    }

    /*******************************************************************
    向有子地址器件发送1字节数据函数
    函数原型: unsigned char ReadByte(unsigned char dev_address,unsigned char sub_address);
    功能: 从启动总线到发送地址,子地址,结束总线的全过程,从器件
    地址dev_address,子地址sub_address.
    如果返回1表示操作成功,否则操作有误。
    注意: 使用前必须已结束总线。
    ********************************************************************/
    unsigned char ReadByte(unsigned char dev_address/*dev_address*/,unsigned char sub_address/*sub_address*/)
    {
    unsigned char RecData = 0;
    Start(); //启动总线
    SendByte(dev_address); //发送器件地址
    ReceiveAck();
    SendByte(sub_address); //发送器件子地址
    ReceiveAck();
    Delay(100);
    Start(); //重新启动总线
    SendByte(dev_address + 0x01);
    ReceiveAck();
    RecData = ReceiveByte();
    NAcknowledge();
    Stop(); //结束总线
    return(RecData);
    }

    /*******************************************************************
    向有子地址器件读取1字节数据函数
    函数原型: unsigned char WriteByte(unsigned char dev_address,unsigned char sub_address, unsigned char sendData);
    功能: 从启动总线到发送地址,子地址,结束总线的全过程,从器件
    地址sla,子地址suba.
    如果返回1表示操作成功,否则操作有误。
    注意: 使用前必须已结束总线。
    ********************************************************************/
    unsigned char WriteByte(unsigned char dev_address,unsigned char sub_address, unsigned char sendData)
    {
    Start(); //启动总线
    SendByte(dev_address); //发送器件地址
    if(ReceiveAck()==0x01) //判断是否出错
    {
    SendByte(sub_address); //发送器件子地址
    if(ReceiveAck()==0x01) //判断是否出错
    {
    SendByte(sendData); //发送数据
    if(ReceiveAck()==0x01) //判断是否出错
    {
    Stop(); //结束总线
    return(0x01);
    }
    else
    {
    Stop(); //结束总线
    return(0x00);
    }
    }
    else
    {
    Stop();
    return(0x00);
    }
    }
    else
    {
    Stop();
    return(0x00);
    }
    }

    /****************************************************************************
    * 名称:DelayNS()
    * 功能:长软件延时 调试时用
    * 入口参数:dly 延时参数 : 1ms
    * 出口参数:无
    ****************************************************************************/
    void DelayNS(unsigned int dly)
    { unsigned int i,j;

    for(j=0; j<=dly; j++)
    {
    for(i=0; i<1135; i++);
    }
    }

    /********************************************************************************
    *函数名: Rtc_ReadTime()
    *参数: 无
    *返回值: true(OK);false(ERROR)
    *描述: 从Rtc读取时间
    *编写: bobo.li
    *版本信息:
    ********************************************************************************/
    void Rtc_ReadTime(void)
    {
    Seconds = ReadByte(PCF8563_RTC,0x02)&0x7f; //读秒

    Minutes = ReadByte(PCF8563_RTC,0x03)&0x7f; //读分

    hour = ReadByte(PCF8563_RTC,0x04)&0x3f; //读时

    day= ReadByte(PCF8563_RTC,0x05)&0x3f; //读天

    week= ReadByte(PCF8563_RTC,0x06)&0x07; //读周

    month = ReadByte(PCF8563_RTC,0x07)&0x1f; //读月

    year = ReadByte(PCF8563_RTC,0x08); //读年

    }
    //----------------BCD转10进制-----------
    unsigned char bcd_dec(unsigned char bat)
    {
    /*unsigned char temp1,temp2,tol;*/
    temp1=bat&0x0f;
    temp2=(bat&0xf0)>>4;
    tol=temp2*10+temp1;
    return tol;
    }

    void main (void)
    {

    shiwei=0x00;
    Sys_Ini();
    Init();
    WriteByte(PCF8563_RTC,0x02, 0x00); //秒的初始值

    WriteByte(PCF8563_RTC,0x03, 0x00); //分的初始值

    WriteByte(PCF8563_RTC,0x04, 0x00); //时的初始值

    WriteByte(PCF8563_RTC,0x05, 0x00); //天的初始值

    WriteByte(PCF8563_RTC,0x06, 0x00); //周的初始值

    WriteByte(PCF8563_RTC,0x07, 0x00); //月的初始值

    WriteByte(PCF8563_RTC,0x08, 0x00); //年的初始值
    while(1)
    {
    Rtc_ReadTime();
    Seconds1=bcd_dec(Seconds);
    Minutes1=bcd_dec(Minutes);
    hour1=bcd_dec(hour);
    month1= bcd_dec(month);
    day1=bcd_dec(day);
    week1=bcd_dec(week);
    year1=bcd_dec(year);
    //shiwei1=bcd_dec(shiwei);
    }
    }