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
相关产品推荐
相关产品推荐

