PCF8583 connected to PIC Microcontroller

Figure 1: PCF8583 connected to PIC Microcontroller

The PIC 18F2620 has a built-in I²C (Inter-Integrated Circuit) bus. I²C is a 2-wire synchronous serial bus. 

Some devices, such as sensors, communicate with microcontrollers on this 2-wire serial bus. Multiple devices, even different types of devices, can be attached to the same 2-wire I²C bus without causing collisions or errors. 
Each device contains a unique address allowing multiple devices attached to the same I²C bus. 
In this example, we will use the PCF8583 real-time clock (RTC) that communicates over I²C to set (write) the time and date and also read from it. Before continuing, be sure to read through the I²C tutorial

The PCF8583 is a small 8-pin clock and calendar chip from NXP Semiconductors with full binary coded decimal (BCD) clock/calendar plus 2048 RAM (256 by 8 RAM memory) that is used in microcontroller based systems to provide real time date and time information.

Data and Addresses are transferred serially through a bidirectional I2C bus. The PCF8583 RTC provides year, month, date, hour, minute and second information. The built-in word address register is incremented automatically after each written or read data byte. Address pin A0 is used for programming the hardware address, allowing the connection of two devices to the bus without additional hardware. The built-in 32.768 kHz oscillator circuit and the first 8 bytes of the RAM are used for the clock, calendar, and counter functions. The next 8 bytes can be programmed as alarm registers or used as free RAM space. The remaining 240 bytes are free RAM locations. 

Features and benefits

  • „I2C-bus interface
  • Clock operating supply voltage 1.0 V to 6.0 V at 0 °C to +70 °C, this can allow a small 3V backup battery to power the chip in case of power failure, thus timekeeping operation can continues. 
  • Operating current (at fSCL = 0 Hz): max 50 μA
  • On chip 256 × 8 RAM memory
  • Clock function with four year calendar
  • 24 hour or 12 hour format
  • Crystal input for accurate timing 
  • Programmable alarm, timer, and interrupt function

PCF8583 RTC Connection

PCF8583 pin configurations

Figure 2: PCF8583 pin configurations

Figure 1 shows how the PCF8583 can be interfaced to a PIC microcontroller. This chip uses I2C protocol to communicate with a PIC, pins SCL and SDA of the RTC must be connected to I2C pins of the microcontroller. Connect two pull up resistors one from the serial clock line and the other from the serial data line to positive power supply.
The higher value of pull up resistor is limited by the rise time and the lower vale of pull up resistor is limited by the drive strength (IOL max) of the SDA and SCL drivers. If the pull up resistor is very low , the bus line might not work. 
Connect an external 32768 crystal to pins 1 and 2 of the PCF8583.  The pin VDD (pin 8) of the PCF8583 (not shown on the circuit) should be connected to +5V and VSS (pin 4) should be connected to ground as well.
A 3V backup battery can also be connected to pin VDD(pin 8) and pin VSS(pin 4) so that date and time information are not lost when power is removed from the chip. You should note the presence of a variable capacitor as well (VC1), this can be used to adjust the accuracy of the timing of the RTC chip. On our circuit, we are using internal oscillator and the MCLR is disabled. If an external oscillator is needed, it can be connected to pins 9 and 10 and if the MCLR is needed, it can be connected to positive supply via a 10K resisitor.

MikroC Pro for PIC provides built-in libraries for I²C devices, the PCF8583 works as a slave device with devices addresses 0xA 1 or 0xA3 for reading, and 0xA0 or 0xA2 for writing on the I²C bus. 

The first 16 bytes of the RAM (memory addresses 00h to 0Fh) are designed as addressable 8 bit parallel special function registers. The first register (memory address 00h) is used as a control and status register. The memory addresses 01h to 07h are used as counters for the clock function. The memory addresses 08h to 0Fh may be programmed as alarm registers or used as free RAM locations, when the alarm is disabled. By setting the alarm enable bit of the control and status register the alarm control register (address 08h) is activated. By setting the alarm control register, a dated alarm, a daily alarm, a weekday alarm, or a timer alarm may be programmed. In the clock modes, the timer register (address 07h) may be programmed to count hundredths of a second, seconds, minutes, hours, or days. Days are counted when an alarm is not programmed.

More details can be found from the PCF8583 Datasheet.                   

There are 2 functions commonly used with this device: set values in memory (writing data to PCF8583) and get values from memory (reading data from PCF8583). 
We will go through both functions.  

