You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PIC16F1789与PCF8523T通信异常:I2C读取RTC始终返回0

问题描述

我正在实现PIC16F1789与PCF8523T RTC模块的通信,已花费数小时排查错误,确认RTC模块工作正常,但调用PCF8523_Read读取数据时始终返回0,无法定位问题原因。以下是相关代码文件与电路原理图:

main.c

#include <xc.h>
#include <stdbool.h>
#include "LCD.h"
#include "I2C.h"
#include "PCF8523.h"
#define _XTAL_FREQ  20000000

#pragma config FOSC = HS        // 振荡器选择位(HS振荡器)
#pragma config WDTE = OFF       // 看门狗定时器使能位(WDT禁用)
#pragma config PWRTE = ON       // 上电定时器使能位(PWRT启用)
#pragma config BOREN = OFF      // 欠压复位使能位(BOR禁用)
#pragma config LVP = OFF        // 低压(单电源)在线串行编程使能位(RB3为数字I/O,编程需使用MCLR引脚高压)
#pragma config CPD = OFF        // 数据EEPROM存储器代码保护位(数据EEPROM代码保护关闭)
#pragma config WRT = OFF        // 闪存程序存储器写使能位(写保护关闭;所有程序存储器可通过EECON控制写入)
#pragma config CP = OFF         // 闪存程序存储器代码保护位(代码保护关闭)

void __interrupt() InterruptServiceRoutine()
{
    if(PIR1bits.RCIF && PIE1bits.RCIE)
    {
        PIR1bits.RCIF = 0;
    }
}

void delay_s(unsigned int numseconds) 
{
    do 
    {
        __delay_ms(1000);
    } while (--numseconds != 0);
}

void main(void) {
    // -- 引脚I/O配置
    TRISB0 = 1; // 引脚B0为输入(LCD切换按钮)
    TRISB1 = 0; // 引脚B1为输出(蓝色LED;-> 水泵运行/阀门打开指示灯)(接入J2)
    TRISB2 = 0; // 引脚B2为输出(红色LED;-> 低水位指示灯/阀门无水流)(接入J2)
    TRISB4 = 0; // 引脚B4为输出(阀门)(接入J1)
    TRISC5 = 0; // 引脚C5为输出(LCD开关)
    
    // -- 变量定义
    bool Lcd_Enabled = true;    // 当前始终为true(忽略)
    unsigned char msg[] = "Hochbeet (--/--)";
    unsigned char Time[] = "UHRZEIT: --:--";
    unsigned char Min,Hour,Day,Month;
    
    unsigned char SetHour = 9;
    unsigned char SetMin = 15;  // 自动浇水系统触发时间
    
    RC5 = 0;
    RB2 = 0;
    
    I2C_Init();
    
    PCF8523_Init();
    Lcd_Init();
    Lcd_Write_Text(msg);
    Lcd_Cmd(LCD_SECOND_ROW);
    Lcd_Write_Text(Time);
    
    while (1) 
    {
        Min = PCF8523_Read(MINUTES);    // 这些值始终返回0???
        Hour = PCF8523_Read(HOURS);
        Day = PCF8523_Read(DAYS);
        Month = PCF8523_Read(MONTHS);
        
        if (Lcd_Enabled == true) 
        {
            Lcd_Cmd(LCD_FIRST_ROW + 10);
            Lcd_Write(BCD2UpperCh(Day));
            Lcd_Write(BCD2LowerCh(Day));
            Lcd_Write('/');
            Lcd_Write(BCD2UpperCh(Month));
            Lcd_Write(BCD2LowerCh(Month));
            Lcd_Write(')');
            
            Lcd_Cmd(LCD_SECOND_ROW + 9);
            Lcd_Write(BCD2UpperCh(Hour));
            Lcd_Write(BCD2LowerCh(Hour));
            Lcd_Write(':');
            Lcd_Write(BCD2UpperCh(Min));
            Lcd_Write(BCD2LowerCh(Min));
        }
        
        if(RB0) 
        {
            if (Lcd_Enabled == false) {
                Lcd_Enabled = true;
                RC5 = 1;
                Lcd_Init();
                Lcd_Write(msg);
                Lcd_Cmd(LCD_SECOND_ROW);
                Lcd_Write(Time);
            }
        }
        else if (Hour == SetHour && Min == SetMin) 
        {
            RB4 = 1;
            RB1 = 1;
            if (Lcd_Enabled == true) 
            {
                Lcd_Cmd(LCD_SECOND_ROW);
                Lcd_Write("Wasser ist an!");
            }
            delay_s(60); // 浇水1分钟
            RB4 = 0;
            RB1 = 0;
            if (Lcd_Enabled == true) 
            {
                Lcd_Cmd(LCD_SECOND_ROW);
                Lcd_Write(Time);
            }
            delay_s(3);
        }
        else 
        {
            __delay_ms(500);
            
        }
    }
}

