This topic shows how to make a simple real time clock using DS3231 and PIC16F877A microcontroller where time and date are displayed on 20×4 LCD screen.
The compiler used in this example is CCS C.
General Description (from the DS3231 datasheet):
The DS3231 is a low-cost, extremely accurate I2C real-time clock (RTC) with an integrated temperature compensated crystal oscillator (TCXO) and crystal.
The device incorporates a battery input, and maintains accurate timekeeping when main power to the device is interrupted. The integration of the crystal resonator enhances the long-term accuracy of the device as well as reduces the piece-part count in a manufacturing line.
The DS3231 RTC maintains seconds, minutes, hours, day, date, month, and year information. The date at the end of the month is automatically adjusted for months with fewer than 31 days, including corrections for leap year.
The following image shows a typical operating circuit of the DS3231:
DS3231 RTC driver (library) for CCS C compiler:
Library functions are listed below.
void RTC_Set(RTC_Time *time_t): this function sets time and date (writes time and date to the DS3231) where the variable time_t of type struct (structure) collects the following integer variables:
seconds, minutes, hours, dow, day, month and year.
Where dow is day of the week (Monday, Tuesday …) and day is month day.
seconds and minutes range: 0 – 59
hours range: 0 – 23 (24-hour format)
dow range: 1 – 7 (1 equals Sunday, 2 equals Monday …)
day range: 1 – 31 (depends on month)
month range: 1 – 12 (1 equals January)
year range: 0 – 99.
RTC_Time *RTC_Get(): reads time and date from the DS3231, this function returns them as a variable of type struct (same as the previous function).
void Alarm1_Set(RTC_Time *time_t, al1 _config): sets alarm1 of the DS3231 where the variable time_t of type struct and _config is alarm1 configuration which should be one of the following:
ONCE_PER_SECOND —> alarm every 1 second
SECONDS_MATCH —> alarm when seconds match
MINUTES_SECONDS_MATCH —> alarm when minutes and seconds match
HOURS_MINUTES_SECONDS_MATCH —> alarm when hours, minutes and seconds match
DATE_HOURS_MINUTES_SECONDS_MATCH —> alarm when date (month day), hours, minutes and seconds match
DAY_HOURS_MINUTES_SECONDS_MATCH —> alarm when day (week day), hours, minutes and seconds match.
RTC_Time *Alarm1_Get(): reads time and date of alarm1, this function returns them as a variable of type struct.
void Alarm1_Enable(): enables alarm1 (writes 1 to A1IE bit).
void Alarm1_Disable(): disables alarm1 (writes 0 to A1IE bit).
int1 Alarm1_IF_Check(): returns 1 (TRUE) if alarm1 occurred, otherwise it returns 0 (FALSE).
void Alarm1_IF_Reset(): resets alarm1 flag bit (writes 0 to A1IF bit).
int1 Alarm1_Status(): returns 1 if alarm1 is enabled and 0 if disabled (reads A1IE bit).
void Alarm2_Set(RTC_Time *time_t, al2 _config): sets alarm2 of the DS3231 where the variable time_t of type struct and _config is alarm2 configuration which should be one of the following:
ONCE_PER_MINUTE —> alarm every 1 minute
MINUTES_MATCH —> alarm when minutes match
HOURS_MINUTES_MATCH —> alarm when hours and minutes match
DATE_HOURS_MINUTES_MATCH —> alarm when date (month day), hours and minutes match
DAY_HOURS_MINUTES_MATCH —> alarm when day (week day), hours and minutes match.
RTC_Time *Alarm2_Get(): reads time and date of alarm2, this function returns them as a variable of type struct.
void Alarm2_Enable(): enables alarm2 (writes 1 to A2IE bit).
void Alarm2_Disable(): disables alarm2 (writes 0 to A2IE bit).
int1 Alarm2_IF_Check(): returns 1 if alarm2 occurred, otherwise it returns 0.
void Alarm2_IF_Reset(): resets alarm2 flag bit (writes 0 to A2IF bit).
int1 Alarm2_Status(): returns 1 if alarm2 is enabled and 0 if disabled (reads A2IE bit).
void IntSqw_Set(INT_SQW _config): this function configures INT/SQW pin of the DS3231 where _config should be one of the following:
OUT_OFF —> output is off (internally attached to ground)
OUT_INT —> output is active low interrupt when alarm (alarm1 or alarm2)
OUT_1Hz —> output is a square wave with frequency of 1Hz
OUT_1024Hz —> output is a square wave with frequency of 1024Hz
OUT_4096Hz —> output is a square wave with frequency of 4096Hz
OUT_8192Hz —> output is a square wave with frequency of 8192Hz
void Enable_32kHZ(): enables 32kHz output (32kHz pin is open drain).
void Disable_32kHZ(): disables 32kHz output (internally attached to ground).
OSC_Start(): enables the DS3231 oscillator (writes 0 to ESOC bit).
OSC_Stop(): disables the DS3231 oscillator (writes 1 to ESOC bit).
int16_t Get_Temperature(): returns chip temperature. Temperature is stored in hundredths C (output value of “3125” equals 31.25 °C).
uint8_t RTC_Read_Reg(uint8_t reg_address): this function returns the value stored in register of address reg_address.
void RTC_Write_Reg(uint8_t reg_address, uint8_t reg_value): writes reg_value to register of address reg_address.
DS3231 driver for CCS C compiler download:
Driver source file download link is below, installation of this driver is easy, just add it to project folder or CCS C drivers folder (for example C:\Program Files (x86)\CCS\Drivers). Driver name is: DS3231.c.
DS3231 CCS C driver
DS3231 RTC Library Example:
This is a small example that shows how to use this library.
In this example PIC16F877A microcontroller is used, hardware circuit diagram is shown below.
All grounded terminals are connected together.
The 20×4 LCD screen (4 rows and 20 columns) is used to display time and date where:
RS —> pin RD0
RW —> pin RD1
E —> pin RD2
D4 —> pin RD3
D5 —> pin RD4
D6 —> pin RD5
D7 —> pin RD6
VSS, D0, D1, D2, D3 and K are connected to circuit ground
VEE to the variable resistor (or potentiometer) output
VDD to +5V and A to +5V through 330 ohm resistor.
VEE pin is used to control the contrast of the LCD. A (anode) and K (cathode) are the back light LED pins.
In this project the PIC16F877A microcontroller runs with 8 MHz crystal oscillator.
CCS C code:
The C code below is for CCS C compiler, it was tested with version 5.051.
To be able to compile project C code with no error, a driver (library) for the DS3231 RTC is required, download link is above.
After you download the driver file which named DS3231.c, add it to your project folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* * Interfacing PIC16F877A microcontroller with DS3231 RTC. * C Code for CCS C compiler. * Time and date are displayed on 20x4 LCD. * This is a free software with NO WARRANTY. * http://simple-circuit.com/ */ // LCD module connections #define LCD_RS_PIN PIN_D0 #define LCD_RW_PIN PIN_D1 #define LCD_ENABLE_PIN PIN_D2 #define LCD_DATA4 PIN_D3 #define LCD_DATA5 PIN_D4 #define LCD_DATA6 PIN_D5 #define LCD_DATA7 PIN_D6 // end LCD module connections #include <16F877A.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock = 8MHz) #use I2C(MASTER, I2C1, SLOW = 100000, STREAM = DS3231_STREAM) #include <lcd.c> // include LCD driver source file #include <DS3231.c> // include DS3231 driver source file signed int16 chip_temp; // DS3231 library variable declaration RTC_Time *mytime; // function for printing time and date on LCD void rtc_print() { // print day of the week lcd_gotoxy(5, 1); switch(mytime->dow) { case SUNDAY : printf(lcd_putc, " SUNDAY "); break; case MONDAY : printf(lcd_putc, " MONDAY "); break; case TUESDAY : printf(lcd_putc, " TUESDAY "); break; case WEDNESDAY: printf(lcd_putc, "WEDNESDAY"); break; case THURSDAY : printf(lcd_putc, "THURSDAY "); break; case FRIDAY : printf(lcd_putc, " FRIDAY "); break; default : printf(lcd_putc, "SATURDAY "); } // print time lcd_gotoxy(1, 2); printf(lcd_putc, "TIME: %02u:%02u:%02u", mytime->hours, mytime->minutes, mytime->seconds); // print date lcd_gotoxy(21, 1); printf(lcd_putc, "DATE: %02u-%02u-20%02u", mytime->day, mytime->month, mytime->year); // print chip temperature lcd_gotoxy(21, 2); if (chip_temp < 0) // if temperature is negative printf(lcd_putc, "TEMP:-%02Lu.%02Lu%cC", abs(chip_temp) / 100, abs(chip_temp) % 100, 223); else printf(lcd_putc, "TEMP: %02Lu.%02Lu%cC", chip_temp / 100, chip_temp % 100, 223); } // main function void main() { delay_ms(1000); // wait a second lcd_init(); lcd_putc('\f'); // read current time and date from the RTC chip mytime = RTC_Get(); // print them rtc_print(); delay_ms(1000); // wait a second // set RTC time to 21:08:47 (hh:mm:ss) and date to 03-01-19 (dd-mm-yy) mytime->hours = 21; mytime->minutes = 8; mytime->seconds = 47; mytime->dow = THURSDAY; mytime->day = 3; mytime->month = JANUARY; mytime->year = 19; // write time and date to the RTC chip RTC_Set(mytime); // enable SQW output with frequency of 1Hz IntSqw_Set(OUT_1Hz); while(TRUE) { // read current time and date from the RTC chip mytime = RTC_Get(); // read chip temperature chip_temp = Get_Temperature(); // print all data rtc_print(); delay_ms(100); // wait 100 ms } } // end of code. |
Proteus simulation as well as hardware circuit of the example should give the result shown below (RTC starts updating immediately).
Note that Proteus simulation circuit is not the same as real hardware circuit, project hardware circuit is shown above.
PIC Projects where DS3231 RTC driver is used:
Real time clock with alarms using PIC18F46K22 and DS3231
Discover more from Simple Circuit
Subscribe to get the latest posts sent to your email.
how to set this rtc to 12 hrs format ?
please replay