Thursday, July 6, 2017

DS1307 Interfacing with PIC16F887



This article shows how to build a simple real time clock/calendar using PIC16F887 and DS1307 RTC chip.
The DS1307 is an 8-pin integrated circuit uses I2C communication protocol to communicate with master device which is in our case the PIC16F887 microcontroller.
The PIC16F887 microcontroller has an I2C (IIC) module with two pins are used for data transfer. These are the RC3/SCK/SCL pin, which is the clock (SCL), and the RC4/SDI/SDA pin, which is the data (SDA).
The DS1307 can count seconds, minutes, hours, day, date, month and year with leap-year up to year 2100.
The DS1307 receives and transfers data (clock data and calendar data) as BCD format, so after receiving data we have to convert these data into decimal data, and before writing data to the DS1307 we have to convert this data from decimal to BCD format. For example we have the BCD number 33, converting this number into decimal gives 21.
In the CCS C code I used the following line to covert a number 'x' from BCD to decimal:
x = (x >> 4) * 10 + (x & 0x0F);
And to go from decimal to BCD I used this line:
x = ((x / 10) << 4) + (x % 10);
Hardware Required:
  • PIC16F887 Microcontroller
  • DS1307 RTC (datasheet)
  • 16x2 LCD screen
  • 32.768 KHz crystal
  • 10K potentiometer or variable resistor
  • 2 x 10K ohm resistors
  • 3V Coin cell battery
  • 0.1µF Ceramic capacitor (optional)
  • 5V Power supply source
  • Breadboard
  • Jumper wires
