This topic shows how to build a real time clock with temperature monitor using PIC16F877A microcontroller, DS3231 RTC chip and ST7735R (ST7735S) 128×160 color TFT display. CCS C compiler is used in this example. Also a small video shows Proteus simulation of this project.
To build this project we need a driver for the ST7735 TFT screen which can be found in the post below:
ST7735 SPI TFT Display Driver for CCS C compiler
Previously I interfaced the PIC16F877A microcontroller with the DS3231 and the ST7735 TFT modules, project links are below:
Real time clock and calendar using DS3231 and PIC16F877A – CCS C
PIC16F877A + DS3231 with alarms and temperature monitor – CCS C
ST7735 1.8″ TFT display with PIC16F877A example – CCS C
Components Required:
To build this project we need the following components.
- PIC16F877A microcontroller —> datasheet
- DS3231 board
- ST7735R (ST7735S) TFT screen
- 20 MHz crystal oscillator
- 2 x 22 pF ceramic capacitor
- 10k ohm resistor
- 5 x 1K ohm resistor
- 2 x push button
- 3V coin cell battery
- Power source with 5V
- Breadboard
- Jumper wires
PIC16F877A with DS3231 RTC and 128×160 TFT circuit:
Project circuit schematic diagram is shown below.
All grounded terminals are connected together.
In the circuit there are 2 push buttons (B1 & B2) connected to PIC16F877A pins RB2 and RB3 respectively, the two push buttons are used to set time and date parameters (minutes, hours, day of the week, date, month and year). Button B1 selects the parameter and B2 increments the selected parameter.
In this project PORTB pull-ups are enabled (in the software) which means there is no need for external pull up resistors for pins RB2 and RB3. The microcontroller runs with 20MHz crystal oscillator (5 MIPS).
PIC16F877A with DS3231 RTC and 128×160 TFT C code:
The C code below was tested with CCS C compiler version 5.051 with no error and no warning!
ST7735 TFT driver for CCS C compiler is required and without it we can not compile the code, driver download link can be found in this post:
ST7735 SPI TFT Display Driver for CCS C compiler
After you download the driver (ST7735_TFT.c) just put it in your project folder or CCS C compiler drivers folder.
Since the PIC16F877A has one MSSP module (Master Synchronous Serial Port module) which can operate in SPI mode or I2C mode, I used software I2C to communicate between the master device (the microcontroller) and the slave device (DS3231). Software I2C is initialized using the function below:
#use I2C(master, SCL = PIN_B0, SDA = PIN_B1)
So, I used the MSSP in SPI mode for faster data transfer between the microcontroller and the ST7735 TFT display. Software SPI can be used but its very slow compared to hardware SPI.
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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | // PIC16F877A with DS3231 RTC and ST7735 1.8" SPI color TFT display // ST7735 TFT display driver for CCS PIC C compiler is required! // TFT module connections #define TFT_CS PIN_D1 #define TFT_DC PIN_D0 #define TFT_SPI_HARDWARE // End TFT module connections #define button1 PIN_B2 // Button B1 is connected to RB2 pin #define button2 PIN_B3 // Button B2 is connected to RB3 pin #include <16F877A.h> #device PASS_STRINGS = IN_RAM #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock = 20MHz) #use fast_io(B) #use fast_io(D) #include <ST7735_TFT.c> // Include ST7735 TFT driver #use I2C(master, SCL = PIN_B0, SDA = PIN_B1) char Time[] = " : : "; char Calendar[] = " / /20 "; char temperature[] = " 00.00"; signed int8 temperature_msb; int8 i, second, minute, hour, day, date, month, year, temperature_lsb; void display_day(){ switch(day){ case 1: drawtext(40, 10, " SUNDAY ", ST7735_CYAN, ST7735_BLACK, 1); break; case 2: drawtext(40, 10, " MONDAY ", ST7735_CYAN, ST7735_BLACK, 1); break; case 3: drawtext(40, 10, " TUESDAY ", ST7735_CYAN, ST7735_BLACK, 1); break; case 4: drawtext(40, 10, "WEDNESDAY", ST7735_CYAN, ST7735_BLACK, 1); break; case 5: drawtext(40, 10, "THURSDAY ", ST7735_CYAN, ST7735_BLACK, 1); break; case 6: drawtext(40, 10, " FRIDAY ", ST7735_CYAN, ST7735_BLACK, 1); break; default: drawtext(40, 10, "SATURDAY ", ST7735_CYAN, ST7735_BLACK, 1); } } void DS3231_display(){ // Convert BCD to decimal second = (second >> 4) * 10 + (second & 0x0F); minute = (minute >> 4) * 10 + (minute & 0x0F); hour = (hour >> 4) * 10 + (hour & 0x0F); date = (date >> 4) * 10 + (date & 0x0F); month = (month >> 4) * 10 + (month & 0x0F); year = (year >> 4) * 10 + (year & 0x0F); // End conversion Time[7] = second % 10 + 48; Time[6] = second / 10 + 48; Time[4] = minute % 10 + 48; Time[3] = minute / 10 + 48; Time[1] = hour % 10 + 48; Time[0] = hour / 10 + 48; Calendar[9] = year % 10 + 48; Calendar[8] = year / 10 + 48; Calendar[4] = month % 10 + 48; Calendar[3] = month / 10 + 48; Calendar[1] = date % 10 + 48; Calendar[0] = date / 10 + 48; if(temperature_msb < 0){ temperature_msb = abs(temperature_msb); temperature[0] = '-'; } else temperature[0] = ' '; temperature_lsb >>= 6; temperature[2] = temperature_msb % 10 + 48; temperature[1] = temperature_msb / 10 + 48; if(temperature_lsb == 0 || temperature_lsb == 2){ temperature[5] = '0'; if(temperature_lsb == 0) temperature[4] = '0'; else temperature[4] = '5'; } if(temperature_lsb == 1 || temperature_lsb == 3){ temperature[5] = '5'; if(temperature_lsb == 1) temperature[4] = '2'; else temperature[4] = '7'; } drawtext(4, 27, Calendar, ST7735_YELLOW, ST7735_BLACK, 2); drawtext(16, 81, Time, ST7735_GREEN, ST7735_BLACK, 2); drawtext(14, 134, temperature, ST7735_WHITE, ST7735_BLACK, 2); drawCircle(90, 134, 2, ST7735_WHITE); // Degree symbol (°) drawtext(96, 134, "C", ST7735_WHITE, ST7735_BLACK, 2); } void blink_parameter(){ byte j = 0; while(j < 10 && input(button1) && input(button2)){ j++; delay_ms(25); } } int8 edit(x_pos, y_pos, parameter){ char text[3]; int16 color = ST7735_YELLOW; sprintf(text,"%02u", parameter); if(i == 3 || i == 4) color = ST7735_GREEN; while(!input(button1)); // Wait until button B1 released while(true){ while(!input(button2)){ // If button (pin #9) is pressed parameter++; if(i == 0 && parameter > 31) // If date > 31 ==> date = 1 parameter = 1; if(i == 1 && parameter > 12) // If month > 12 ==> month = 1 parameter = 1; if(i == 2 && parameter > 99) // If year > 99 ==> year = 0 parameter = 0; if(i == 3 && parameter > 23) // If hours > 23 ==> hours = 0 parameter = 0; if(i == 4 && parameter > 59) // If minutes > 59 ==> minutes = 0 parameter = 0; sprintf(text,"%02u", parameter); drawtext(x_pos, y_pos, text, color, ST7735_BLACK, 2); delay_ms(200); // Wait 200ms } fillRect(x_pos, y_pos, 22, 16, ST7735_BLACK); blink_parameter(); drawtext(x_pos, y_pos, text, color, ST7735_BLACK, 2); blink_parameter(); if(!input(button1)){ // If button (pin #8) is pressed i++; // Increament 'i' for the next parameter return parameter; // Return parameter value and exit } } } void main(){ port_b_pullups(TRUE); // Enable PORTB pull-ups TFT_BlackTab_Initialize(); // Initialize the TFT display module fillScreen(ST7735_BLACK); // Fill the screen with black color // Draw fast two blue horizontal lines drawFastHLine(0, 53, _width, ST7735_BLUE); drawFastHLine(0, 106, _width, ST7735_BLUE); // Draw two texts ("TIME" and "TEMPERATURE") drawtext(52, 64, "TIME", ST7735_MAGENTA, ST7735_BLACK, 1); drawtext(30, 117, "TEMPERATURE", ST7735_RED, ST7735_BLACK, 1); while(TRUE){ if(!input(button1)){ // If button B1 is pressed i = 0; while(!input(button1)); // Wait for button B1 release while(true){ while(!input(button2)){ // While button B2 pressed day++; // Increment day if(day > 7) day = 1; display_day(); // Call display_day function delay_ms(200); // Wait 200 ms } fillRect(40, 10, 54, 8, ST7735_BLACK); // Draw rectangle (erase day from the display) blink_parameter(); // Call blink_parameter function display_day(); // Call display_day function blink_parameter(); // Call blink_parameter function if(!input(button1)) // If button B1 is pressed break; } date = edit(4, 27, date); // Edit date month = edit(40, 27, month); // Edit month year = edit(100, 27, year); // Edit year hour = edit(16, 81, hour); // Edit hours minute = edit(52, 81, minute); // Edit minutes // Convert decimal to BCD minute = ((minute / 10) << 4) + (minute % 10); hour = ((hour / 10) << 4) + (hour % 10); date = ((date / 10) << 4) + (date % 10); month = ((month / 10) << 4) + (month % 10); year = ((year / 10) << 4) + (year % 10); // End conversion // Write data to DS3231 RTC i2c_start(); // Start I2C protocol i2c_write(0xD0); // DS3231 address i2c_write(0); i2c_write(0); // Reset sesonds and start oscillator i2c_write(minute); // Write minute value to DS3231 i2c_write(hour); // Write hour value to DS3231 i2c_write(day); // Write day value (not used) i2c_write(date); // Write date value to DS3231 i2c_write(month); // Write month value to DS3231 i2c_write(year); // Write year value to DS3231 i2c_stop(); // Stop I2C protocol delay_ms(200); // Wait 200ms } // Read time and date i2c_start(); // Start I2C protocol i2c_write(0xD0); // DS3231 address i2c_write(0); // Send register address (seconds) i2c_start(); // Restart I2C i2c_write(0xD1); // Initialize data read second = i2c_read(1); // Read seconds from register 0 minute = i2c_read(1); // Read minuts from register 1 hour = i2c_read(1); // Read hour from register 2 day = i2c_read(1); // Read day from register 3 date = i2c_read(1); // Read date from register 4 month = i2c_read(1); // Read month from register 5 year = i2c_read(0); // Read year from register 6 i2c_stop(); // Stop I2C protocol // Read temperature i2c_start(); // Start I2C protocol i2c_write(0xD0); // DS3231 address i2c_write(0x11); // Send register address (temperature MSB) i2c_start(); // Restart I2C i2c_write(0xD1); // Initialize data read temperature_msb = i2c_read(1); // Read temperature MSB temperature_lsb = i2c_read(0); // Read temperature LSB i2c_stop(); // Stop I2C protocol display_day(); // Display day DS3231_display(); // Diaplay time & date delay_ms(50); // Wait 50ms } } // End of code |
The video below shows a simple protoboard circuit of the project:
and the following video shows Proteus simulation where DS3232 is used instead of the DS3231:
Proteus simulation file download:
Proteus simulation file can be downloaded from the link below, use it with version 8.6 or higher.
Download
Discover more from Simple Circuit
Subscribe to get the latest posts sent to your email.
and i wait a project with 2.4 inch TFT_ILI9341 by PIC18 or similar
Hi,thank you for this good project. How can we use display as landscape,