Menu

all about electronic and microcontrollers

Tuesday, November 11, 2014

DS1307 [ RTC with Set Functions] & DS18B20 & MAX7219 [8 Digits]

Today I will show you how to display the values of RTC DS1307 and DS18B20 on six digits with seven segments driven by MAX7219. Obviously I designed a sort of menu (helped by three buttons) to be able to change the values on IC DS1307.
We have already explained, in previous projects, how works and communicate the IC DS1307 and MAX7219, so we will proceed further by developing electronic schematic and the software model.

Hardware setup:
I intend to display the clock and room temperature, on six digits with seven segment. The time will be displayed on digits for 5 seconds then for another 5 second it will be displayed the temperature and so on.
In my case, the clock and max7219 circuit are mounted separately on pcb.
Clock circuit is designed separately by me, but max7219 circuit is acquired from Mikroelektronika.
Electrical schematic is designed to include the complete circuit.
Physical realization is carried out on the breadboard with 2420 dots.




Video:

Circuit Diagram:
This schematic has a low difficulty level. Microcontroller used is PIC16F876A.
S1 is the master reset button, R1 is the resistor of pull-up button.
Crystal quartz used has 8Mhz.
ICSP connector is used to program the microcontroller (I use PICKIT2).
R1, R3, R5, R10 are pull-up resistors.
Diode D1 has a protective role.
All three buttons are part of: incrementing hour, incrementing minute and enter.
Communication between DS1307 and circuit board "breadboard" is established by five pins as follow (GND, SQW, SCL, SDA, 5VDC). SQW pin is not used in this project.
We used a battery of 3vcc to ensure the functioning of the internal clock of DS1307 IC's, even if it is disconnected from 5 VDC.
Communication between max7219 circuit and microcontroller is set by pins RC0 (CS), RC1 (CLK) and RC2 (MOSI) used for software SPI protocol.
IF you are planning to use the "Serial 7-Seg 8-Digit Board" from mikroelektronika, it is necessary to set the appropriate switches on the DIP switch SW1 to the ON position:
  • Switch 1- MOSI 
  • Switch 4 - SCK 
  • Switch 7 - CS 
Port RC7 ensure communication with DS18B20 sensor.
The capacitors C8-C11 serve as power filtering. Preferably is that the capacitors filters to be as near by ICs.


Electronic schematic is built in Eagle Cad, free version.

Software:
The program is written in mikroC Pro for PIC (version v6.4.0).
Below is my software version:
/*
'*******************************************************************************
'  Project name: Real Time Clock [DS1307 with Set Functions] & DS18B20 & max7219
'  Description:
'          With this experiment we wish to succed the next task:
'          Display on 6 digits with 7 segment leds, the clock and the room 
'          temperature (in Celsius Degree).
'          Setting the time helped by three buttons: hours, minutes and enter.
'
'          The sign "-" to the negative temperature and the hundreds for the
'          temperature value are displayed just if are used.
'          The time is displayed 5 second then he display the temperature value 
'          in Celsius Degrees for other 5 seconds and the loop goes to infinite.
'          Our clock, displays as shown below(but just in display time,
'          not in set mode).
'          Ex. of viewing in 7 segment display,6 digits :
'          Display time, mode:             Display temperature mode:
'               __________                         _________
'              |__24.59.59|     ~5 sec delay      |____23.6C|
'
'          Hardware configuration is:
'             IC ds1307 is connected with our microcontroller trough RC3=SCL,
'             RC4=SDA (I2C Connections), 
'             max7219 as follow:(CS at RC0, CLK at RC1 and MOSI(SDO) at RC2)
'             DS18B20 is assigned to RC7,
'             RB0,RB1 and RB3 are assigned to the buttons
'             Buttons Menu: RB0= Enter,  (It goes to set functions or exit from set functions)
'                           RB1= Minutes,
'                           RB2= Hours,
'
'  Written by:
'          Aureliu Raducu Macovei, 2014.
'  Test configuration:
'    MCU:                        PIC16F876A;
'    Test.Board:                 WB-106 Breadboard 2420 dots;
'    SW:                         MikroC PRO for PIC 2013 (version v6.4.0);
'  Configuration Word:
'    Oscillator:                 HS (8Mhz)on pins 9 and 10;
'    Watchdog Timer:             OFF;
'    Power up Timer:             OFF;
'    Browun Out Detect:          ON;
'    Low Voltage Program:        Disabled;
'    Data EE Read Protect:       OFF;
'    Flash Program Write:        Write Protection OFF;
'    Background Debug:           Disabled;
'    Code Protect:               OFF
'*******************************************************************************
*/

// Software SPI module connections for max7219
sbit SoftSpi_SDI at RC6_bit;
sbit SoftSpi_SDO at RC2_bit;                   // MOSI
sbit SoftSpi_CLK at RC1_bit;
sbit Chip_Select at RC0_bit;

sbit SoftSpi_SDI_Direction at TRISC6_bit;
sbit SoftSpi_SDO_Direction at TRISC2_bit;
sbit SoftSpi_CLK_Direction at TRISC1_bit;
sbit Chip_Select_Direction at TrisC0_bit;
// End Software SPI module connections for max7219

const unsigned short TEMP_RESOLUTION = 12;     //This is resolution for ds18b20
unsigned temp;

unsigned sec, min1, hr, week_day, day, mn, year;
unsigned short mask(unsigned short num)
{
 switch (num)               // Define switch cases
 {
  case  0 : return 0x7E;    // 0 for those values please study the datasheet max7219
  case  1 : return 0x30;    // 1
  case  2 : return 0x6D;    // 2
  case  3 : return 0x79;    // 3
  case  4 : return 0x33;    // 4
  case  5 : return 0x5B;    // 5
  case  6 : return 0x5F;    // 6
  case  7 : return 0x70;    // 7
  case  8 : return 0x7F;    // 8
  case  9 : return 0x7B;    // 9
  case 10 : return 0x01;    // Symbol '-'
  case 11 : return 0x00;    // Blank
  case 12 : return 0x80;    // Comma "," symbol
  case 13 : return 0x43;    // C
  } //case end
}

void max7219_init()
{
 Chip_Select = 0;           // SELECT MAX
 Soft_Spi_write(0x09);      // Decode-Mode Register
 Soft_Spi_write(0x00);      // No decode for digits 7–0
 Chip_Select = 1;           // DESELECT MAX
 
 Chip_Select = 0;           // SELECT MAX
 Soft_Spi_write(0x0A);      // Intensity Register Format
 Soft_Spi_write(0x01);      // Segment luminosity intensity set to 3/32
 Chip_Select = 1;           // DESELECT MAX

 Chip_Select = 0;           // SELECT MAX
 Soft_Spi_write(0x0B);      // Scan-Limit Register Format
 Soft_Spi_write(0x05);      // Display digits 0 1 2 3 4 5
 Chip_Select = 1;           // DESELECT MAX

 Chip_Select = 0;           // SELECT MAX
 Soft_Spi_write(0x0C);      // Shutdown Register Format
 Soft_Spi_write(0x01);      // Normal Operation
 Chip_Select = 1;           // DESELECT MAX

 Chip_Select = 0;           // SELECT MAX
 Soft_Spi_write(0x00);      // No-Op
 Soft_Spi_write(0xFF);      // No test
 Chip_Select = 1;           // DESELECT MAX
}

char minute2,hour2;
void max7219_display_set_mode(unsigned minute2, unsigned hour2)
{
 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(6);                              // digit 6
 Soft_Spi_write(mask((hour2/10)%10));            // assign tens of hours
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(5);                              // digit 5
 Soft_Spi_write ((mask(hour2%10))+ mask(12));    // assign units of hours
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(4);                              // digit 4
 Soft_Spi_write(mask((minute2/10)%10));          // assign tens of minutes
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(3);                              // digit 3
 Soft_Spi_write((mask(minute2%10))+mask(12));    // assign units of minutes
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;           // select max7219
 Soft_Spi_write(2);         // digit 2
 Soft_Spi_write (0);        // set as blank
 Chip_Select = 1;           // deselect max7219

 Chip_Select = 0;           // select max7219
 Soft_Spi_write(1);         // digit 1
 Soft_Spi_write (0);        // set as blank
 Chip_Select = 1;           // deselect max7219
}

void max7219_display (unsigned sec, unsigned min, unsigned hr)
{
 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(6);                              // digit 6
 Soft_Spi_write(mask((hr/10)%10));               // assign tens of hours
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(5);                              // digit 5
 Soft_Spi_write ((mask(hr%10))+ mask(12));       // assign units of hours
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(4);                              // digit 4
 Soft_Spi_write(mask((min/10)%10));              // assign tens of minutes
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(3);                              // digit 3
 Soft_Spi_write((mask(min%10))+mask(12));        // assign units of minutes
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(2);                              // digit 2
 Soft_Spi_write (mask((sec/10)%10));             // assign tens of seconds
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(1);                              // digit 1
 Soft_Spi_write (mask(sec%10));                  // assign units of seconds
 Chip_Select = 1;                                // deselect max7219
}