DS1307 Interfacing with PIC16F887 circuit:
The circuit diagram of the example is given below.
PIC16F887 and DS1307 RTC circuit
In this example the PIC16F887 MCU uses its internal oscillator and MCLR pin function is disabled.
SCL pin of PIC16F887 (pin number 18) is connected to the SCL pin of the DS1307 (pin number 6) and SDA pin of PIC16F887 (pin number 23) is connected to the SDA pin of the DS1307 (pin number 5).
The 3V cell battery is used to keep the time running if the main power is off.
The two resistors R1 & R2 are pull-up resistors, they are necessary for the I2C protocol.
In the circuit there are two buttons to set time and calendar. The button B1 selects time or calendar parameter (minutes, hours, date, month and year) and B2 increments the selected parameter.
DS1307 Interfacing with PIC16F887 CCS PIC C compiler code:
The code below can display time and calendar where their parameters such as minutes using two push buttons.
This code is tested with version 5.051.
/* Real time clock using PIC16F887 & DS1307 CCS C code
   Read DS1307 RTC datasheet to understand the code!
   Internal oscillator used @ 8MHz
   http://ccspicc.blogspot.com/
   electronnote@gmail.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 <16F887.h>
#fuses NOMCLR NOBROWNOUT NOLVP INTRC_IO
#use delay(clock = 8MHz)
#include <lcd.c>
#use fast_io(B)
#use I2C(master, I2C1, FAST = 100000)

char time[] = "TIME:  :  :  ";
char calendar[] = "DATE:  /  /20  ";
unsigned int8  second, minute, hour, date, month, year, day;
void ds1307_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[12]     = second % 10  + 48;
  time[11]     = second / 10  + 48;
  time[9]      = minute % 10  + 48;
  time[8]      = minute / 10  + 48;
  time[6]      = hour % 10  + 48;
  time[5]      = hour / 10  + 48;
  calendar[14] = year % 10 + 48;
  calendar[13] = year / 10  + 48;
  calendar[9]  = month % 10 + 48;
  calendar[8]  = month / 10 + 48;
  calendar[6]  = date % 10 + 48;
  calendar[5]  = date / 10 + 48;
  lcd_gotoxy(1, 1);                              // Go to column 1 row 1
  printf(lcd_putc, time);                        // Display time
  lcd_gotoxy(1, 2);                              // Go to column 1 row 2
  printf(lcd_putc, calendar);                    // Display calendar
}
void ds1307_write(unsigned int8 address, data_){
  i2c_start();                                   // Start I2C protocol
  i2c_write(0xD0);                               // DS1307 address
  i2c_write(address);                            // Send register address
  i2c_write(data_);                              // Write data to the selected register
  i2c_stop();                                    // Stop I2C protocol
}
void main(){
  setup_oscillator(OSC_8MHZ);                    // Set internal oscillator to 8MHz
  port_b_pullups(3);                             // Enable internal pull-ups for RB0 & RB1
  lcd_init();                                    // Initialize LCD module
  lcd_putc('\f');                                // LCD clear
  while(TRUE){
   if(!input(PIN_B0)){                           // If RB0 button is pressed
    lcd_putc('\f');                              // LCD clear
    lcd_gotoxy(5, 1);                            // Go to column 5 row 1
    lcd_putc("Minute:");
    delay_ms(200);
    while(TRUE){
     if(!input(PIN_B1))                          // If RB1 button is pressed
      minute++;                                  // Increment minutes
     if(minute > 59)
      minute = 0;
     lcd_gotoxy(8, 2);                           // Go to column 8 row 2
     printf(lcd_putc,"%02u", minute);
     if(!input(PIN_B0))
      break;
     delay_ms(200);
    }
    lcd_putc('\f');                              // LCD clear
    lcd_gotoxy(6, 1);                            // Go to column 6 row 1
    lcd_putc("Hour:");
    delay_ms(200);
    while(TRUE){
     if(!input(PIN_B1))
      hour++;
     if(hour > 23)
      hour = 0;
     lcd_gotoxy(8, 2);                           // Go to column 8 row 2
     printf(lcd_putc,"%02u", hour);
     if(!input(PIN_B0))
      break;
     delay_ms(200);
    }
    lcd_putc('\f');                              // LCD clear
    lcd_gotoxy(6, 1);                            // Go to column 6 row 1
    lcd_putc("Date:");
    delay_ms(200);
    while(TRUE){
     if(!input(PIN_B1))
      date++;
     if(date > 31)
      date = 1;
     lcd_gotoxy(8, 2);                           // Go to column 8 row 2
     printf(lcd_putc,"%02u", date);
     if(!input(PIN_B0))
      break;
     delay_ms(200);
    }
    lcd_putc('\f');                              // LCD clear
    lcd_gotoxy(6, 1);                            // Go to column 6 row 1
    lcd_putc("Month:");
    delay_ms(200);
    while(TRUE){
     if(!input(PIN_B1))
      month++;
     if(month > 12)
      month = 1;
     lcd_gotoxy(8, 2);                           // Go to column 8 row 2
     printf(lcd_putc,"%02u", month);
     if(!input(PIN_B0))
      break;
     delay_ms(200);
    }
    lcd_putc('\f');                              // LCD clear
    lcd_gotoxy(6, 1);                            // Go to column 6 row 1
    lcd_putc("Year:");
    lcd_gotoxy(7, 2);                            // Go to column 7 row 1
    lcd_putc("20");
    delay_ms(200);
    while(TRUE){
     if(!input(PIN_B1))
      year++;
     if(year > 99)
      year = 0;
     lcd_gotoxy(9, 2);                           // Go to column 9 row 2
     printf(lcd_putc,"%02u", year);
     if(!input(PIN_B0)){
      // 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
      ds1307_write(1, minute);                   // Write minute value to DS1307
      ds1307_write(2, hour);
      ds1307_write(4, date);
      ds1307_write(5, month);
      ds1307_write(6, year);
      ds1307_write(0, 0);                        //Reset seconds and start oscillator
      delay_ms(200);
      break;
     }
     delay_ms(200);
    }
   }
   i2c_start();                                  // Start I2C protocol
   i2c_write(0xD0);                              // DS1307 address
   i2c_write(0);                                 // Send register address
   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
   ds1307_display();                             // Diaplay time & calendar
   delay_ms(50);
  }
}

The following video shows project simulation with Proteus:


Simulation file can be downloaded from this link:
DS1307 + PIC16F887 Simulation

Saturday, November 5, 2016

Real time clock with remote control and ST7735 TFT display


Remote controlled real time clock using PIC18F4550 and DS1307
PIC18F4550 + DS1307 + ST7735R SPI TFT Display + RC-5 IR remote Control circuit 
(Some knowledge about RC-5 protocol is required)
This project shows how to build a remote controlled real time clock with TFT display using PIC18F4550 microcontroller.
In this project DS1307 RTC is used as a real time clock chip and the remote control is an IR (infrared) remote control which uses RC-5 communication protocol, this remote control is used to set time and date. The device used t display time and calendar is 1.8" ST7735R (ST7735S) SPI TFT display.
To display the ST7735 TFT display with PIC18F4550 microcontroller we need a driver, this driver and some other details about this display can be fount at the following url:
ST7735 SPI TFT Display Driver for CCS PIC C compiler
And the post at the following link shows how to interface this display with PIC18F4550 microcontroller:
Interfacing PIC18F4550 with 1.8" TFT display
Or simply you can download the ST7735 TFT driver from the following link:
ST7735 SPI TFT Display Driver
The method used to decode RC-5 signals is described in the following topic:
RC5 IR Remote Control Decoder with PIC12F1822 Microcontroller
The decoding process follows the state machine show below:
Philips RC-5 protocol state machine
Where:
SP : Short Pulse (About 889µs)
LP : Long Pulse (About 1778µs)
SS: Short Space (About 889µs)
LS : Long Space (About 1778µs)
Basically there are 4 states: Mid1, Mid0, Start1 and Start0.
Components List:
  • PIC18F4550 Microcontroller
  • ST7735R (ST7735S) 1.8" SPI TFT Display
  • DS1307 RTC Chip
  • RC-5 IR Remote Control
  • IR Receiver
  • 8MHz Crystal Oscillator
  • 32.768KHz Crystal Oscillator
  • 2 x 22pF Ceramic Capacitors
  • 47uF Capacitor
  • 3 x 10K Resistor
  • 5 x 1K Resistors
  • 3V Lithium Coin Cell Battery
  • +5V Power Supply Source
  • Breadboard
  • Jumper Wires
For the DS1307 RTC chip there are many topics in this blog talking about it and how to interface it with different types of PIC microcontrollers for example the topic at the url below:
Real time clock with PIC18F4550 and DS1307 RTC
Real time clock with remote control and ST7735 TFT display circuit:
The following image shows our project circuit schematic where the microcontroller runs with 8MHz external crystal oscillator.
Real time clock with PIC18F4550, ST7735R SPI TFT, DS1307 RTC and RC-5 IR remote control
Real time clock with remote control and ST7735 TFT display CCS C code:
In this project the microcontroller runs with 8MHz external crystal oscillator and to make it runs at full speed which is 48MHz we have to use the following fuses:
#fuses NOMCLR HSPLL PLL2 CPUDIV1
Where: PLL2 enables the PLL and divide it by 2
and if for example the crystal oscillator frequency is 12MHz so we have to change PLL2 to PLL3 and so on.
CPUDIV1: No system clock postscaler
PIC18F4550 Microcontroller has only 1 MSSP module which can be configured to work as SPI module or I2C module. In this project we need SPI protocol for the TFT display and I2C for DS1307. Since the TFT display needs a high speed SPI interface, I used PIC18F4550 hardware SPI module to communicate with the TFT display and I implemented a software I2C protocol for DS1307, the following line is used to create a simple software I2C:
#use I2C(master, SDA = PIN_D3, SCL = PIN_D2)
So DS1307 SDA pin is mapped at RD3 and SCL at RD2.
The remote control used in this project is shown below with button codes. This IR remote control is just a TV remote control which use RC5 communication protocol:
Only 3 buttons are used and the rest have no effect on the circuit.
The button codes displayed in the picture above are the address and command codes combined together. The RC-5 code message is 14 bit long, 2 start bits, a toggle bit, 5 bits as address and 6 bits as command. For example select button which has an address of 0 and command of 0x3B which gives a 16-bit number of 0x3B (toggle bit is neglected).
The toggle bit toggles between 0 and 1. Every time a button is pressed the toggle bit changes. If a button is pressed and kept pressing the toggle bit changes only at the first time and the remote control keep sending the same code of the pressed button with the same toggle bit.
From that I used the toggle bit to check if the select button is pressed again or kept pressing in order to avoid jumping from parameter to another and if you want to go from paramter to another you have to repress the select button.
For the other two buttons (up & down) the toggle bit is not used in order to speed up the setting of the parameters.
The output of the IR receiver is connected to RB2 pin which is external interrupt 2 pin. When the receiver receives an IR signal its output falls (goes form 5V to 0) which makes the microcontroller interrupts. When the mcu interrupts it jumps to interrupt routine ( void ext2_isr(void) ) and starts decoding the IR signal. Timer1 is used to measure pulses and spaces comes from the remote control. The microcontroller decodes the signal according to the state machine above. The interrupt is stopped during DS1307 reading or writing and also during sending data to TFT display.
The following code is tested with CCS PIC C compiler versions 4.068 and 5.051.
/* Real time clock with remote control using PIC18F4550 CCS C code
   1.8" ST7735R with balck tap (ST7735S) SPI TFT display is used to diplay time and date
   DS1307 RTC is used as real time clock chip
   DS1307 Uses I2C protocol
   Remote control: TV RC5 IR remote control
   ST7735 TFT display driver for CCS PIC C compiler is required
   http://ccspicc.blogspot.com/
   electronnote@gmail.com
*/

