View previous topic :: View next topic |
Author |
Message |
HGHK
Joined: 29 Jun 2010 Posts: 33
|
I have Problem to use PCF8563 for RTC and need a driver |
Posted: Tue Sep 14, 2010 10:44 pm |
|
|
I need a driver for PCF8563. I can't read and write in it's register using I2C. I use PIC16F87 for control. Pleas help me in it. thanks. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Sep 15, 2010 9:58 am |
|
|
Before asking for a driver, you should look in the CCS drivers directory
on your computer. CCS has a driver for the pcf8563. Here's the file location:
Quote: |
c:\program files\picc\drivers\pcf8563.c
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Sep 15, 2010 1:52 pm |
|
|
If you don't have the file, then upgrade your compiler.
We are not allowed to post CCS files on the forum.
See this post at the top of the list:
Announcement: CCS Forum Policy and Guidelines
Stop asking me for the driver in PM's. |
|
|
HGHK
Joined: 29 Jun 2010 Posts: 33
|
my driver not work help me! |
Posted: Tue Oct 05, 2010 1:21 am |
|
|
I wrote a driver for PCF8563 and Now It Does not work. Please help me if it have bug.
my driver is it:
PCF8563.c :
Code: |
// PCF8563.C
// Command Set:
// PCF8563_init(void)
// PCF8563_write_byte(int8 address, int8 data)
// PCF8563_read_byte(int8 address)
// bin2bcd(int8 value)
// bcd2bin(char bcd_value)
// PCF8563_set_datetime(date_time_t *dt)
// PCF8563_read_datetime(date_time_t *dt)
// Set_Alarm(int8 AMode,PCF8563_Alarm *AT)
// config_CLKOUT(int8 mode)
// config_PCF8563_Timer(int8 mode)
// config_PCF8563_Interrupt(int8 mode,ti_tp)
#ifndef PCF8563_SDA
#define PCF8563_SDA PIN_C4
#define PCF8563_SCL PIN_C3
#endif
#use i2c(master, sda=PCF8563_SDA, scl=PCF8563_SCL)
#ifndef PCF8563_WRITE_ADDRESS
#define PCF8563_WRITE_ADDRESS 0xA2
#define PCF8563_READ_ADDRESS 0xA3
#endif
// Register addresses
#define PCF8563_CTRL_STATUS_REG1 0x00
#define PCF8563_CTRL_STATUS_REG2 0x01
#define PCF8563_SECONDS_REG 0x02
#define PCF8563_MINUTES_REG 0x03
#define PCF8563_HOURS_REG 0x04
#define PCF8563_DAY_REG 0x05
#define PCF8563_WEEK_REG 0x06
#define PCF8563_MONTH_REG 0x07
#define PCF8563_YEAR_REG 0x08
#define PCF8563_ALARM_MINS_REG 0x09
#define PCF8563_ALARM_HOURS_REG 0x0A
#define PCF8563_ALARM_DAY_REG 0x0B
#define PCF8563_ALARM_WEEKDAY_REG 0x0C
#define PCF8563_CTRL_CLKOUT_REG 0x0D
#define PCF8563_CTRL_TIMER_REG 0x0E
#define PCF8563_TIMER_REG 0x0F
// Commands for the Control/Status register.
#define PCF8563_START_COUNTING 0x08
#define PCF8563_STOP_COUNTING 0x28
//************************************* for Set_Alarm()
#define PCF8563_Alarm_off 0x00
#define PCF8563_M_Mode 0x01
#define PCF8563_MH_Mode 0x04
#define PCF8563_MHW_Mode 0x07
#define PCF8563_MHD_Mode 0x0B
//************************************* for config_CLKOUT()
#define PCF8563_CLKOUT_off 0x00
#define PCF8563_CLKOUT_32KHz 0x80
#define PCF8563_CLKOUT_1KHz 0x81
#define PCF8563_CLKOUT_32Hz 0x82
#define PCF8563_CLKOUT_1Hz 0x83
//************************************* for config_PCF8563_Timer()
#define PCF8563_Timer_off 0x00
#define PCF8563_Timer_4KHz 0x80
#define PCF8563_Timer_64Hz 0x81
#define PCF8563_Timer_1Hz 0x82
#define PCF8563_Timer_1_60Hz 0x83
//************************************* for config_PCF8563_Interrupt()
#define Alarm_Interrupt_Enable 0x01
#define Timer_Interrupt_Enable 0x02
#define A_T_Interrupt_Enable 0x03
#define Timer_INT_Pulse_on 0x10
#define Timer_INT_Pulse_off 0x00
char const weekday_names[7][10] =
{
{"Sunday"},
{"Monday"},
{"Tuesday"},
{"Wednesday"},
{"Thursday"},
{"Friday"},
{"Saturday"}
};
// This structure defines the user's date and time data.
// The values are stored as unsigned integers. The user
// should declare a structure of this type in the application
// program. Then the address of the structure should be
// passed to the PCF8563 read/write functions in this
// driver, whenever you want to talk to the chip.
typedef struct
{
int8 seconds; // 0 to 59
int8 minutes; // 0 to 59
int8 hours; // 0 to 23 (24-hour time)
int8 day; // 1 to 31
int8 weekday; // 0 = Sunday, 1 = Monday, etc.
int8 month; // 1 to 12
int8 year; // 00 to 99
}date_time_t;
typedef struct
{
int8 minutes; // 0 to 59
int8 hours; // 0 to 23 (24-hour time)
int8 day; // 1 to 31
int8 weekday; // 0 = Sunday, 1 = Monday, etc.
}PCF8563_Alarm;
int8 LV_sec,C_Mon;
#bit LowVoltage = LV_sec.7
#bit Century = C_Mon.7
//----------------------------------------------
void PCF8563_write_byte(int8 address, int8 data)
{
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8563_WRITE_ADDRESS);
i2c_write(address);
i2c_write(data);
i2c_stop();
enable_interrupts(GLOBAL);
}
//----------------------------------------------
int8 PCF8563_read_byte(int8 address)
{
int8 retval;
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8563_WRITE_ADDRESS);
i2c_write(address);
i2c_start();
i2c_write(PCF8563_READ_ADDRESS);
retval = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
return(retval);
}
//----------------------------------------------
// PCF8563 Initial //
void PCF8563_init(void)
{
PCF8563_write_byte(PCF8563_CTRL_STATUS_REG1,PCF8563_START_COUNTING);
}
//----------------------------------------------
// This function converts an 8 bit binary value
// to an 8 bit BCD value.
// The input range must be from 0 to 99.
int8 bin2bcd(int8 value)
{
char retval;
retval = 0;
while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(value >= 10)
{
value -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += value;
break;
}
}
return(retval);
}
//----------------------------------------------
// This function converts an 8 bit BCD value to
// an 8 bit binary value.
// The input range must be from 00 to 99.
char bcd2bin(char bcd_value)
{
char temp;
temp = bcd_value;
// Shifting the upper digit right by 1 is
// the same as multiplying it by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;
// Now return: (Tens * 8) + (Tens * 2) + Ones
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
//----------------------------------------------
//----------------------------------------------
void PCF8563_set_datetime(date_time_t *dt)
{
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 bcd_mon;
int8 bcd_yer;
int8 wek;
// Convert the input date/time into BCD values
// that are formatted for the PCF8563 registers.
bcd_sec = bin2bcd(dt->seconds);
bcd_min = bin2bcd(dt->minutes);
bcd_hrs = bin2bcd(dt->hours);
bcd_day = bin2bcd(dt->day) | (dt->year << 6);
bcd_mon = bin2bcd(dt->month) | (dt->weekday << 5);
bcd_yer = bin2bcd(dt->year);
wek = dt->weekday;
// Stop the RTC from counting, before we write to
// the date and time registers.
PCF8563_write_byte(PCF8563_CTRL_STATUS_REG1,PCF8563_STOP_COUNTING);
// Write to the date and time registers. Disable interrupts
// so they can't disrupt the i2c operations.
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8563_WRITE_ADDRESS);
i2c_write(PCF8563_SECONDS_REG); // Start at seconds reg.
i2c_write(bcd_sec);
i2c_write(bcd_min);
i2c_write(bcd_hrs);
i2c_write(bcd_day);
i2c_write(wek);
i2c_write(bcd_mon);
i2c_write(bcd_yer);
i2c_stop();
enable_interrupts(GLOBAL);
// Now allow the PCF8563 to start counting again.
PCF8563_write_byte(PCF8563_CTRL_STATUS_REG1,PCF8563_START_COUNTING);
}
//----------------------------------------------
//----------------------------------------------
// Read the Date and Time from the hardware registers
// in the PCF8563. We don't have to disable counting
// during read operations, because according to the data
// sheet, if any of the lower registers (1 to 7) is read,
// all of them are loaded into "capture" registers.
// All further reading within that cycle is done from
// those registers.
void PCF8563_read_datetime(date_time_t *dt)
{
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 wek;
int8 bcd_mon;
int8 bcd_yer;
// LowVoltage = VL_sec.7
// Century = C_Mon.7
// Disable interrupts so the i2c process is not disrupted.
disable_interrupts(GLOBAL);
// Read the date/time registers inside the PCF8563.
i2c_start();
i2c_write(PCF8563_WRITE_ADDRESS);
i2c_write(PCF8563_SECONDS_REG); // Start at seconds reg.
i2c_start();
i2c_write(PCF8563_READ_ADDRESS);
LV_sec = i2c_read();
bcd_min = i2c_read();
bcd_hrs = i2c_read();
bcd_day = i2c_read();
wek = i2c_read();
C_Mon = i2c_read();
bcd_yer = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
// Convert the date/time values from BCD to
// unsigned 8-bit integers. Unpack the bits
// in the PCF8563 registers where required.
bcd_sec = LV_sec & 0x7F;
bcd_mon = C_Mon & 0x7F;
dt->seconds = bcd2bin(bcd_sec);
dt->minutes = bcd2bin(bcd_min);
dt->hours = bcd2bin(bcd_hrs & 0x3F);
dt->day = bcd2bin(bcd_day & 0x3F);
dt->month = bcd2bin(bcd_mon & 0x1F);
dt->weekday = wek & 0x07;
dt->year = bcd2bin(bcd_yer);
}
//----------------------------------------------
void Set_Alarm(int8 AMode)
{
if (AMode == 0x00)
{
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8563_WRITE_ADDRESS);
i2c_write(PCF8563_ALARM_MINS_REG); // Start at alarm min reg.
i2c_write(0x80);
i2c_write(0x80);
i2c_write(0x80);
i2c_write(0x80);
i2c_stop();
enable_interrupts(GLOBAL);
}
}
void Set_Alarm(int8 AMode,PCF8563_Alarm *AT)
{
int8 min = 0x80;
int8 hrs = 0x80;
int8 day = 0x80;
int8 wek = 0x80;
switch (AMode){
case 0x01: min = AT->minutes;
break;
case 0x04: min = AT->minutes;
hrs = AT->hours;
break;
case 0x07: min = AT->minutes;
hrs = AT->hours;
wek = AT->weekday;
break;
case 0x0B: min = AT->minutes;
hrs = AT->hours;
day = AT->day;
break;
}
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8563_WRITE_ADDRESS);
i2c_write(PCF8563_ALARM_MINS_REG); // Start at alarm min reg.
i2c_write(min);
i2c_write(hrs);
i2c_write(day);
i2c_write(wek);
i2c_stop();
enable_interrupts(GLOBAL);
}
//----------------------------------------------
void config_CLKOUT(int8 mode)
{
PCF8563_write_byte(PCF8563_CTRL_CLKOUT_REG, mode);
}
//----------------------------------------------
void config_PCF8563_Timer(int8 mode)
{
PCF8563_write_byte(PCF8563_CTRL_TIMER_REG, mode);
}
//----------------------------------------------
void config_PCF8563_Interrupt(int8 mode,ti_tp)
{
mode = mode | ti_tp;
PCF8563_write_byte(PCF8563_CTRL_STATUS_REG2, mode);
}
//----------------------------------------------
|
Help me Please, Thanks a lot. |
|
|
asdf85
Joined: 03 Jan 2011 Posts: 34
|
|
Posted: Wed Dec 28, 2011 1:44 am |
|
|
Hi,
How do I use the provided driver?
I do a #include "pcf8563.c" . But when I call this function "rtc_get_datetime();", it says 'A numeric expression must appear here'.
If I simply put a random number or variable in the brackets, then it compiles, but I see no data.
I think I'm calling it wrongly? Basically I just need to know how to use the write and read functions of this driver. I'm not familiar with structures, and I've never included other files in my project before, so I'm kinda clueless on this.
Thanks for the help. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Dec 28, 2011 2:59 am |
|
|
Try reading the text at the top of the driver.
All CCS drivers have a set of comments at the top describing the functions and variables involved (worthwhile practice to follow in general....).
Both rtc_get_datetime, and rtc_set_datetime, need to be called with the _address_ of a TIME_STRUCT structure. The functions then put/get the time into/out of this structure.
Putting a number in here instead of the address means the data will be written to a point in the RAM, defined by the number, and _will_ result in RAM being corrupted.
So you need to declare a TIME_STRUCT variable, and pass it's address to the function.
Best Wishes |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Dec 28, 2011 7:03 am |
|
|
Also be sure to use the correct value pullup resistors on the I2C bus lines !
If running 5V VDD, I use 3k3 resistors. |
|
|
asdf85
Joined: 03 Jan 2011 Posts: 34
|
|
Posted: Wed Dec 28, 2011 7:38 pm |
|
|
I still dont get it and can't get it working. How do i call it with the '_address_ of a TIME_STRUCT structure' ? I tried creating an INT variable and pointing it to that adress, but that doesnt work.
This part is confusing too
Code: |
void rtc_get_datetime(TIME_STRUCT *pTs)
|
How come there's no need for a comma after the 'TIME_STRUCT'? I also dont see the pointer '*pTs' being initialized anywhere.
Could you give an example of how to call this function, with whatever nescessary initialized variable/pointers/address/structure?
And how do i receive the response?
I really am quite blur when it comes to structures.
Thanks alot |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1934 Location: Norman, OK
|
|
Posted: Wed Dec 28, 2011 8:26 pm |
|
|
Take a look at the example file ex_rtctimer.c in the examples directory
and the time.h file in the drivers directory for some info.
Also try here:
http://pdfserv.maxim-ic.com/en/an/AN517.pdf
The struct is called tm_struct. examine all the code to see how it is used further down. _________________ Google and Forum Search are some of your best tools!!!! |
|
|
|