//-----Reads time and date information from RTC (DS1307)
void Read_Time(unsigned *sec, unsigned *min, unsigned *hr, unsigned *week_day, 
               unsigned *day, unsigned *mn, unsigned *year)
{
 I2C1_Start();
 I2C1_Wr(0xD0);
 I2C1_Wr(0);
 I2C1_Repeated_Start();
 I2C1_Wr(0xD1);
 *sec =I2C1_Rd(1);
 *min =I2C1_Rd(1);
 *hr =I2C1_Rd(1);
 *week_day =I2C1_Rd(1);
 *day =I2C1_Rd(1);
 *mn =I2C1_Rd(1);
 *year =I2C1_Rd(0);
 I2C1_Stop();
}//~

//-----------------start write time routine------------------
void Write_Time(unsigned minute, unsigned hour)
{
 unsigned tmp1, tmp2;
 
 tmp1 = minute / 10;           // assign values from variables
 tmp2 = minute % 10;           // assign values from variables
 minute = tmp1 * 16 + tmp2;    // assign values from variables

 tmp1 = hour / 10;             // assign values from variables
 tmp2 = hour % 10;             // assign values from variables
 hour = tmp1 * 16 + tmp2;      // assign values from variables

 I2C1_Start();          // issue start signal
 I2C1_Wr(0xD0);         // address DS1307
 I2C1_Wr(0);            // start from word at address (REG0)
 I2C1_Wr(0x80);         // write $80 to REG0. (pause counter + 0 sec)
 I2C1_Wr(minute);       // write minutes word to (REG1)
 I2C1_Wr(hour);         // write hours word (24-hours mode)(REG2)
 I2C1_Wr(0x00);         // write 6 - Saturday (REG3)
 I2C1_Wr(0x00);         // write 14 to date word (REG4)
 I2C1_Wr(0x00);         // write 5 (May) to month word (REG5)
 I2C1_Wr(0x00);         // write 01 to year word (REG6)
 I2C1_Wr(0x80);         // write SQW/Out value (REG7)
 I2C1_Stop();           // issue stop signal

 I2C1_Start();          // issue start signal
 I2C1_Wr(0xD0);         // address DS1307
 I2C1_Wr(0);            // start from word at address 0
 I2C1_Wr(0);            // write 0 to REG0 (enable counting + 0 sec)
 I2C1_Stop();           // issue stop signal
}
//-----------------end write time routine------------------

//-------------------- Formats date and time
void Transform_Time(unsigned *sec, unsigned *min, unsigned *hr, 
                    unsigned *week_day, unsigned *day, unsigned *mn, unsigned *year)
{
 *sec  =  ((*sec & 0x70) >> 4)*10 + (*sec & 0x0F);
 *min  =  ((*min & 0xF0) >> 4)*10 + (*min & 0x0F);
 *hr   =  ((*hr & 0x30) >> 4)*10 + (*hr & 0x0F);
 *week_day =(*week_day & 0x07);
 *day  =  ((*day & 0xF0) >> 4)*10 + (*day & 0x0F);
 *mn   =  ((*mn & 0x10) >> 4)*10 + (*mn & 0x0F);
 *year =  ((*year & 0xF0)>>4)*10+(*year & 0x0F);
}//~

void blink_min()
{
 Chip_Select = 0;               // select max7219
 Soft_Spi_write(4);             // digit 4
 Soft_Spi_write(0);             // set as blank
 Chip_Select = 1;               // deselect max7219

 Chip_Select = 0;               // select max7219
 Soft_Spi_write(3);             // digit 3
 Soft_Spi_write(0);             // set as blank
 Chip_Select = 1;

 delay_ms(50);                               // 50ms delay
 max7219_display_set_mode(minute2,hour2);    // display those values
 delay_ms(50);                               // 50ms delay
}
void blink_hr()
{
 Chip_Select = 0;               // select max7219
 Soft_Spi_write(6);             // digit 6
 Soft_Spi_write(0);             // set as blank
 Chip_Select = 1;               // deselect max7219

 Chip_Select = 0;               // select max7219
 Soft_Spi_write(5);             // digit 5
 Soft_Spi_write(0);             // set as blank
 Chip_Select = 1;               // deselect max7219

 delay_ms(50);                               // 50ms delay
 max7219_display_set_mode(minute2,hour2);    // display those values
 delay_ms(50);                               // 50ms delay
}

char setuptime=0;
unsigned count=0;
void Press_Switch()
{
 if(button(&portb,0,1,0))        // check if button RB0 is pressed
 {
  Delay_ms(200);
  setuptime = !setuptime;        // switch that value;

  if(setuptime)
  {
  hour2=hr;
  minute2=min1;
  max7219_display_set_mode(minute2,hour2);   // display those values
  }
  else
  {
   hr=hour2;
   min1=minute2;
   Write_Time(min1,hr);
   max7219_display_set_mode(minute2,hour2);
  }
 }
 
 if(Setuptime)
 {
  if(button(&portb,1,1,0))
  {
   Delay_ms(150);
   minute2++;
   if(minute2 > 59)
   minute2=0;
   blink_min();
   }
  if(button(&portb,2,1,0))
  {
   Delay_ms(150);
   hour2++;
   if(hour2 > 23)
   hour2=0;
   blink_hr();
   }
  }
}

// Starts ds18b20 declarations
void ds18b20(unsigned int temp2write)
{
 const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
 unsigned temp_whole;
 unsigned int temp_fraction;
 unsigned short isNegative = 0x00;
 // Check if temperature is negative
 if (temp2write & 0x8000)
 {
  temp2write = ~temp2write + 1;
  isNegative = 1;
  }
 // Extract temp_whole
 temp_whole = temp2write >> RES_SHIFT ;

 // Extract temp_fraction and convert it to unsigned int
 temp_fraction  = temp2write << (4-RES_SHIFT);
 temp_fraction &= 0x000F;
 temp_fraction *= 625;          // 625 for ds18b20 and 5000 for ds1820;

 Chip_Select = 0;               // select max7219
 Soft_Spi_write(1);             // digit 1
 Soft_Spi_write(mask(13));      // write C symbol
 Chip_Select = 1;               // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(2);                              // Set digit number 3
 Soft_Spi_write(mask(temp_fraction /1000));      // assigne as fraction
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(3);                              // Set digit number 3
 Soft_Spi_write((mask(temp_whole%10))+mask(12)); // Assigne as ones
 Chip_Select = 1;                                // deselect max7219

 Chip_Select = 0;                                // select max7219
 Soft_Spi_write(4);                              // Set digit number 4
 Soft_Spi_write (mask((temp_whole/10)%10));      // Assigne as tens
 Chip_Select = 1;                                // deselect max7219
  
 if (isNegative == 1)
 {
  Chip_Select = 0;               // select max7219
  Soft_Spi_write(5);             // Set digit number 5
  Soft_Spi_write(mask(10));      // Assigne as symbol "-"
  Chip_Select = 1;               // deselect max7219
  }
 else
 {
  if(isNegative ==0 && temp_whole/100==0)
  {
   Chip_Select = 0;               // select max7219
   Soft_Spi_write(5);             // Set digit number 5
   Soft_Spi_write(mask(11));      // Assign as blank
   Chip_Select = 1;               // deselect max7219
   }
  else
  {
   Chip_Select = 0;                         // select max7219
   Soft_Spi_write(5);                       // Set digit number 5
   Soft_Spi_write(mask(temp_whole/100));    // Assign the hundreds
   Chip_Select = 1;                         // deselect max7219
   }
  }
  
 Chip_Select = 0;                 // select max7219
 Soft_Spi_write(6);               // Set digit number 6
 Soft_Spi_write(0);               // Assign value 0
 Chip_Select = 1;                 // deselect max7219
}// End ds18b20 declarations

void interrupt()
{
 if(setuptime)
 count=0;
 else
 count++;                  // Interrupt causes count to be incremented by 1
 TMR0 = 0;                 // Timer TMR0 is returned its initial value
 INTCON = 0x20;            // Bit T0IE is set, bit T0IF is cleared
}