// TFT module connections
#define TFT_CS  PIN_D1
#define TFT_DC  PIN_D0
#define TFT_SPI_HARDWARE
// End TFT module connections

#include <18F4550.h>
#fuses NOMCLR HSPLL PLL2 CPUDIV1
#use delay(clock = 48000000)
#include <ST7735_TFT.c>
#use fast_io(B)
#define IR_Sensor PIN_B2
#use I2C(master, SDA = PIN_D3, SCL = PIN_D2)

int1 toggle0, toggle;
char *text = "TIME:";
char time[]       = "  :  :  "  ;
char calendar[] = "  /  /20  ";
unsigned int8 second, second10, minute, minute10, hour, hour10, date,
              date10, month, month10, year, year10, day0, day, i, j ;
unsigned int16 ir_code, count;
int8 test_pulse(){
  count = 0;
  SET_TIMER1(0);
  while(!input(IR_Sensor) && (count < 3000))
    count = GET_TIMER1();
  if((count > 2999) || (count < 1000))
    return 0;
  if(count > 1800)
    return 1;
  else
    return 2;
}
int8 test_space(){
  count = 0;
  SET_TIMER1(0);
  while(input(IR_Sensor) && (count < 3000))
    count = GET_TIMER1();
  if((count > 2999) || (count < 1000))
    return 0;
  if(count > 1800)
    return 1;
  else
    return 2;
}
// Follow the RC5 state machine to understand
short remote_read(){
  int8 m = 0, check;
  mid1:
  check = test_pulse();
  if(check == 0)
    return FALSE;
  bit_set(ir_code, 13 - m);
  m++;
  if(m > 13)  return TRUE;
  if(check == 1)
    goto mid0;
  else
    goto start1;
  mid0:
  check = test_space();
  if((check == 0) && (m != 13))
    return FALSE;
  bit_clear(ir_code, 13 - m);
  m++;
  if(m > 13) return TRUE;
  if(check == 1)
    goto mid1;
  else
    goto start0;
  start1:
  check = test_space();
  if(check != 2)
    return FALSE;
  goto mid1;
  start0:
  check = test_pulse();
  if(check != 2)
    return FALSE;
  goto mid0;
}
void display_day(){
  switch(day){
    case 1: strcpy (text, "SUNDAY");
      drawtext(28, 105, text, ST7735_CYAN, ST7735_BLACK, 2); break;
    case 2: strcpy (text, "MONDAY");
      drawtext(28, 105, text, ST7735_CYAN, ST7735_BLACK, 2); break;
    case 3: strcpy (text, "TUESDAY");
      drawtext(22, 105, text, ST7735_CYAN, ST7735_BLACK, 2); break;
    case 4: strcpy (text, "WEDNESDAY");
      drawtext(10, 105, text, ST7735_CYAN, ST7735_BLACK, 2); break;
    case 5: strcpy (text, "THURSDAY");
      drawtext(16, 105, text, ST7735_CYAN, ST7735_BLACK, 2); break;
    case 6: strcpy (text, "FRIDAY");
      drawtext(28, 105, text, ST7735_CYAN, ST7735_BLACK, 2); break;
    case 7: strcpy (text, "SATURDAY");
      drawtext(16, 105, text, ST7735_CYAN, ST7735_BLACK, 2); break;
  }
}
void ds1307_display(){
  strcpy (time, "  :  :  ");
  strcpy (calendar, "  /  /20  ");
  second10  =  (second & 0x70) >> 4;
  second = second & 0x0F;
  minute10  =  (minute & 0x70) >> 4;
  minute = minute & 0x0F;
  hour10  =  (hour & 0x30) >> 4;
  hour = hour & 0x0F;
  date10  =  (date & 0x30) >> 4;
  date = date & 0x0F;
  month10  =  (month & 0x10) >> 4;
  month = month & 0x0F;
  year10  =  (year & 0xF0) >> 4;
  year = year & 0x0F;
  time[7]  = second  + 48;
  time[6]  = second10  + 48;
  time[4]  = minute  + 48;
  time[3]  = minute10  + 48;
  time[1]  = hour  + 48;
  time[0]  = hour10  + 48;
  calendar[9]  = year  + 48;
  calendar[8]  = year10  + 48;
  calendar[4]  = month + 48;
  calendar[3]  = month10 + 48;
  calendar[1]  = date + 48;
  calendar[0]  = date10 + 48;
  drawtext(16, 41, time, ST7735_GREEN, ST7735_BLACK, 2);
  drawtext(4, 137, calendar, ST7735_YELLOW, ST7735_BLACK, 2);
  if(day0 != day){
    day0 = day;
    fillRect(8, 105, 112, 15, ST7735_BLACK);
  }
  display_day();
}
void ds1307_write(unsigned int8 address, data_){
  i2c_start();                                        // Start I2C
  i2c_write(0xD0);                                    // DS1307 address
  i2c_write(address);                                 // Send register address
  i2c_write(data_);                                   // Write data to the selected register
  i2c_stop();                                         // Stop I2C
}
void ds1307_read(){
  i2c_start();                                        // Start I2C protocol
  i2c_write(0xD0);                                    // DS1307 address
  i2c_write(0);                                       // Send register address
  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
}
int8 edit(int8 parameter, unsigned int8 xx, unsigned int8 yy, unsigned int16 color){
  ir_code = 0;
  while(TRUE){
    if(ir_code == 0x20){
      ir_code = 0;
      parameter++;
      if(i == 1 && parameter > 23)
        parameter = 0;
      if(i == 2 && parameter > 59)
        parameter = 0;
      if(i == 3 && parameter > 31)
        parameter = 1;
      if(i == 4 && parameter > 12)
        parameter = 1;
      if(i == 5 && parameter > 99)
        parameter = 0;
    }
    if(ir_code == 0x21){
      ir_code = 0;
      if(i == 1 && parameter < 1)
        parameter = 24;
      if(i == 2 && parameter < 1)
        parameter = 60;
      if(i == 3 && parameter < 2)
        parameter = 32;
      if(i == 4 && parameter < 2)
        parameter = 13;
      if(i == 5 && parameter < 1)
        parameter = 100;
      parameter--;
    }
    sprintf(text,"%02u", parameter);
    drawtext(xx, yy, text, color, ST7735_BLACK, 2);
    j = 0;
    while((ir_code != 0x20) && (ir_code != 0x21) && ((ir_code != 0x3B) || (toggle0 == toggle)) && (j < 25)){
      j++;
      delay_ms(10);
    }
    strcpy (text, "  ");
    drawtext(xx, yy, text, color, ST7735_BLACK, 2);
    j = 0;
    while((ir_code != 0x20) && (ir_code != 0x21) && ((ir_code != 0x3B) || (toggle0 == toggle)) && (j < 25)){
      j++;
      delay_ms(10);
    }
    if((ir_code == 0x3B) && (toggle0 != toggle)){
      toggle0 = toggle;
      sprintf(text,"%02u", parameter);
      drawtext(xx, yy, text, color, ST7735_BLACK, 2);
      return parameter;
    }
  }  
}
#INT_EXT2                                             // External interrupt (INT2) ISR
void ext2_isr(void){
  if(remote_read()){
    toggle = bit_test(ir_code, 11);
    ir_code &= 0x07FF;
  }
  clear_interrupt(INT_EXT2);
}
void main(){
  setup_adc_ports(NO_ANALOGS);                        // Configure AN pins as digital
  enable_interrupts(GLOBAL);                          // Enable global interrupts
  ext_int_edge(2, H_TO_L);
  clear_interrupt(INT_EXT2);                          // Clear RA IOC flag bit
  SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_8);
  TFT_BlackTab_Initialize();
  fillScreen(ST7735_BLACK);
  drawtext(36, 9, text, ST7735_RED, ST7735_BLACK, 2);
  strcpy (text, "DATE:");
  drawtext(36, 73, text, ST7735_MAGENTA, ST7735_BLACK, 2);
  while(TRUE){
    if((ir_code == 0x3B) && (toggle0 != toggle)){
      toggle0 = toggle;
      // Convert BCD to decimal
      minute = minute + minute10 * 10;
      hour = hour + hour10 * 10;
      date = date + date10 * 10;
      month = month + month10 * 10;
      year = year + year10 * 10;
      // End conversion
      i = 1;
      hour = edit(hour, 16, 41, ST7735_GREEN);
      i = 2;
      minute = edit(minute, 52, 41, ST7735_GREEN);
      ir_code = 0;
      while(TRUE){
        if(ir_code == 0x20){
          ir_code = 0;
          day++;
          if(day > 7)  day = 1;
        }
        if(ir_code == 0x21){
          ir_code = 0;
          if(day < 2)  day = 8;
          day--;
        }
        display_day();
        j = 0;
        while((ir_code != 0x20) && (ir_code != 0x21) && ((ir_code != 0x3B) || (toggle0 == toggle)) && (j < 25)){
          j++;
          delay_ms(10);
        }
        fillRect(4, 105, 120, 14, ST7735_BLACK);
        j = 0;
        while((ir_code != 0x20) && (ir_code != 0x21) && ((ir_code != 0x3B) || (toggle0 == toggle)) && (j < 25)){
          j++;
          delay_ms(10);
        }
        if((ir_code == 0x3B) && (toggle0 != toggle)){
          toggle0 = toggle;
          display_day();
          break;
        }
      }
      i = 3;
      date = edit(date, 4, 137, ST7735_YELLOW); 
      i = 4;
      month = edit(month, 40, 137, ST7735_YELLOW);
      i = 5;
      year = edit(year, 100, 137, ST7735_YELLOW);      
      ir_code = 0;
      // 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
      // Save all parametrs in DS1307 chip
      disable_interrupts(INT_EXT2);                   // Disable INT2
      ds1307_write(1, minute);
      ds1307_write(2, hour);
      ds1307_write(3, day);
      ds1307_write(4, date);
      ds1307_write(5, month);
      ds1307_write(6, year);
      ds1307_write(0, 0);
      enable_interrupts(INT_EXT2);                    // Enable INT2
      // End saving
    }
    disable_interrupts(INT_EXT2);                     // Disable INT2
    ds1307_read();                                    // Read data from DS1307 RTCC
    ds1307_display();                                 // Diaplay time and calendar
    enable_interrupts(INT_EXT2);                      // Enable INT2
    delay_ms(100);
  }
}
Real time clock with remote control and ST7735 TFT display video:
Project video ....