The digital values in this device are stored using 4-bit binary-coded decimal (BCD). A conversion from BCD t Binary and Binary to BCD will be needed to properly display and save the values using a PIC. 

Set RTC Values

First thing is to program the IC with the correct values for the calendar and the clocks. 

These are the steps to follow to write new date and time information to the RTC chip:

  • Start I2C bus communication
  • Send address for writing (0xA0)
  • Write seconds
  • Write minutes
  • Write Hours
  • Write day and year
  • Write month
  • Stop I2C bus communication
  • Restart I2C bus communication
  • Send address for writing (0xA0)
  • Start counter
  • Stop I2C bus communication

 Writing to RTC Example

This example writes new date and time to the RTC. As the date and time has to be in BCD format, the ASCII date and time data will be converted to BCD first, we will use the macro ConvertToBCD to achieve that. In this example we also assume the date information is already stored in array Date and time information in array Time and the year information will be stored in address 0 of the EEPROM memory.

#define ConvertToBCD(x,y) (((x-'0') << 4) + y - '0')
I2C1_Init(100000);  //PCF8583 I2C is running at 100KHz
I2C1_Start();           // begin I2C communications
I2C1_Wr(0xA0);      // writing address
I2C1_Wr( 0 );
I2C1_Wr( 0x80 );  
I2C1_Wr( 0 );
I2C1_Wr( ConvertToBCD(Time[6], Time[7])); // write Seconds  
I2C1_Wr( ConvertToBCD(Time[3], Time[4])); // write Minutes
I2C1_Wr( ConvertToBCD(Time[0], Time[1])); // write Hours
year = 10 * (Date[6] - '0'] + Date[7] - '0';
EEPROM_Write(0, year)             // write year to EEPROM adress 0
yr = (year % 4) << 2;
Date[0] = Date[0] + yr;
I2C1_Wr( ConvertToBCD(Date[0], Date[1])); // write Day
I2C1_Wr( ConvertToBCD(Date[3], Date[4])); // write Month
I2C1_Wr(0xA0);      // writing address
I2C1_Wr( 0 );
I2C1_Wr( 0 );          // enable counting

Get RTC Values

These are the steps to follow to read date and time information from the RTC chip:

  • Start I2C bus communication
  • Send address for writing (0xA0)
  • Send address for the second register (0x02)
  • Restart the I2C bus
  • Send address for reading (0xA1)
  • Read seconds
  • Read minutes
  • Read Hours
  • Read day and year
  • Calculate the actual years
  • Read month
  • Stop I2C bus communication

Reading from the RTC Example

In this example, date and time will be read and stored in arrays Date and Time respectively. The date will be stored in this format: dd-mm-yy.

The time will be stored in this format: hh:mm:ss

As RTC date and time information is stored in BCD inside the RTC, we will use macro routines HigherBit and LowerBit to convert the BCD to ASCII format. The year is also stored in EEPROM address 0.

#define HigherBit(x) ((x >>) + '0')
#define LowerBit(x) ((x & 0x0F) + '0')
unsigned char rtc, year, seconds;
I2C1_Start();           // begin I2C communications
I2C1_Wr(0xA0);      // addresses the chip
I2C1_Wr(0x2 );  
I2C1_Start();           // begin I2C communications
I2C1_Wr(0xA1);      // addresses for reading
rtc = I2C1_Rd(1);    // read seconds
Time[6] = HigherBit(rtc);
Time[7] = LowerBit(rtc);
seconds = 10 * (Time[6] -'0') + Time[7]-'0';
new_time = seconds;
rtc = I2C1_Rd(1);     //read minutes
Time[3] = HigherBit(rtc);
Time[4] = LowerBit(rtc);
rtc = I2C1_Rd(1);     //read hours
Time[0] = HigherBit(rtc);
Time[1] = LowerBit(rtc); 
rtc = I2C1_Rd(1);     //read year/day
Date[0] = HigherBit((rtc & 0x30));
Date[1] = LowerBit(rtc);
year = (rtc & 0xC0) >>6;   //Year starts from 2008
rtc = I2C1_Rd(0)     //read weekday/month
Date[3] = HigherBit((rtc & 0x10);
Date[4] =LowerBit(rtc);
I2C1_Stop();               // Stop condition I2C on bus
//Year adjustment in EEPROM
rtc = EEPROM_Read(0)                  //address 0 of EEPROM
if (year ! 0)
Date[6] = (rtc / 10) + '0';
Date[7] = (rtc % 10) + '0';