void main() 
{
 CMCON  |= 7;                  // Disable Comparators
 OPTION_REG = 0x84;            // Prescaler Rate Selected at 1:32;
 TMR0 = 0;                     // Reset timer;
 INTCON = 0xA0;                // Disable interrupt PEIE,INTE,RBIE,T0IE

 Chip_Select_Direction = 0;    // Set RC0 pin as output
 Soft_Spi_init();              // Initialize software SPI module
 max7219_init();               // initialize  max7219
 I2C1_Init(100000);            // initialize I2C

 while (1)                     // and here, our while loope
 {
  Press_Switch();
     
  if(!setuptime)
  {
   if(count<=1400)                    // ~ 5 seconds
   {
    Read_Time(&sec,&min1,&hr,&week_day,&day,&mn,&year);      // read time from RTC(DS1307)
    Transform_Time(&sec,&min1,&hr,&week_day,&day,&mn,&year); // format date and time
    max7219_display(sec,min1, hr);
    }
   else
   {
    if(count>1400)                     // ~ 5 seconds
    {
     //Perform temperature reading
     Ow_Reset(&PORTC, 7);          // Onewire reset signal
     Ow_Write(&PORTC, 7, 0xCC);    // Issue command SKIP_ROM
     Ow_Write(&PORTC, 7, 0x44);    // Issue command CONVERT_T
     
     Ow_Reset(&PORTC, 7);
     Ow_Write(&PORTC, 7, 0xCC);    // Issue command SKIP_ROM
     Ow_Write(&PORTC, 7, 0xBE);    // Issue command READ_SCRATCHPAD

     temp =  Ow_Read(&PORTC, 7);   // Next Read Temperature and Read Byte 0 from Scratchpad
     // Then read Byte 1 from Scratchpad and shift 8 bit left and add the Byte 0
     temp = (Ow_Read(&PORTC, 7) << 8) + temp;
     ds18b20(temp);                  //Format and display result on digits.
     }
    }
   if(count>2800)
   count = 0;
   }
  }
}

Wednesday, July 23, 2014

GSM Click (Warning Action via SMS)

OK Folks, we will continue our experiments with this GSM module, and we will show how we can send an warning message. Obviously we will create the warning situation trough a button, but of course it can be changed with everything else for example a couple of movement sensors, etc.

Hardware setup:
After we spoke "the given situation" is set by a button set on RD7. The info led set on RB7 show the situation as follow:
  • After initialize, it flash for 2 seconds.
  • After the message is sent, it flashing ten times.
Some adjustments are needed on Easypic v7 motherboard to establish our connections. The adjustments are as follow:
  1. Turn on portB LEDs on SW3 (SW3.2).
  2. Place GSM click board into mikroBUS socket 1.
  3. Place power selection jumper (J5) into 3.3V position.


Video:

For hardware details, please study the EasyPic v7 and Telit GL865 datasheets.

Software:
The program is written in mikroC Pro for PIC (version v6.4.0).
Below is my software version:

warning action.c
/*
 * Project name:
     Warning Action via SMS.
 * Copyright:
     (c) Macovei Aureliu Raducu, 2014.
 * Revision History:
     1.1
 * Description:
     This is an Warning Action via SMS project who are able to send a 
     warning message for a given situation.
     In this experiment "the given situation" is one button set on RD7.
     The info led set on RB7 show the situation as follow:
         - After initialize, it flash for 2 seconds.
         - After the message is sent, it flashing ten times.
 * Test configuration:
     MCU:             PIC18F45k22
                      http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf
     Ddev.board:       EasyPIC7
                      http://www.mikroe.com/easypic/
     Oscillator:      HS-PLL 32.0000 MHz, 8.0000 MHz Crystal
     Ext. Modules:    GSM click
                      http://www.mikroe.com/click/gsm/
     SW:              mikroC PRO for PIC
                      http://www.mikroe.com/mikroc/pic/
 * NOTES:
     Adjust the number to which the SMS will be sent and recompile the project
     now have HEX file ready for programming.
*/
// Configure phone number on which the SMS warning will be sent
// Use international code + your phone number
char phoneNumber1[] = "your number1";    // This is the first number
char phoneNumber2[] = "your number2";    // This is the second number

#include "Telit_GL865.h"

// Pin definitions
sbit LD1 at LATB7_bit;                    // Set LED1 at port RB7
sbit LD1_Direction at TRISB7_bit;         // Set LED1 at port RB7

sbit T1 at RD7_bit;                       // Set Button at port RD7.
sbit T1_Direction at TRISD7_bit;          // Set Button at port RD7
// Pin definitions

void Delay_LD(){
  Delay_ms(100);                          // Led Delay 100ms
}

// Simple LED action indicating a button press
void Blink(){
  LD1 = 1;
  Delay_LD();
  LD1 = 0;
  Delay_LD();
  LD1 = 1;
  Delay_LD();
  LD1 = 0;
}

void check_status(){
 LD1 = 1;
 delay_ms(2000);           // Add 2s delay
 LD1 = 0;
}

void MCU_Init()
{
  ANSELA = 0;              // Set all ports as digital
  ANSELB = 0;
  ANSELC = 0;
  ANSELD = 0;
  ANSELE = 0;              // Set all ports as digital

  // GSM definitions
  PWRMON_Direction = 1;
  RST = 0;
  RST_Direction = 0;
  // GSM definitions

  // Button on RD7;
  T1_Direction = 1;             // Button pins are set as input
  // Button on RD7;

  // Led Indicator set on RB7
  LD1 = 0;                      // Turn OFF the LED
  LD1_Direction = 0;            // Set direction for LEDS
  // Led Indicator set on RB7

  UART1_Init(9600);       // Using default baud rate 9600
  Delay_ms(200);          // Wait a while till the GSM network is configured
}

// main function
void main() {
  MCU_Init();                   // Initialize MCU pins and modules
  if (GSM_Init() == 0)          // Initialize GSM module, if AT is received LED1 is ON
  check_status();               // Shown by LD1

  while(1){                     // Endless loop
  if (T1 == 1){                 // With Button1 we activate "the given situation"
    SendSMS(phoneNumber1);      // First things first, send the SMS
    delay_ms(3500);
    SendSMS(phoneNumber2);
    Blink();Blink();            // Blink ten times, after message sent
    Blink();Blink();
    Blink();
    }
  }
}

telite_GL865.c
#include "Telit_GL865.h"

void GSMcmd(char *ch)                 // GSM commands
{
 while(*ch)
 if(UART1_Tx_Idle() == 1)
 UART1_Write(*ch++);
 UART1_Write(0x0D);                  // Send CR - command terminate character
}

char GSM_Init(){
  char cmdTO = 0, readTO = 0;         // TimeOut counters
  char gsmRes[26]={0}, resCnt = 0;    // Response from GSM module
  while(PWRMON != 0){};               // Wait for POWER to be generated by the GSM module
  Delay_ms(3500);
  while(cmdTO++ < 5){                 // Check the communication by sending AT command for few times
    UART1_Read();
    GSMcmd("AT");                     // AT commamd.
    while(readTO++ < 10){
      Delay_us(300);                  // 1/9600 * 3 = 312.5us takse a UART HW buffer to fill up.
      while(UART1_Data_Ready()){      // Place the received bytes to buffer array(gsamRes[])
        readTO = 0;
        gsmRes[resCnt++] = UART1_Read();
        gsmRes[resCnt] = 0;
        if (resCnt == 25){
         resCnt = 0;
        }
      }
    }
    readTO = 0;
    if (strstr(gsmRes,"AT\r\r\nOK\r\n")){   // Check for occurrence of expected string
      GSMcmd("ATE1");                       // Few more GSM module configuration commands.
      GSMcmd("AT+CMGF=1");                  // Select Text Mode.
      GSMcmd("AT#GPIO=5,0,2");              // Set GPIO5 pin as RFTXMON OUTPUT
      return 0;
    }
  }
  return 1;
}

void SMSbegin(char *phoneNo){               // Sending an SMS requires three easy steps
                                            // 1. Begin with SMS command  +CMGS
  UART1_Write_Text("AT+CMGS=\"");           // AT+CMGS="+39xxxxxxxxxx"[CR]
  UART1_Write_Text(phoneNo);
  GSMcmd("\"");
}

void SMSwrite(char *text){
  UART1_Write_Text(text);                   // 2. After SMS command, SMS text is expected
}

void SMSsend(){
  GSMcmd("\x1A");     // 3. At the end CTRL + Z is sent as terminating character
}
// Function sends an SMS to predefined number with predefined text(warning)
void SendSMS(char *phone){
  SMSbegin(phone);
  Delay_ms(100);
  SMSwrite("WARNING!!\r\n");                            // This is our message line1
  SMSwrite("We have a situation here!\r\n");            // This is our message line2
  SMSwrite("(someone somehow has press the button)");   // This is our message line3
  SMSsend();
}

telite_GL865.h
// GSM definitions
sbit PWRMON           at PORTA.B2;
sbit PWRMON_Direction at TRISA2_bit;
sbit RST              at LATE1_bit;
sbit RST_Direction    at TRISE1_bit;
// GSM definitions

char GSM_Init();
void SendSMS(char *phone);

Monday, July 21, 2014

GSM Click (Temperature & Controll via SMS)

Today I will share with you an experiment made with the module Telit GL856-Quad wich is mounted on a pcb board called "GSM Click Board" designed by Mikroelektronika. The GSM click board is attached to the EasyPIC v7 motherboard trough mikroBUS™ host connector, making our hardware platform.


Telit GL865 Module.