Sunday, October 23, 2016

Real Time Clock/Calendar with Remote Control


Remote Controlled Real Time Clock/Calendar with PIC12F1822, DS1307
It is good idea to build a simple and low cost DIY remote controlled real time clock/calendar using simple components. This post show how to make a remote controlled real time clock using PIC12F1822 microcontroller, DS1307 RTC chip, NEC IR remote control and all data are displayed on 1602 LCD.
The DS1307 is an 8-pin integrated circuit uses I2C communication protocol to communicate with master device which is in our case PIC12F1822 microcontroller. This small chip can count seconds, minutes, hours, day, date, month and year with leap-year up to year 2100.
The DS1307 receives and transfers data (clock data and calendar data) as BCD format, so after receiving data we have to convert these data into decimal data, and before writing data to the DS1307 we have to convert this data from decimal to BCD format. For example we have the BCD number 33, converting this number into decimal gives 21.
PIC12F1822 has an I2C hardware module which can work as master device. The I2C bus specifies two signal connections:
Serial Clock (SCL) (pin RA1)
Serial Data (SDA) (pin RA2)
The time and date informations are displayed on 1602 LCD display. This LCD is interfaced with the microcontroller using 74HC595 shift register as what was done in this post:
Interfacing PIC12F1822 microcontroller with LCD display
The IR remote control used in this project uses NEC communication protocol. The following post shows how this protocol works and how to decode its data with PIC12F1822:
Extended NEC Protocol Decoder Using PIC12F1822 Microcontroller
An image of the remote control used in this project with used buttons data is shown below. Only 3 buttons are used in this project and the rest of buttons have no effect on the circuit.
Components List:
  • PIC12F1822 Microcontroller
  • NEC Protocol IR Remote Control (Example: Car MP3)
  • DS1307 RTC
  • 1602 LCD
  • 74HC595 Shift Register
  • IR Receiver
  • 47µF Capacitor
  • 32.768 Crystal
  • 3V Lithium Coin Cell Battery
  • 10K Variable Resistor
  • 3 x 10K Resistor
  • +5V Power Supply
  • Protoboard
  • Jumper Wires