PCF8523.h

#ifndef PC8523_H
#define PC8523_H

#define     PC8523_ADDRESS  0xD0
#define     CONTROL_1       0x00
#define     CONTROL_2       0x01
#define     CONTROL_3       0x02
#define     SECONDS         0x03    // 未使用
#define     MINUTES         0x04
#define     HOURS           0x05
#define     DAYS            0x06
#define     WEEKDAYS        0x07
#define     MONTHS          0x08
#define     YEARS           0x09    // 未使用
#define     MINUTE_ALARM    0x0A
#define     HOUR_ALARM      0x0B
#define     DAY_ALARAM      0x0C
#define     WEEKDAY_ALARM   0x0D
#define     OFFSET          0x0E
#define     TMR_CLKOUT_CTRL 0x0F
#define     TMR_A_FREQ_CTRL 0x10
#define     TMR_A_REG       0x11
#define     TMR_B_FREQ_CTRL 0x12
#define     TMR_B_REG       0x13

void PCF8523_Init(void);
void PCF8523_SetTimeDate(unsigned char hours,unsigned char minutes,unsigned char seconds,unsigned char day,unsigned char month,unsigned char year);
void PCF8523_SetTime(unsigned char hours,unsigned char minutes,unsigned char seconds);
void PCF8523_SetDate(unsigned char day,unsigned char month,unsigned char years);
unsigned char PCF8523_Read(unsigned char Address);
unsigned char BCD2UpperCh(unsigned char bcd);
unsigned char BCD2LowerCh(unsigned char bcd);

#endif  /* PC8523_H */

PCF8523.c

#include <xc.h>
#include "PCF8523.h"
#include "I2C.h"

void PCF8523_Init(void)
{
    I2C_Init();
}
void PCF8523_SetTimeDate(unsigned char hours,unsigned char minutes,unsigned char seconds,unsigned char day,unsigned char month,unsigned char year)
{
    PCF8523_SetTime(hours,minutes,seconds);
    PCF8523_SetDate(day,month,year);
}
void PCF8523_SetTime(unsigned char hours,unsigned char minutes,unsigned char seconds)
{
    I2C_Start();
    I2C_Send(PC8523_ADDRESS);
    I2C_Send(SECONDS);
    I2C_Send(seconds);
    I2C_Send(minutes);
    I2C_Send(hours);
    I2C_Stop();
}
void PCF8523_SetDate(unsigned char day,unsigned char month,unsigned char years)
{
    I2C_Start();
    I2C_Send(PC8523_ADDRESS);
    I2C_Send(DAYS);
    I2C_Send(day);
    I2C_Send(0x00);
    I2C_Send(month);
    I2C_Send(years);
    I2C_Stop();
}
unsigned char PCF8523_Read(unsigned char Address)
{
    unsigned char temp;
    I2C_Start();
    I2C_Send(PC8523_ADDRESS);
    I2C_Send(Address);
    I2C_Restart();
    I2C_Send(PC8523_ADDRESS+1);
    temp = I2C_Read();
    I2C_Stop();
    return temp;
}
unsigned char BCD2UpperCh(unsigned char bcd)
{
    unsigned char temp;
    temp = bcd >> 4;
    temp = temp | 0x30;
    return(temp);
}
unsigned char BCD2LowerCh(unsigned char bcd)
{
    unsigned char temp;
    temp = bcd & 0x0F; // 保留低4位
    temp = temp | 0x30;
    return(temp);
}