Features:
  1. The Telit GL865-Quad module family can be controlled via the serial interface using the standard AT commands. 
  2. Ultra Compact; GPRS Class 10; LCC Package
  3. Quad Band GSM/GPRS 850/900/1800/1900MHz
  4. Embedded TCP/IP Stack
  5. Supply voltage range: 3.22 - 4.5V DC (3.8V DC recommended)
  6. Power consumption (typical values): Power off: <5 uA
  7. Idle (registered, power saving): 1.5 mA @ DRX=9
  8. Dedicated mode: 230mA @ max power level
  9. GPRS class 10: 360 mA @ max power level
  10. Sensitivity: 108 dBm (typ.) @ 850/900MHz; 106 dBm (typ.) @ 1800/1900MHz.
As can be seen from it's datasheet, the communications are achieved in UART mode (TX,RX), with a Baud rate from 300 to 115,200bps.

Hardware setup:
In example, "FAN1ON" command turns ON the output on RD0, "FAN2OFF" turns OFF the output on RD1. In this experiment we used two leds instead fans (just to prove the output commands.)
PORT RD0 and RD1 leads two digital output and RA0 one analog input.
Some adjustments are needed on Easypic v7 motherboard to establish our connections:
The adjustments are as follow:
  1. Turn on portD LEDs on SW3 (SW3.4).
  2. Place GSM click board into mikroBUS socket 1.
  3. Place power selection jumper (J5) into 3.3V position.





Video:

Pin Configurations.

For hardware details, please study the EasyPic v7 and Telit GL865 datasheets.

Software:
The program is written in mikroC Pro for PIC (version v6.0.0).
Below is my software version:
/*
 * Project name:
    GSM Click (Temperature & Controll via SMS).
 * Copyright:
     Macovei Aureliu Raducu, 2014.
 * Description:
     Program uses GSM module GL865 for sending and receiving SMS.
     The scenario of this experiment is as follows:
     User can interrogate the EasyPIC v7 development board via SMS, and receive
     the status situation of the motherboard.
     Port RD0 and RD1 are used to control two Fans and port RA0 is used to 
     measure the temperature of LM35 sensor.
     As a bonus the temperature is displayed in both format, Celsius and Fahrenheit.
 * Test configuration:
     MCU:             PIC18F45K22
                      http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf
     dev.board:       EasyPIC7
                      http://www.mikroe.com/easypic/
     Oscillator:      HS-PLL 32.0000 MHz, 8.0000 MHz Crystal
     ext. modules:    gsm click : 
                      http://www.mikroe.com/click/gsm/
                      Telit GL865-QUAD
                      http://www.telit.com/en/products.php?p_id=3&p_ac=show&p=110
                      LM35 (Analog temperature sensor)
                      http://www.ti.com/lit/ds/symlink/lm35.pdf
     SW:              mikroC PRO for PIC
                      http://www.mikroe.com/mikroc/pic/
 * NOTES:
     - Due different mobile operators some adjustments may be required, please consult Telit AT commands
       reference guide at http://www.telit.com/module/infopool/download.php?id=542
     - The SMS messages (which GL865 receives) contain commands: "FAN1ON" or "FAN1OFF", "FAN2ON" or "FAN2OFF"
       and "Status?" (it is case sensitive and without quotes).
       In example, "FAN1ON"  command turns ON the output on RD0, "FAN2OFF" turns OFF the output on RD1.
       In this experiment we used two leds instead fans (just to prove the output commands.)
       You can send only the "Status?" inquiry via your SMS (or add it to the SMS containg relay commands) 
       and then you'll receive an info about the state of EasyPic7 motherboard.
       PORT RD0 and RD1 leads two digital output and RA0 one analog input.
       An example of one control message is below:
       "FAN1ON FAN2OFF Status?"  (Note that there is no need for separation chars (spaces in this case)).
       Valid message is also: "FAN2OFFFAN1ONStatus?"; just be careful about the case of letters.

     - Turn on portD LEDs on SW3 (SW3.4).
     - Place GSM click board into mikroBUS socket 1.
     - Place power selection jumper (J5) into 3.3V position.
 */

//  Set VREF according to the voltage reference for LM35:
//  5.00 - power supply jumper set to 5V position (reference = 5V)
//  3.30 - power supply jumper set to 3.3V position (reference = 3.3V)
const unsigned short VREF = 3.30;

// Set of basic AT commands
const char atc0[] = "AT";                        // Every AT command starts with "AT"
const char atc1[] = "ATE0";                      // Disable command echo
const char atc2[] = "AT+CMGF=1";                 // TXT messages
      char atc3[] = "AT+CMGS=\"";                // sends SMS to desired number
const char atc4[] = "AT+CMGR=1";                 // Command for reading message from location 1 from inbox
const char atc5[] = "AT+CMGD=1,4";               // Erasing all messages from inbox
const char atc6[] = "AT+CMGL=\"ALL\"";           // Check status of received SMS
const char atc7[] = "AT#SLED=2";                 // Activate STAT_LED pin
const char atc8[] = "AT#SLEDSAV";                // Save previous command
const char atc9[] = "AT#GPIO=5,0,2";             // Set GPIO5 pin as RFTXMON OUTPUT (the GPIO5 pin is set
                                                 // in output direction; the setting is saved at module power off.)

// Responses to parse
const GSM_OK                       = 0;
const GSM_Ready_To_Receive_Message = 1;
const GSM_ERROR                    = 2;
const GSM_UNREAD                   = 3;
//

// Telit GL865 Module settings
sbit PWRMON at PORTA.B2;
sbit PWRMON_Direction at TRISA2_bit;

sbit RTS at LATE0_bit;
sbit RTS_Direction at TRISE0_bit;

sbit GL865_ON_OFF at LATE1_bit;
sbit GL865_ON_OFF_Direction at TRISE1_bit;
//

//Fan Connections
sbit FAN1 at LATD0_bit;
sbit FAN2 at LATD1_bit;

sbit FAN1_Direction at TRISD0_bit;
sbit FAN2_Direction at TRISD1_bit;
//

// Temperature sensor connections
sbit LM35 at PORTA.B0;
sbit LM35_Direction at TRISA0_bit;
//

// SMS Message string
char SMS_Message[300];

// LM35 data string
char LM35_dataC[15];
char LM35_dataF[15];
//
// phone number string
char phone_number[20];

// State machine control variables
char gsm_state = 0;
char response_rcvd = 0;
short responseID = -1, response = -1;
char gsm_number = 0;
char Unread_flag;
char status_req = 0; // Status request variable

// Send command or data to the Telit GL865 Module - (const)
void GL865_Send(const char *s)
{
// Send command or data string
   while(*s) {
    UART1_Write(*s++);
   }
// Terminatation by CR
   UART_Wr_Ptr(0x0D);
}

// Send command or data to the Telit GL865 Module - (RAM)
void GL865_Send_Ram(char *s1)   //
{
// Send command or data string
   while(*s1) {
    UART_Wr_Ptr(*s1++);
   }
// Terminatation by CR
   UART_Wr_Ptr(0x0D);
}

// Get GSM response, if there is any
short Get_response() {
    if (response_rcvd) {
      response_rcvd = 0;
      return responseID;
    }
    else
      return -1;
}

// Wait for GSM response (infinite loop)
void Wait_response(char rspns) {
char test = 1;

  while (test){
  test = Get_response();
  if ((test == rspns) || (test == GSM_ERROR))
    test = 0;
  else
    test = 1;
  }
}

// Compose Status SMS
unsigned ComposeMessage(char* Message);

// Send Status SMS
void Send_Msg(char* Msg){
  char atc[33];

  atc[0] = 0;                        // clear atc string
  strcat(atc, atc3);                 // atc3 command for sending messages
  strcat(atc, phone_number);         // add phone number
  strcat(atc, "\"");                 // complete AT command
  GL865_Send_Ram(atc);               // send AT command for SMS sending
  Wait_response(GSM_Ready_To_Receive_Message); // Wait for appropriate ready signal

  GL865_Send_Ram(Msg);               // Send message content
  UART_Wr_Ptr(0x1A);                 // Send CTRL + Z as end character
  UART_Wr_Ptr(0x0D);                 // Send CR
  Wait_response(GSM_OK);             // Wait OK as confirmation that the message was sent
}

// Send status SMS to the cell phone number defined by the atc3 const string
void Send_Status(){
 ComposeMessage(SMS_Message);
 Send_Msg(SMS_Message);
}

// 5sec pause
void Wait(){
   Delay_ms(5000);
}