Remote controlled real time clock using PIC12F1822 and DS1307 circuit:
Remote controlled real time clock using PIC12F1822, DS1307 and NEC IR remote control circuit
For this project internal oscillator of the microcontroller is used and MCLR pin is configured to work as a digital input pin.
The IR receiver has 3 pins: GND, VCC (+5V) and OUT. The OUT pin is connected to RA3 pin of PIC12F1822. The IR receiver is used to receive IR signals comes from the remote control and sends data to the microcontroller.
DS1307 RTC has 8 pins and only pin 7 is not used. The DS1307 RTC needs an external crystal oscillator of 32.768KHz which is connected between pins 1 & 2. A 3V coin cell Lithium battery is connected between pin 3 (VBAT) and GND. This battery is used as a backup power supply for the DS1307 whenever the main power fails, it keeps the time running without any problem. DS1307 is connected to microcontroller via two lines SCL and SDA. A pull-ups resistors must be added to the two lines because both are open drain.
The 1602 LCD display pins are connected to 74HC595 shift register except the Enable pin (E) which is connected directly to PIC12F1822. With the help of the shift register 74HC595 the LCD uses only 3 data lines: clock, data and Enable. Other types of serial-in parallel-out shift registers can be used such as 74HC164 and CD4094 (74HC4094).
Remote controlled real time clock using PIC12F1822 and DS1307 CCS C code:
PIC12F1822 internal oscillator is used in this project at 8MHz and by enabling PLL we get a frequency of 32MHz (8 x 4).
Timer1 is configured to increment by 1 every 1us. It is used to measure IR signals spaces and pulses.
RA3 Pin interrupt is used to interrupt when the IR receiver receives an IR signal. So when the IR receiver receives a signal the output of the IR receives goes from high to low which causes the microcontroller to interrupt and starts decoding the received IR signal. Enabling RA3 interrupt is done using the following two lines:
enable_interrupts(GLOBAL);
enable_interrupts(INT_RA3_H2L);
Complete CCS C code:
// Real time colck/calendar with remote control using PIC12F1822 and DS1307 RTC CCS PIC C code
// 3-Wire LCD driver must be added
// http://ccspicc.blogspot.com/
// electronnote@gmail.com
// Use at your own risk

//LCD module connections
#define LCD_DATA_PIN PIN_A0
#define LCD_CLOCK_PIN PIN_A4
#define LCD_EN_PIN PIN_A5
//End LCD module connections

#include <12F1822.h>
#fuses NOMCLR INTRC_IO PLL_SW
#use delay(clock=32000000)
#include <3WireLCD.c>
#use fast_io(A)
#define IR_Sensor PIN_A3
#use I2C(master, I2C1, FAST = 100000)

char time[] =     "TIME:  :  :     ";
char calendar[] = "DATE:  /  /20   ";
unsigned int8 second, second10, minute, minute10, hour, hour10, date,
              date10, month, month10, year, year10, day, i, j;