I2C.h

#ifndef I2C_H
#define I2C_H

#define i2c_init        I2C_Init
#define I2C_init        I2C_Init
#define I2c_init        I2C_Init
#define i2c_init        I2C_Init

#define I2c_Start       I2C_Start
#define I2C_start       I2C_Start
#define I2c_start       I2C_Start
#define i2c_start       I2C_Start

#define I2c_Restart     I2C_Restart
#define I2C_restart     I2C_Restart
#define I2c_restart     I2C_Restart
#define i2c_restart     I2C_Restart

#define I2c_Stop        I2C_Stop
#define I2C_stop        I2C_Stop
#define I2c_stop        I2C_Stop
#define i2c_stop        I2C_Stop

#define I2c_Wait        I2C_Wait
#define I2C_wait        I2C_Wait
#define I2c_wait        I2C_Wait
#define i2c_wait        I2C_Wait

#define I2c_Send        I2C_Send
#define I2C_send        I2C_Send
#define I2c_send        I2C_Send
#define i2c_send        I2C_Send

#define I2c_Read        I2C_Read
#define I2C_read        I2C_Read
#define I2c_read        I2C_Read
#define i2c_read        I2C_Read

void I2C_Init(void);
void I2C_Start(void);
void I2C_Restart(void);
void I2C_Stop(void);
void I2C_Wait(void);
void I2C_Send(unsigned char data);
unsigned char I2C_Read(void);


#endif  /* I2C_H */

I2C.c

#include "I2C.h"
#include <xc.h>

void I2C_Init(void)
{
    TRISCbits.TRISC3 = 1;
    TRISCbits.TRISC4 = 1;
    SSPSTAT |= 0x80; // 禁用斜率控制
    SSPADD = 49;

    SSPCON = 0b00101000;            // 主机模式
    SSPADD = 49;
    /*SSPEN = 1
    启用串行端口并将SDA和SCL引脚配置为串行引脚
    SSPM3:SSPM0 --> 1000
    I2C主机模式
    时钟 = Fosc/4*(SSPADD+1)
    */
}
void I2C_Start(void)
{
    SEN = 1;
    //SSPCON2位0
    while (SEN == 1)
        continue;
    //SEN=1在SDA和SCL引脚上启动起始条件
    //由硬件自动清除
    //0表示空闲状态
}
void I2C_Restart(void)
{
    RSEN = 1;
    //SSPCON2位0
    while (RSEN == 1)
        continue;
    //RSEN=1在SDA和SCL引脚上启动重复起始条件
    //由硬件自动清除
    //0表示空闲状态
}
void I2C_Stop(void)
{
    PEN = 1;
    //SSPCON2位0
    while (PEN == 1)
        continue;
    //PEN=1在SDA和SCL引脚上启动停止条件
    //由硬件自动清除
    //0表示空闲状态
}
void I2C_Wait(void)
{
    while( R_nW == 1)
        continue;
    if(ACKSTAT == 1)
    {
        I2C_Stop();
    }
    //如果ACKSTAT位为0则成功收到应答
    //否则未收到
}
void I2C_Send(unsigned char data)
{
    SSPBUF = data;    /* 将数据移入SSPBUF */
    while(BF);       /* 等待数据从缓冲区完全发送 */
    I2C_Wait();       /* 等待任何未完成的传输 */
}
unsigned char I2C_Read(void)
{
    unsigned char temp;
    RCEN = 1;        /* 启用数据接收 */
    while(BF == 0)      /* 等待缓冲区满 */
        continue;
    temp = SSPBUF;   /* 读取串行缓冲区并存入临时寄存器 */
    I2C_Wait();       /* 等待检查任何未完成的传输 */
    ACKDT=1;                // 发送非应答
    ACKEN=1;
    while(ACKEN == 1)
        continue;
    //I2C_Stop();
    return temp;
}

电路原理图

电路原理图

内容的提问来源于stack exchange,提问作者Davide_24

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:06:59