// Main
void main(){
  ANSELA = 0;             // Set all ports as digital
  ANSELB = 0;
  ANSELC = 0;
  ANSELD = 0;
  ANSELE = 0;

  SLRCON = 0;             // Set output slew rate on all ports at standard rate

  ANSELA |= 0x01;         // Configure RA0 pins as analog
  LM35_Direction = 1;     // Configure RA0 pin as input

  //Initialy, FAN's are turned off
  FAN1=0;
  FAN2=0;
  
  FAN1_Direction=0;
  FAN2_Direction=0;
  //

// Setup interrupts
  RC1IE_bit = 1;          // Enable Rx1 intterupts
  PEIE_bit = 1;           // Enable peripheral interrupts
  GIE_bit  = 1;           // Enable global interrupts
//

  // Initial state of Telit GL865 Module pins
  PWRMON_Direction = 1;   // Make PWRMON(RA2) as input

  RTS = 0;                //  Set RTS pin to zero (we will use only RX and TX)
  RTS_Direction  = 0;

  GL865_ON_OFF = 0;
  GL865_ON_OFF_Direction = 0;
  //
  
// Turn on the GM865 module
  GL865_ON_OFF = 1;       // hardware reset
  Delay_ms(2500);         // hold it at least for two seconds
  GL865_ON_OFF = 0;
//

  UART1_Init(9600);
  ADC_Init();

  Wait();                 // Wait a while till the GSM network is configured

// Negotiate baud rate
  while(1) {
    GL865_Send(atc0);                 // Send "AT" string until GSM862 sets up its baud rade
    Delay_ms(100);                    // and gets it correctly
    if (Get_response() == GSM_OK)     // If GSM862 says "OK" on our baud rate we program can continue
      break;
  }

 GL865_Send(atc1);                    // Disable command echo
 Wait_response(GSM_OK);

 GL865_Send(atc2);                    // Set message type as TXT
 Wait_response(GSM_OK);
 
 GL865_Send(atc7);                    // Activate STAT_LED pin
 Wait_response(GSM_OK);
 
 GL865_Send(atc8);                    // Then save it
 Wait_response(GSM_OK);
 
 GL865_Send(atc9);                    // Set GPIO5 pin as RFTXMON OUTPUT
 Wait_response(GSM_OK);

 while(1){
   GL865_Send(atc5);             // Delete all messages (if any)
   if (get_response() == GSM_OK) // If messages are deleted
     break;                      // break from while
   Delay_ms(500);
 }
  // infinite loop
  while(1) {
    GL865_Send(atc6);        // Read status of the messages and read message it self
    Delay_ms(100);           // Wait until the message is read

    while(1) {
      GL865_Send(atc0);      // Wait until the module is ready
      Delay_ms(50);
      if (Get_response() == GSM_OK)
        break;
    }
    
    if (Unread_flag){
      while(1) {
        GL865_Send(atc0);    // Wait until the module is ready
        Delay_ms(50);
        if (Get_response() == GSM_OK)
          break;
      }

      if (status_req){       // Send status SMS if it's been requested
        status_req = 0;
        Send_Status();
      }

      Unread_flag = 0;
    }

    while(1){
      GL865_Send(atc5);  // Delete all messages (if any)
      Delay_ms(50);
      if (get_response() == GSM_OK) // If messages are deleted
        break;           // break from while
      Delay_ms(50);
      if (Unread_flag){  // if we have received message in mean time
        Unread_flag = 0;
        break;           // break from while
      }
    }
    Wait();
  }
}

/******************************************************************************/

// Compose Status SMS
unsigned ComposeMessage(char* Message){
  unsigned int adc_value1 = 0;
  float Celsius_format, Fahrenheit_format;
 
  RC1IE_bit = 0;                // Disable Rx1 intterupts

  Message[0] = '\0';
//================================================================
  // SMS header
  strcat(Message, "EasyPIC7 Info:");
  strcat(Message, "\r\n");              // Add new line (CR + LF)
  //
  if(FAN1)
     strcat(Message, "FAN1: ON");
  else
     strcat(Message, "FAN1: OFF");
  strcat(Message, "\r\n");              // Add new line (CR + LF)
  
  if(FAN2)
     strcat(Message, "FAN2: ON");
  else
     strcat(Message, "FAN2: OFF");
  strcat(Message, "\r\n");              // Add new line (CR + LF)
//================================================================

  // Adding Temperature values to the SMS
  adc_value1 = ADC_Get_Sample(0);                 // RA0
  Celsius_format = (adc_value1 * VREF)/10.240;    // Calculate temperature in Celsuis
  FloatToStr(Celsius_format, LM35_dataC);
  LM35_dataC[4] =0;                               // Use just four string value

  strcat(Message, "TEMP: +");
  strcat(Message, LM35_dataC);
  strcat(Message, "'C");                          // Celsius degree symbol
  strcat(Message, " / +");                        // Delimitation and + symbol
  
  Fahrenheit_format = (Celsius_format *9/5)+32;   // °F =°C*9/5 + 32 transformation formula
  FloatToStr(Fahrenheit_format, LM35_dataF);
  LM35_dataF[4] =0;                               // Use just four string value
  strcat(Message, LM35_dataF);
  strcat(Message, "'F");
  strcat(Message, "\r\n");                        // Add new line (CR + LF)
  // SMS footer
  strcat(Message, "End.");
  strcat(Message, "\r\n");                        // Add new line (CR + LF)
  //
  RC1IE_bit = 1;                                  // Enable Rx1 intterupts

  return strlen(Message);
}