unsigned int32 ir_code;
unsigned int32 nec_remote_read(){
  unsigned int8 k;
  unsigned int16 count = 0;
  unsigned int32 code;
  // Check 9ms pulse (remote control sends logic high)
  SET_TIMER1(0);
  while(!input(IR_Sensor) && (count < 9500))
    count = GET_TIMER1();
  if((count > 9499) || (count < 8500))
    return 0;
  // Check 4.5ms space (remote control sends logic low)
  SET_TIMER1(0);
  count = 0;
  while((input(IR_Sensor)) && (count < 5000))
    count = GET_TIMER1();
  if((count > 4999) || (count < 4000))
    return 0;
  // Read message (32 bits)
  for(k = 0; k < 32; k++){
    SET_TIMER1(0);
    count = 0;
    while(!input(IR_Sensor) && (count < 650))
      count = GET_TIMER1();
    if((count > 649) || (count < 500))
      return 0;
    count = 0;
    SET_TIMER1(0);
    while((input(IR_Sensor)) && (count < 1800))
      count = GET_TIMER1();
    if( (count > 1799) || (count < 400))
      return 0;
    if( count > 1000)                                 // If space width > 1ms
      bit_set(code, (31 - k));                        // Write 1 to bit (31 - k)
    else                                              // If space width < 1ms
      bit_clear(code, (31 - k));                      // Write 0 to bit (31 - k)
  }
  return code;
}
#INT_RA                                               // RB port interrupt on change
void ra_isr(void){
  ir_code = nec_remote_read();
  clear_interrupt(INT_RA);
}
void ds1307_display(){
  second10  =  (second & 0x70) >> 4;
  second = second & 0x0F;
  minute10  =  (minute & 0x70) >> 4;
  minute = minute & 0x0F;
  hour10  =  (hour & 0x30) >> 4;
  hour = hour & 0x0F;
  date10  =  (date & 0x30) >> 4;
  date = date & 0x0F;
  month10  =  (month & 0x10) >> 4;
  month = month & 0x0F;
  year10  =  (year & 0xF0) >> 4;
  year = year & 0x0F;
  time[12]  = second  + 48;
  time[11]  = second10  + 48;
  time[9]  = minute  + 48;
  time[8]  = minute10  + 48;
  time[6]  = hour  + 48;
  time[5]  = hour10  + 48;
  calendar[14]  = year  + 48;
  calendar[13]  = year10  + 48;
  calendar[9]  = month + 48;
  calendar[8]  = month10 + 48;
  calendar[6]  = date + 48;
  calendar[5]  = date10 + 48;
  lcd_goto(1, 1);                                     // Go to column 1 row 1
  printf(lcd_out, time);                              // Display time
  lcd_goto(1, 2);                                     // Go to column 1 row 2
  printf(lcd_out, calendar);                          // Display calendar
}
void ds1307_write(unsigned int8 address, data_){
  i2c_start();                                        // Start I2C
  i2c_write(0xD0);                                    // DS1307 address
  i2c_write(address);                                 // Send register address
  i2c_write(data_);                                   // Write data to the selected register
  i2c_stop();                                         // Stop I2C
}
void ds1307_read(){
   i2c_start();                                       // Start I2C protocol
   i2c_write(0xD0);                                   // DS1307 address
   i2c_write(0);                                      // Send register address
   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
}
int8 edit(int8 parameter, int8 xx, int8 yy){
  ir_code = 0;
  while(TRUE){
    if(ir_code == 0x40BF40BF){
      ir_code = 0;
      parameter++;
      if(i == 1 && parameter > 23)
        parameter = 0;
      if(i == 2 && parameter > 59)
        parameter = 0;
      if(i == 3 && parameter > 31)
        parameter = 1;
      if(i == 4 && parameter > 12)
        parameter = 1;
      if(i == 5 && parameter > 99)
        parameter = 0;
      }
    if(ir_code == 0x40BF807F){
      ir_code = 0;
      if(i == 1 && parameter < 1)
        parameter = 24;
      if(i == 2 && parameter < 1)
        parameter = 60;
      if(i == 3 && parameter < 2)
        parameter = 32;
      if(i == 4 && parameter < 2)
        parameter = 13;
      if(i == 5 && parameter < 1)
        parameter = 100;
      parameter--;
      }
    lcd_goto(xx, yy);
    printf(lcd_out,"%02u", parameter);
    j = 0;
    while((ir_code != 0x40BF00FF) && (ir_code != 0x40BF40BF) && (ir_code != 0x40BF807F) && (j < 5)){
      j++;
     delay_ms(50);}
    lcd_goto(xx, yy);
    lcd_out("  ");
    j = 0;
    while((ir_code != 0x40BF00FF) && (ir_code != 0x40BF40BF) && (ir_code != 0x40BF807F) && (j < 5)){
      j++;
      delay_ms(50);}
    if(ir_code == 0x40BF00FF){
      lcd_goto(xx, yy);
      printf(lcd_out,"%02u", parameter);
      return parameter;}
  }
}
void main() {
  setup_oscillator(OSC_8MHZ | OSC_PLL_ON);            // Set internal oscillator to 32MHz (8MHz and PLL)
  setup_adc_ports(NO_ANALOGS);                        // Configure AN pins as digital
  output_a(0);
  set_tris_a(0x0E);                                   // Configure RA1, RA2 & RA3 as inputs
  lcd_initialize();                                   // Initialize LCD module
  lcd_cmd(LCD_CLEAR);                                 // LCD Clear
  SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_8);           // Configure Timer 1 to increment every 1 us
  enable_interrupts(GLOBAL);                          // Enable global interrupts
  clear_interrupt(INT_RA);                            // Clear RA IOC flag bit
  enable_interrupts(INT_RA3_H2L);                     // Enable RA3 interrupt (High to low)
  while(TRUE){
    if(ir_code == 0x40BF00FF){
      // Convert BCD to decimal
      minute = minute + minute10 * 10;
      hour = hour + hour10 * 10;
      date = date + date10 * 10;
      month = month + month10 * 10;
      year = year + year10 * 10;
      // End conversion
      i = 1;
      hour = edit(hour, 6, 1);
      i = 2;
      minute = edit(minute, 9, 1);
      i=3;
      date = edit(date, 6, 2); 
      i=4;
      month = edit(month, 9, 2);
      i=5;
      year = edit(year, 14, 2);
      ir_code = 0;
      // 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
      ds1307_write(1, minute);
      ds1307_write(2, hour);
      ds1307_write(4, date);
      ds1307_write(5, month);
      ds1307_write(6, year);
      ds1307_write(0, 0);
    }
    ds1307_read();                                    // Read data from DS1307 RTCC
    ds1307_display();                                 // Diaplay time and calendar
    delay_ms(50);
  }
}
Real Time Clock/Calendar with Remote Control Video:
Project hardware circuit.

Thursday, September 8, 2016

Real time clock with relative humidity and temperature sensing using PIC16F877A, 2004 LCD, DS1307 RTC and DHT11


This topic shows how to build a real time clock with relative humidity and temperature sensing using PIC16F877A microcontroller, DS1307 RTC and DHT11 (RHT01) sensor where all data are displayed on 20x4 LCD display. The 20x4 LCD has 20 columns and 4 rows which is good enough for this project. The compiler used to program the microcontroller is CCS PIC C PCWHD.
To see how to interface PIC16F877A with DS1307 take a look at the following topic:
Real time clock using PIC16F877A microcontroller and DS1307 serial RTC
And to see how to interface PIC18F4550 with DHT22 (AM2302) take a look at this topic:
Interfacing DHT11 relative humidity and temperature sensor with PIC16F877A microcontroller
The DS1307 RTC is an 8-pin integrated circuit uses I2C communication protocol to communicate with master device which is in our case the PIC16F877A microcontroller. This small chip can count seconds, minutes, hours, day, date, month and year with leap-year up to year 2100.
The DHT11 (RHT01) sensor comes in a single row 4-pin package and operates from 3.3 to 5.5V power supply. It can measure temperature from 0-50 °C with an accuracy of ±2°C and relative humidity ranging from 20-90% with an accuracy of  ±5%. The sensor provides fully calibrated digital outputs for the two measurements. It has got its own proprietary 1-wire protocol, and therefore, the communication between the sensor and a microcontroller is not possible through a direct interface with any of its peripherals. The protocol must be implemented in the firmware of the MCU with precise timing required by the sensor.
Component list:
  • PIC16F877A microcontroller
  • DS1307 RTC
  • DHT11 (RHT01) Sensor
  • 2004 LCD
  • 3V Coin cell battery
  • 8MHz and 32.768KHz crystal oscillators
  • 2 x 22pF capacitors
  • 3 x 10K resistors
  • 4.7K resistor
  • 10K Potentiometer
  •  2 Buttons
  • +5V Power Supply
  • Protoboard
  • Jumper Wires
PIC16F877A + 2004 LCD + DS1307 RTC + DHT11 sensor circuit:
PIC16F877A + 2004 LCD + DS1307 RTC + DHT11 (RHT01) circuit CCS C
 The two pushbuttons for adjusting time and date as shown in the video below.
CCS C code:
The project C code is just a combination of the C codes of the two previous projects.
The reading of relative humidity and temperature data is done every 1 second.
// PIC16F877A + 2004 LCD + DS1307 RTC + DHT11 Sensor CCS C code
// http://ccspicc.blogspot.com/
// electronnote@gmail.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 = 8000000)
#include <lcd.c>
#use fast_io(B)
#use I2C(master, I2C1, FAST=100000)
#define DHT11_PIN PIN_B2                // Connection pin between DHT11 and mcu

short button_state, Time_out;
char time[] = "TIME:      :  :  ";
char calendar[] = "  /  /20  ";
unsigned int8 second, second10, minute, minute10,
               hour, hour10, date, date10, month, month10,
               year, year10, day, i, j ;