// state machine
// Reading the data from UART in the interuppt routine
void interrupt(){
char tmp,i;

  if (RCIF_bit == 1) {                           // Do we have uart rx interrupt request?
    tmp = UART_Rd_Ptr();                         // Get received byte

// Process reception through state machine
// We are parsing only "OK" and "> " responses
    switch (gsm_state) {
      case  0: {
                response = -1;                   // Clear response
                if (tmp == 'O')                  // We have 'O', it could be "OK"
                  gsm_state = 1;                 // Expecting 'K'
                if (tmp == '>')                  // We have '>', it could be "> "
                  gsm_state = 10;                // Expecting ' '
                if (tmp == 'E')                  // We have 'E', it could be "> "
                  gsm_state = 30;                // Expecting 'R'
                if (tmp == 'S')                  // We have 'S', it could be "Status?"
                  gsm_state = 40;                // Expecting 't'
                if (tmp == 'F')                  // We have 'F', it could be "FANxON or FANxOFF"
                  gsm_state = 50;                // Expecting A
                if (tmp == 'U')                  // We have 'U', it could be "UNREAD"
                  gsm_state = 70;                // Expecting 'N'
                break;
               }
      case  1: {
                if (tmp == 'K') {                // We have 'K' ->
                  response = GSM_OK;             // We have "OK" response
                  gsm_state = 20;                // Expecting CR+LF
                }
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 10: {
                if (tmp == ' ') {
                  response_rcvd = 1;             // We have "> " response
                  response = GSM_Ready_To_Receive_Message; // Set reception flag
                  responseID = response;         // Set response ID
                }
                gsm_state = 0;                   // Reset state machine
                break;
                }

      case 20: {
                if (tmp == 13)                   // We have 13, it could be CR+LF
                  gsm_state = 21;                // Expecting LF
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 21: {
                if (tmp == 10) {                 // We have LF, response is complete
                  response_rcvd = 1;             // Set reception flag
                  responseID = response;         // Set response ID
                }
                gsm_state = 0;                   // Reset state machine
                break;
               }

      case 30: {
                if (tmp == 'R')                  // We have 'R', it could be "ERROR"
                  gsm_state = 31;                // Expecting 'R'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 31: {
                if (tmp == 'R')                  // We have 'R', it could be "ERROR"
                  gsm_state = 32;                // Expecting 'O'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 32: {
                if (tmp == 'O')                  // We have 'O', it could be "ERROR"
                  gsm_state = 33;                // Expecting 'R'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 33: {
                if (tmp == 'R'){                 // We have 'R'
                  response_rcvd = 1;             // We have "ERROR" response
                  response = GSM_ERROR;          // Set reception flag
                  responseID = response;         // Set response ID
                }
                gsm_state = 0;                   // Reset state machine
                break;
                }
      case 40: {
                if (tmp == 't')                  // We have 't', it could be "Status?"
                  gsm_state = 41;                // Expecting 'a'
                else
                  gsm_state = 0;               // Reset state machine
                break;
                }
      case 41: {
                if (tmp == 'a')                  // We have 'a', it could be "Status?"
                  gsm_state = 42;                // Expecting 't'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }
      case 42: {
                if (tmp == 't')                  // We have 't', it could be "Status?"
                  gsm_state = 43;                // Expecting 'u'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 43: {
                if (tmp == 'u')                  // We have 'u', it could be "Status?"
                  gsm_state = 44;                // Expecting 's'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 44: {
                if (tmp == 's')                  // We have 's', it could be "Status?"
                  gsm_state = 45;                // Expecting '?'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 45: {
                if (tmp == '?'){                 // We have '?'
                  status_req = 1;                // Status has been requested!
                }
                gsm_state = 0;                   // Reset state machine
                break;
                }

      case 50: {
                if (tmp == 'A')                  // We have 'A', it could be "FANx"
                  gsm_state = 51;                // Expecting 'N'
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 51: {
                if (tmp == 'N')                  // We have 'N', it could be "FANx"
                  gsm_state = 52;                // Expecting number
                else
                  gsm_state = 0;                 // Reset state machine
                break;
               }

      case 52: {
                if (tmp == '1')
                   gsm_state = 53;
                else
                if (tmp == '2')
                   gsm_state = 60;
                else
                   gsm_state = 0;
                break;
                }
                
      case 53: {
                if (tmp == 'O')
                gsm_state = 54;
                else
                gsm_state = 0;
                break;
               }
               
      case 54: {
                if (tmp == 'N'){
                   FAN1 = 1;
                   gsm_state = 0;}
                else
                if (tmp == 'F')
                   gsm_state = 55;
                else
                   gsm_state = 0;
                break;
               }
      case 55: {
                if (tmp == 'F'){
                   FAN1 = 0;
                   gsm_state = 0;}
                else
                   gsm_state = 0;
                break;
                }
      case 60: {
                if (tmp == 'O')
                   gsm_state = 61;
                else
                   gsm_state = 0;
                break;
                }
      case 61: {
                if (tmp == 'N'){
                   FAN2 = 1;
                   gsm_state = 0;}
                else
                   if (tmp = 'F')
                   gsm_state = 62;
                else
                   gsm_state = 0;
                break;
                }
      case 62: {
                if (tmp == 'F'){
                   FAN2 = 0;
                   gsm_state = 0;}
                else
                   gsm_state = 0;
                break;
                }
      case 70: {
                if (tmp == 'N')
                   gsm_state = 71;
                else
                   gsm_state = 0;
                break;
                }
      case 71: {
                if (tmp == 'R')
                   gsm_state = 72;
                else
                   gsm_state = 0;
                break;
                }
      case 72: {
                if (tmp == 'E')
                   gsm_state = 73;
                else
                   gsm_state = 0;
                break;
                }
      case 73: {
                if (tmp == 'A')
                   gsm_state = 74;
                else
                   gsm_state = 0;
                break;
                }
      case 74: {
                if (tmp == 'D'){
                   response_rcvd = 1;             // We have "ERROR" response
                   response = GSM_UNREAD;         // Set reception flag
                   responseID = response;         // Set response ID
                   Unread_flag = 1;
                   }
                gsm_state = 0;
                break;
                }
      default: {                                 // Unwanted character
                gsm_state = 0;                   // Reset state machine
               }
    }
    // parse phone number on which we should reply
    switch (gsm_number) {
      case 0 :{
               if (tmp == '"'){
                 gsm_number = 1;
                 i = 0;
               }
              }; break;
      case 1 :{
               if (tmp == '+'){
                 phone_number[i] = tmp;
                 i ++;
                 gsm_number = 2;
               }
               else{
                 gsm_number = 0;
                 i = 0;
               }
              }; break;
      case 2 :{
               if (tmp >= '0' && tmp <= '9'){
                 phone_number[i] = tmp;
                 i ++;
               }
               else
                 if (tmp == '"'){
                   phone_number[i] = 0;
                   i = 0;
                   gsm_number = 0;
                 }
                 else{
                   phone_number[0] = 0;
                   i = 0;
                   gsm_number = 0;
                 }
              }; break;
      default : {
                 phone_number[0] = 0;
                 i = 0;
                 gsm_number = 0;
                }
    }
 }
}
/******************************************************************************/

Saturday, March 29, 2014

Real Time Clock [DS1307 with Set Functions] & DS18B20

Hello dear fellows, today I will share with you this amazing project which will highlights what can be done with DS1307.
The Real Time Clock (RTC) chip produced by Maxim is a popular and relatively low cost solution for creating a room clock.

Features:
  1. Real-Time Clock (RTC) Counts Seconds, Minutes, Hours, Date of the Month, Month, Day of the week, and Year with Leap-Year Compensation Valid Up to 2100.
  2. 56-Byte, Battery-Backed, General-Purpose RAM with Unlimited Writes.
  3.  I2C Serial Interface.
  4. Programmable Square-Wave Output Signal.
  5.  Automatic Power-Fail Detect and Switch Circuitry.
  6. Consumes Less than 500nA in Battery-Backup Mode with Oscillator Running.
  7.  Operating temperature range for commercial use only: 0°C to +70°C.
  8. Optional Industrial Temperature Range: -40°C to +85°C.
  9. Available in 8-Pin Plastic DIP or SO.
As can be seen from it's datasheet, the communications are achieved via I2C (designed by Philips) protocol.

Hardware setup:
In the current article I intend to display the clock information and room temperature, on the LCD with 2x16 characters. Also trough four buttons, I will try to be able to set all the times variable, stored, in DS1307 chip.
Physical realization is carried out on the breadboard with 2420 dots.





Trough this video I would like to let you know precisely, how are things going.


Below I present the timing diagram for I2C signal transmitted on pins 5-6 of the DS1307.

Data Transfer on I2C Serial Bus.

Pin Configurations.
The diagram block.


For more details, please study the DS1307 datasheet.

Circuit Diagram:
Difficulty level of the electronic scheme, is low. The microcontroller used is PIC16F876A.
S1 is the master reset button, R1 is the resistor of pull-up button.
Cristal quartz by 8 MHz, is used.
ICSP connector is used to program the microcontroller.
Trough R7 we can adjust the contrast for LCD with 2x16 characters.
R6 adjusts the current through the LED LCD (light intensity of it).
R2-R5, R8-R10 are resistors for pull-up.

I personally designed the physical pcb circuit for DS1307, through the five pins,  pcb communicate with the breadboard in this way (GND, SQW, SCL, SDA, 5VDC). In this project i didn't use SQW pin.


The electronic scheme is built in Eagle Cad , free version.

Software:
The program is written in mikroC Pro for PIC 2013 (version v6.0.0).
Below is my software version:
/*
'*******************************************************************************
'  Project name: Real Time Clock [DS1307 with Set Functions] & DS18B20
'  Description:
'          Trough the current experiment we wish to succed the next task:
'          Display on LCD 2x16 character the clock and room temperature.
'          Setting trough four buttons: the minutes, hours, date of the month,
'          month, day of the week, and year.
'
'          Our clock displays as shown below(but just in display time,
'          not in set mode).
'          Ex. of viewing on 2x16 LCD characters:
'          Display time, mode:             Set time, mode (cursor on):
'          ------------------              ------------------
'          |Sat, 03 Dec 2011|              |Sat, 03 12  2011|
'          |21:32:03 +26,1*C|              |21:32:03        |
'          ------------------              ------------------
'
'          Hardware configuration is:
'             IC ds1307 is connected with our microcontroller trough RC3=SCL,
'             RC4=SDA (I2C Connections), RB0,RB1,RB4-RB7 are assigned to LCD (2x16)
'             DS18B20 is assigned to RC7,
'             Buttons Menu: RC0= Increment value,
'                           RC1= Decrement value,
'                           RC2= Change cursor position,
'                           RC5= Enter.(It goes to set functions or exit from set
'                                functions)
'  Written by:
'          Aureliu Raducu Macovei, 2014.
'  Test configuration:
'    MCU:                        PIC16F876A;
'    Test.Board:                 WB-106 Breadboard 2420 dots;
'    SW:                         MikroC PRO for PIC 2013 (version v6.0.0);
'  Configuration Word:
'    Oscillator:                 HS (8Mhz)on pins 9 and 10;
'    Watchdog Timer:             OFF;
'    Power up Timer:             OFF;
'    Browun Out Detect:          ON;
'    Low Voltage Program:        Disabled;
'    Data EE Read Protect:       OFF;
'    Flash Program Write:        Write Protection OFF;
'    Background Debug:           Disabled;
'    Code Protect:               OFF
'*******************************************************************************
*/

// LCD module connections
sbit LCD_RS at RB0_bit;                 // LCD_RS assigned to PORT RB0;
sbit LCD_EN at RB1_bit;                 // LCD_EN assigned to PORT RB1;
sbit LCD_D4 at RB4_bit;                 // LCD_D4 assigned to PORT RB4;
sbit LCD_D5 at RB5_bit;                 // LCD_D5 assigned to PORT RB5;
sbit LCD_D6 at RB6_bit;                 // LCD_D6 assigned to PORT RB6;
sbit LCD_D7 at RB7_bit;                 // LCD_D7 assigned to PORT RB7;

sbit LCD_RS_Direction at TRISB0_bit;    // LCD_RS assigned to TRIS B0;
sbit LCD_EN_Direction at TRISB1_bit;    // LCD_EN assigned to TRIS B1;
sbit LCD_D4_Direction at TRISB4_bit;    // LCD_D4 assigned to TRIS B4;
sbit LCD_D5_Direction at TRISB5_bit;    // LCD_D5 assigned to TRIS B5;
sbit LCD_D6_Direction at TRISB6_bit;    // LCD_D6 assigned to TRIS B6;
sbit LCD_D7_Direction at TRISB7_bit;    // LCD_D7 assigned to TRIS B7;
// End LCD module connections

unsigned char sec,min1,hr,week_day,day,mn,year;
//--------------------- Reads time and date information from RTC (DS1307)
void Read_Time(char *sec, char *min, char *hr, char *week_day, char *day, char *mn, char *year)
{
 I2C1_Start();                    // Issue start signal
 I2C1_Wr(0xD0);                   // Address DS1307, see DS1307 datasheet
 I2C1_Wr(0);                      // Start from address 0
 I2C1_Repeated_Start();           // Issue repeated start signal
 I2C1_Wr(0xD1);                   // Address DS1307 for reading R/W=1
 *sec =I2C1_Rd(1);                // Read seconds byte
 *min =I2C1_Rd(1);                // Read minutes byte
 *hr =I2C1_Rd(1);                 // Read hours byte
 *week_day =I2C1_Rd(1);           // Read week day byte
 *day =I2C1_Rd(1);                // Read day byte
 *mn =I2C1_Rd(1);                 // Read mn byte
 *year =I2C1_Rd(0);               // Read Year byte
 I2C1_Stop();                     // Issue stop signal
}
//-----------------write time routine------------------
void Write_Time(char minute, char hour ,char weekday,char day,char month,char year)
{
 char tmp1, tmp2;

 tmp1 = minute / 10;               //Write tens of minute
 tmp2 = minute % 10;               //Write unit of minute
 minute = tmp1 * 16 + tmp2;        //Includes all value

 tmp1 = hour / 10;                 //Write tens of hour
 tmp2 = hour % 10;                 //Write unit of hour
 hour = tmp1 * 16 + tmp2;          //Includes all value

 tmp1 = weekday / 10;              //Write tens of weekday
 tmp2 =  weekday % 10;             //Write unit of weekday
 weekday = tmp1 *16 +tmp2;         //Includes all value

 tmp1 = day / 10;                  //Write tens of day
 tmp2 =  day % 10;                 //Write unit of day
 day = tmp1 *16 +tmp2;             //Includes all value

 tmp1 = month / 10;                //Write tens of month
 tmp2 =  month % 10;               //Write unit of month
 month = tmp1 *16 +tmp2;           //Includes all value

 tmp1 = year / 10;                 //Write tens of year
 tmp2 =  year % 10;                //Write unit of year
 year = tmp1 *16 +tmp2;            //Includes all value

 I2C1_Start();          // issue start signal
 I2C1_Wr(0xD0);         // address DS1307
 I2C1_Wr(0);            // start from word at address (REG0)
 I2C1_Wr(0x80);         // write $80 to REG0. (pause counter + 0 sec)
 I2C1_Wr(minute);       // write minutes word to (REG1)
 I2C1_Wr(hour);         // write hours word (24-hours mode)(REG2)
 I2C1_Wr(weekday);      // write 6 - Saturday (REG3)
 I2C1_Wr(day);          // write 14 to date word (REG4)
 I2C1_Wr(month);        // write 5 (May) to month word (REG5)
 I2C1_Wr(year);         // write 01 to year word (REG6)
 I2C1_Wr(0x80);         // write SQW/Out value (REG7)
 I2C1_Stop();           // issue stop signal

 I2C1_Start();          // issue start signal
 I2C1_Wr(0xD0);         // address DS1307
 I2C1_Wr(0);            // start from word at address 0
 I2C1_Wr(0);            // write 0 to REG0 (enable counting + 0 sec)
 I2C1_Stop();           // issue stop signal
}
//-------------------- Formats date and time---------------------
void Transform_Time(char  *sec, char *min, char *hr, char *week_day, char *day, char *mn, char *year)
{
  *sec  =  ((*sec & 0x70) >> 4)*10 + (*sec & 0x0F);
  *min  =  ((*min & 0xF0) >> 4)*10 + (*min & 0x0F);
  *hr   =  ((*hr & 0x30) >> 4)*10 + (*hr & 0x0F);
  *week_day =(*week_day & 0x07);
  *day  =  ((*day & 0xF0) >> 4)*10 + (*day & 0x0F);
  *mn   =  ((*mn & 0x10) >> 4)*10 + (*mn & 0x0F);
  *year =  ((*year & 0xF0)>>4)*10+(*year & 0x0F);
 }
//------------------------Display time---------------------------
char *txt,*mny;
void Display_Time(char sec, char min, char hr, char week_day, char day, char mn, char year)
{
 switch(week_day)
 {
  case 1: txt="Mon"; break;       // Monday;
  case 2: txt="Tue"; break;       // Tuesday;
  case 3: txt="Wed"; break;       // Wednesday;
  case 4: txt="Thu"; break;       // Thursday;
  case 5: txt="Fri"; break;       // Friday;
  case 6: txt="Sat"; break;       // Saturday;
  case 7: txt="Sun"; break;       // Sunday;
  }

 LCD_Out(1, 1,txt);
 LCD_chr(1, 4,',');

 switch(mn)
 {
  case  1: mny="Jan"; break;
  case  2: mny="Feb"; break;
  case  3: mny="Mar"; break;
  case  4: mny="Apr"; break;
  case  5: mny="May"; break;
  case  6: mny="Jun"; break;
  case  7: mny="Jul"; break;
  case  8: mny="Aug"; break;
  case  9: mny="Sep"; break;
  case 10: mny="Oct"; break;
  case 11: mny="Nov"; break;
  case 12: mny="Dec"; break;
  }

 Lcd_Chr(1, 6, (day / 10) + 48);    // Print tens digit of day variable
 Lcd_Chr(1, 7, (day % 10) + 48);    // Print oness digit of day variable
 Lcd_Out(1, 9,mny);
 Lcd_out(1,13,"20");
 Lcd_Chr(1,15, (year / 10)  + 48);  // we can set year 00-99 [tens]
 Lcd_Chr(1,16, (year % 10)  + 48);  // we can set year 00-99 [ones]
 Lcd_Chr(2, 1, (hr / 10)  + 48);
 Lcd_Chr(2, 2, (hr % 10)  + 48);
 Lcd_Chr(2, 3,':');
 Lcd_Chr(2, 4, (min / 10) + 48);
 Lcd_Chr(2, 5, (min % 10) + 48);
 Lcd_Chr(2, 6,':');
 Lcd_Chr(2, 7, (sec / 10) + 48);
 Lcd_Chr(2, 8, (sec % 10) + 48);
 }
//-------------------Display Time in Set mode--------------------
char minute1,hour1,weekday1,month1;
char minute,hour,weekday,day1,month,year1;
void Display_Time_SetMode()
{
 switch(weekday1)
 {
  case 1: txt="Mon"; break;       // Monday;
  case 2: txt="Tue"; break;       // Tuesday;
  case 3: txt="Wed"; break;       // Wednesday;
  case 4: txt="Thu"; break;       // Thursday;
  case 5: txt="Fri"; break;       // Friday;
  case 6: txt="Sat"; break;       // Saturday;
  case 7: txt="Sun"; break;       // Sunday;
  }

 LCD_Out(1, 1,txt);
 LCD_chr(1, 4,',');

 Lcd_Chr(1, 6, (day1 / 10)   + 48);    // Print tens digit of day variable
 Lcd_Chr(1, 7, (day1 % 10)   + 48);    // Print oness digit of day variable
 Lcd_chr(1,10, (month1 / 10) + 48);    // Print tens digit of month variable
 Lcd_chr(1,11, (month1 % 10) + 48);    // Print oness digit of month variable
 Lcd_out(1,13,"20");
 Lcd_Chr(1,15, (year1 / 10)  + 48);    // Print tens digit of year variable
 Lcd_Chr(1,16, (year1 % 10)  + 48);    // Print oness digit of year variable
 Lcd_Chr(2, 1, (hour1 / 10)  + 48);    // Print tens digit of hour variable
 Lcd_Chr(2, 2, (hour1 % 10)  + 48);    // Print oness digit of hour variable
 Lcd_Chr(2, 3,':');
 Lcd_Chr(2, 4, (minute1 / 10) + 48);   // Print tens digit of minute variable
 Lcd_Chr(2, 5, (minute1 % 10) + 48);   // Print oness digit of minute variable
 Lcd_Chr(2, 6,':');
 Lcd_Chr(2, 7, (0 / 10) + 48);
 Lcd_Chr(2, 8, (0 % 10) + 48);
}

char SPos;
//----------------------Move cursor routine----------------------
char index;
void movecursor()
{
 char i,moveto;
 if(SPos==0)
 lcd_cmd(_lcd_first_row);  // set weekday;
 if(SPos==1)
 lcd_cmd(_lcd_first_row);  // set day;
 if(SPos==2)
 lcd_cmd(_lcd_first_row);  // set month;
 if(SPos==3)
 lcd_cmd(_lcd_first_row);  // set year;
 if(SPos==4)
 lcd_cmd(_lcd_second_row); // set hours;
 if(SPos==5)
 lcd_cmd(_lcd_second_row); // set minutes;

 moveto = 2;
 switch(index)
 {
  case 0: moveto = 2;break;
  case 1: moveto = 6;break;
  case 2: moveto =10;break;
  case 3: moveto =15;break;
  case 4: moveto = 1;break;
  case 5: moveto = 4;break;
  }
  for(i=1; i<= moveto; i++)
  lcd_cmd(_lcd_move_cursor_right);
}
//------------Start Buttons routine--------------;
char setuptime=0;
void Press_Switch()
{
 if(setuptime)
 {
  if(Button(&portc,2,1,0))         // If buttons at port c2 is pressed
  {
   delay_ms(200);
   SPos++;
   if(SPos>5)
   SPos=0;
   index++;
   if(index > 5)
   index=0;
   movecursor();
   }
  //-----------------------------case mode to set all values---------------------
  switch(SPos)
  {
   case 0: if(button(&portc,0,1,0))       // If buttons at port c0 is pressed
           {
            Delay_ms(200);
            weekday1++;
            if(weekday1 > 7)
            weekday1=1;
            Display_Time_SetMode();
            index=0;
            movecursor();
            }

           if(button(&portc,1,1,0))       // If buttons at port c1 is pressed
           {
            Delay_ms(200);
            weekday1--;
            if(weekday1 < 1)
            weekday1=7;
            Display_Time_SetMode();
            index=0;
            movecursor();
            }
           break;
   case 1: if(button(&portc,0,1,0))       // If buttons at port c0 is pressed
           {
            Delay_ms(200);
            day1++;
            if(day1 > 31)
            day1 = 1;
            Display_Time_SetMode();
            index=1;
            movecursor();
            }

           if(button(&portc,1,1,0))        // If buttons at port c1 is pressed
           {
            Delay_ms(200);
            day1--;
            if(day1 < 1)
            day1 = 31;
            Display_Time_SetMode();
            index=1;
            movecursor();
            }
           break;
   case 2: if(button(&portc,0,1,0))         // If buttons at port c0 is pressed
           {
            Delay_ms(200);
            month1++;
            if(month1 > 12)
            month1 = 1;
            Display_Time_SetMode();
            index=2;
            movecursor();
            }

           if(button(&portc,1,1,0))          // If buttons at port c1 is pressed
           {
            Delay_ms(200);
            month1--;
            if(month1 < 1)
            month1 = 12;
            Display_Time_SetMode();
            index=2;
            movecursor();
            }
           break;
   case 3: if(button(&portc,0,1,0))           // If buttons at port c0 is pressed
           {
            Delay_ms(200);
            year1++;
            if(year1 > 99)
            year1 = 1;
            Display_Time_SetMode();
            index=3;
            movecursor();
            }

           if(button(&portc,1,1,0))           // If buttons at port c1 is pressed
           {
            Delay_ms(200);
            year1--;
            if(year1 < 1)
            year1 = 99;
            Display_Time_SetMode();
            index=3;
            movecursor();
            }
           break;
   case 4: if(button(&portc,0,1,0))            // If buttons at port c0 is pressed
           {
            Delay_ms(200);
            hour1++;
            if(hour1 > 23)
            hour1 = 0;
            Display_Time_SetMode();
            index=4;
            movecursor();
            }

           if(button(&portc,1,1,0))            // If buttons at port c1 is pressed
           {
            Delay_ms(200);
            hour1--;
            if(hour1 > 23)
            hour1 = 0;
            Display_Time_SetMode();
            index=4;
            movecursor();
            }
           break;
   case 5: if(button(&portc,0,1,0))            // If buttons at port c0 is pressed
           {
            Delay_ms(200);
            minute1++;
            if(minute1 > 59)
            minute1 = 0;
            Display_Time_SetMode();
            index=5;
            movecursor();
            }

           if(button(&portc,1,1,0))             // If buttons at port c1 is pressed
           {
            Delay_ms(200);
            minute1--;
            if(minute1 > 59)
            minute1 = 0;
            Display_Time_SetMode();
            index=5;
            movecursor();
            }
           break;
   }                            // end "if is in switch mode"
  }                             // end "if is in setup"

 if(button(&portc,5,1,0))                      // If buttons at port c5 is pressed
 {
  Delay_ms(200);
  setuptime = !setuptime;
  if(SetupTime)
  {
   lcd_cmd(_lcd_clear);
   lcd_cmd(_lcd_blink_cursor_on);
   weekday1=week_day;
   hour1=hr;
   minute1=min1;
   day1=day;
   month1=mn;
   year1=year;
   Display_Time_SetMode();
   SPos=0;
   index=0;
   movecursor();
   }
   else
   {
   Lcd_Cmd(_Lcd_clear);
   lcd_cmd(_lcd_cursor_off);
   weekday=weekday1;
   hour=hour1;
   minute=minute1;
   day=day1;
   month=month1;
   year=year1;
   Write_time(minute,hour,weekday,day,month,year);
   }
  }
 }
//----------------------End Buttons Routine-------------------
//------------------Temperature sensor routines---------------
const unsigned short TEMP_RESOLUTION = 12;     // 9 for DS1820 and 12 for DS18B20
char *text = "000,0";
unsigned temp;
void Display_Temperature(unsigned int temp2write)
{
 const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
 char temp_whole;
 unsigned int temp_fraction;
 unsigned short isNegative = 0x00;

 // Check if temperature is negative
 if (temp2write & 0x8000)
 {
  text[0] = '-';
  temp2write = ~temp2write + 1;
  isNegative = 1;
  }
  // Extract temp_whole
  temp_whole = temp2write >> RES_SHIFT ;
  // Convert temp_whole to characters
  if (!isNegative){
  if (temp_whole/100)
  text[0] = temp_whole/100  + 48;                // Extract hundreds digit
  else
  text[0] = '+';
  }
  text[1] = (temp_whole/10)%10 + 48;             // Extract tens digit
  text[2] =  temp_whole%10     + 48;             // Extract ones digit
  // Extract temp_fraction and convert it to unsigned int
  temp_fraction  = temp2write << (4-RES_SHIFT);
  temp_fraction &= 0x000F;
  temp_fraction *= 625;
  // Convert temp_fraction to characters
  text[4] =  temp_fraction/1000 + 48;         // Extract thousands digit
  // Print temperature on LCD
  Lcd_Out(2, 10,text);
  lcd_chr(2, 15,0xB2);                        // Ascii code for degrees symbol;
  Lcd_chr(2, 16,'C');                         // Show symbol "C" from Celsius
}
//----------------Read and display Temperature from DS18B20--------------
void Read18b20()
{
 //--- Perform temperature reading
 Ow_Reset(&PORTC, 7);                           // Onewire reset signal;
 Ow_Write(&PORTC, 7, 0xCC);                     // 0xCC Issue command SKIP_ROM;
 Ow_Write(&PORTC, 7, 0x44);                     // Issue command CONVERT_T;
 Delay_us(700);                                 // delay 0,7s (required for signal
                                                // processing);
 Ow_Reset(&PORTC, 7);                           // Onewire reset signal;
 Ow_Write(&PORTC, 7, 0xCC);                     // Issue command SKIP_ROM;
 Ow_Write(&PORTC, 7, 0xBE);                     // Issue command READ_SCRATCHPAD;

 temp = Ow_Read(&PORTC, 7);                     // Next Read Temperature, read Byte
                                                // 0 from Scratchpad;
 temp = (Ow_Read(&PORTC, 7) << 8) + temp;       // Then read Byte 1 from Scratchpad
                                                // and shift 8 bit left and add the Byte 0;
 //--- Format and display result on Lcd
 Display_Temperature(temp);                     // Call Display_Temperature;
 }
//------------------Temperature sensor routines---------------
void Init_Main()
{
 CMCON |=7;             //TURN OFF ANALOGUE COMPARATOR AND MAKE PORTA TO DIGITAL I/O;

 I2C1_Init(100000);         // initialize I2C
 Lcd_Init();                // Initialize LCD
 Lcd_Cmd(_LCD_CLEAR);       // Clear LCD display
 Lcd_Cmd(_LCD_CURSOR_OFF);  // Turn cursor off

 Display_Time(sec, min1, hr, week_day, day, mn, year);

 !setuptime=1;
 index=0;
 SPos=0;
 }
//-----------------Here we have the Main Routine----------------
void main()
{
 Init_Main();
 while (1)                                                 // While loop
 {
  Read_Time(&sec,&min1,&hr,&week_day,&day,&mn,&year);      // read time from RTC(DS1307)
  Transform_Time(&sec,&min1,&hr,&week_day,&day,&mn,&year); // Transform time
  Press_Switch();                                          // Check buttons;
  if(!setuptime)
  {
   Display_Time(sec, min1, hr, week_day, day, mn, year);
   Read18b20();
   }
  }
}