char message1[] = "Temperature: 00.0 C ";
char message2[] = "Humidity   : 00.0 % ";
unsigned int8 T_byte1, T_byte2, RH_byte1, RH_byte2, CheckSum, time_read ;
void ds1307_display(){
  second10  =  (second & 0x70) >> 4;
  second = second & 0x0F;
  minute10  =  (minute & 0x70) >> 4;
  minute = minute & 0x0F;
  hour10  =  (hour & 0x30) >> 4;
  hour = hour & 0x0F;
  date10  =  (date & 0x30) >> 4;
  date = date & 0x0F;
  month10  =  (month & 0x10) >> 4;
  month = month & 0x0F;
  year10  =  (year & 0xF0) >> 4;
  year = year & 0x0F;
  time[16]  = second  + 48;
  time[15]  = second10  + 48;
  time[13]  = minute  + 48;
  time[12]  = minute10  + 48;
  time[10]  = hour  + 48;
  time[9]  = hour10  + 48;
  calendar[9]  = year  + 48;
  calendar[8]  = year10  + 48;
  calendar[4]  = month + 48;
  calendar[3]  = month10 + 48;
  calendar[1]  = date + 48;
  calendar[0]  = date10 + 48;
  lcd_gotoxy(1, 1);                              // Go to column 1 row 1
  printf(lcd_putc, time);                        // Display time
  lcd_gotoxy(1, 2);                              // Go to column 1 row 2
  switch(day){
    case 1: lcd_putc("DATE:Sun"); break;
    case 2: lcd_putc("DATE:Mon"); break;
    case 3: lcd_putc("DATE:Tue"); break;
    case 4: lcd_putc("DATE:Wed"); break;
    case 5: lcd_putc("DATE:Thu"); break;
    case 6: lcd_putc("DATE:Fri"); break;
    case 7: lcd_putc("DATE:Sat"); break;}
  lcd_gotoxy(10, 2);                              // Go to column 9 row 2
  printf(lcd_putc, calendar);                    // Display calendar
}
void ds1307_write(unsigned int8 address, data_){
  i2c_start();                                   // Start I2C
  i2c_write(0xD0);                               // DS1307 address
  i2c_write(address);                            // Send register address
  i2c_write(data_);                        // Write data to the selected register
  i2c_stop();                                    // Stop I2C
}
void ds1307_read(){
   i2c_start();                                  // Start I2C
   i2c_write(0xD0);                              // DS1307 address
   i2c_write(0);                                 // Send register address
   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
}
int8 edit(int8 parameter, int8 xx, int8 yy){
  while(TRUE){
    if(input(PIN_B0)) button_state = 0;
    while(!input(PIN_B1)){
      parameter++;
      if(i == 1 && parameter > 23)
        parameter = 0;
      if(i == 2 && parameter > 59)
        parameter = 0;
      if(i == 3 && parameter > 31)
        parameter = 1;
      if(i == 4 && parameter > 12)
        parameter = 1;
      if(i == 5 && parameter > 99)
        parameter = 0;
      lcd_gotoxy(xx, yy);
      printf(lcd_putc,"%02u", parameter);
      delay_ms(200);}
    lcd_gotoxy(xx, yy);
    lcd_putc("  ");
    j = 0;
    while((input(PIN_B0) || button_state) && input(PIN_B1) && j < 5){
      j++;
     delay_ms(50);}
    lcd_gotoxy(xx, yy);
    printf(lcd_putc,"%02u", parameter);
    j = 0;
    while((input(PIN_B0) || button_state) && input(PIN_B1) && j < 5){
      j++;
      delay_ms(50);}
    if(!input(PIN_B0) && !button_state){
      button_state = 1; return parameter;}
  } 
}
void start_signal(){
  output_drive(DHT11_PIN);              // Configure connection pin as output
  output_low(DHT11_PIN);                // Connection pin output low
  delay_ms(25);
  output_high(DHT11_PIN);               // Connection pin output high
  delay_us(30);
  output_float(DHT11_PIN);              // Configure connection pin as input
}
short check_response(){
  delay_us(40);
  if(!input(DHT11_PIN)){                // Read and test if connection pin is low
    delay_us(80);
    if(input(DHT11_PIN)){               // Read and test if connection pin is high
      delay_us(50);
      return 1;
    }
  }
}
unsigned int8 Read_Data(){
  unsigned int8 i, k, _data = 0;     // k is used to count 1 bit reading duration
  if(Time_out)
    break;
  for(i = 0; i < 8; i++){
    k = 0;
    while(!input(DHT11_PIN)){                          // Wait until pin goes high
      k++;
      if (k > 100) {Time_out = 1; break;}
      delay_us(1);}
    delay_us(30);
    if(!input(DHT11_PIN))
      bit_clear(_data, (7 - i));                       // Clear bit (7 - i)
    else{
      bit_set(_data, (7 - i));                         // Set bit (7 - i)
      while(input(DHT11_PIN)){                         // Wait until pin goes low
      k++;
      if (k > 100) {Time_out = 1; break;}
      delay_us(1);}
    }
  }
  return _data;
}
void main(){
  port_b_pullups(TRUE);                           // Enable PORTB pull-ups
  output_b(0);
  set_tris_b(3);                                  // Configure RB0 & RB1 as inputs
  lcd_init();                                     // Initialize LCD module
  lcd_putc('\f');                                 // LCD clear
  while(TRUE){
    Time_out = 0;
    if(input(PIN_B0)) button_state = 0;
    if(!input(PIN_B0) && (!button_state)){
      button_state = 1;
      // Convert BCD to decimal
      minute = minute + minute10 * 10;
      hour = hour + hour10 * 10;
      date = date + date10 * 10;
      month = month + month10 * 10;
      year = year + year10 * 10;
      // End conversion
      i=1;
      hour = edit(hour, 10, 1);
      i=2;
      minute = edit(minute, 13, 1);
      while(TRUE){
        if(input(PIN_B0)) 
          button_state = 0;
        while(!input(PIN_B1)){
          day++;
          if(day > 7)
            day = 1;
          lcd_gotoxy(6, 2);                        // Go to column 6 row 2
          switch(day){
            case 1: lcd_putc("Sun"); break;
            case 2: lcd_putc("Mon"); break;
            case 3: lcd_putc("Tue"); break;
            case 4: lcd_putc("Wed"); break;
            case 5: lcd_putc("Thu"); break;
            case 6: lcd_putc("Fri"); break;
            case 7: lcd_putc("Sat"); break;}
          delay_ms(200);
        }
        lcd_gotoxy(6, 2);
        lcd_putc("   ");
        j = 0;
        while((input(PIN_B0)||button_state) && input(PIN_B1) && j < 5){
          j++;
          delay_ms(50);}
        lcd_gotoxy(6, 2);
        switch(day){
          case 1: lcd_putc("Sun"); break;
          case 2: lcd_putc("Mon"); break;
          case 3: lcd_putc("Tue"); break;
          case 4: lcd_putc("Wed"); break;
          case 5: lcd_putc("Thu"); break;
          case 6: lcd_putc("Fri"); break;
          case 7: lcd_putc("Sat"); break;}
        if(!input(PIN_B0) && (!button_state)){
          button_state = 1;
          break;}
        j = 0;
        while((input(PIN_B0)||button_state) && input(PIN_B1) && j < 5){
          j++;
          delay_ms(50);}
      }
      i=3;
      date = edit(date, 10, 2); 
      i=4;
      month = edit(month, 13, 2);
      i=5;
      year = edit(year, 18, 2);
      // 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
      ds1307_write(1, minute);
      ds1307_write(2, hour);
      ds1307_write(3, day);
      ds1307_write(4, date);
      ds1307_write(5, month);
      ds1307_write(6, year);
      ds1307_write(0, 0);
    }
    ds1307_read();                              // Read data from DS1307 RTCC
    ds1307_display();                           // Diaplay time and calendar
    if(((second10 * 10+second)>time_read)||((second10 * 10+second)==0 && time_read)){
      time_read = second10 * 10 + second;
      Start_signal();
      if(check_response()){                     // If there is response from sensor
        RH_byte1 = Read_Data();                 // read RH byte1
        RH_byte2 = Read_Data();                 // read RH byte2
        T_byte1 = Read_Data();                  // read T byte1
        T_byte2 = Read_Data();                  // read T byte2
        Checksum = Read_Data();                 // read checksum
        if(Time_out){                           // If reading takes long time
          lcd_gotoxy(21, 1);                    // Go to column 1 row 3
          lcd_putc("     Time Out!      ");
          lcd_gotoxy(21, 2);                    // Go to column 1 row 4
          lcd_putc("                    ");     // Clear 4th row
        }
        else{
          if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)){
            message1[13]  = T_Byte1 / 10  + 48;
            message1[14]  = T_Byte1 % 10  + 48;
            message1[16]  = T_Byte2 / 10  + 48;
            message2[13] = RH_Byte1 / 10 + 48;
            message2[14] = RH_Byte1 % 10 + 48;
            message2[16] = RH_Byte2 / 10 + 48;
            message1[17] = 223;                   // Degree symbol 
            lcd_gotoxy(21, 1);                    // Go to column 1 row 3
            printf(lcd_putc, message1);           // Display message1
            lcd_gotoxy(21, 2);                    // Go to column 1 row 4
            printf(lcd_putc, message2);           // Display message2
          }
          else{
            lcd_gotoxy(21, 1);                    // Go to column 1 row 3
            lcd_putc("  Checksum Error!   ");
            lcd_gotoxy(21, 2);                    // Go to column 1 row 4
            lcd_putc("                    ");     // Clear 4th row
          }
        }
      }
      else {
        lcd_gotoxy(21, 1);           // Go to column 1 row 3
        lcd_putc("    No response     ");
        lcd_gotoxy(21, 2);           // Go to column 1 row 4
        lcd_putc("  from the sensor   ");
      }
    }  
    delay_ms(50);
  }
}
Project Video: