Tuesday 20 October 2015

PIC16F1518 RTC BY BIT BANGING





#include<pic.h>
#include<htc.h>
#define __PIC16F1518_H
#define _XTAL_FREQ   16000000

__CONFIG( FOSC_INTOSC & WDTE_OFF & PWRTE_ON & CP_OFF & MCLRE_ON & BOREN_ON & LVP_OFF &  WRT_OFF );

unsigned char RTCArray[4];
unsigned char Temp;

#define SDA_ADC ANSA3
#define SCK_ADC ANSA5




// Function Declarations
void cmd(unsigned char);
void dat(char);
void InitLCD(void);
void string(unsigned char *s);
void clrscr(void);
void DisplayTimeToLCD(unsigned char*) ;
void DisplayDateOnLCD( unsigned char*);


// Define i2c pins
#define SDA RA3 // Data pin for i2c
#define SCK RA5 // Clock pin for i2c
#define SDA_DIR        TRISA3 // Data pin direction
#define SCK_DIR        TRISA5 // Clock pin direction


// Define macros
#define Set_SDA_Low SDA_DIR = 0
#define Set_SDA_High        SDA_DIR = 1
#define Set_SCK_Low SCK_DIR = 0
#define Set_SCK_High        SCK_DIR = 1

//Function Declarations
void InitI2C(void);
void I2C_Start(void);
void I2C_ReStart(void);
void I2C_Stop(void);
void I2C_Send_ACK(void);
void I2C_Send_NACK(void);
bit  I2C_Write_Byte(unsigned char);
unsigned char I2C_Read_Byte(void);


// Define DS1307 i2c device address
#define RTC_ADDRESS 0xD0

// Define Time Modes
#define AM_Time 0
#define PM_Time 1
#define TwentyFourHoursMode        2

// Define days
#define Mon 1
#define Tue 2
#define Wed       3
#define Thu        4
#define Fri 5
#define Sat       6
#define Sun 7

// Function Declarations
void Write_Byte_To_DS1307_RTC(unsigned char, unsigned char);
unsigned char Read_Byte_From_DS1307_RTC(unsigned char);
void Write_Bytes_To_DS1307_RTC(unsigned char,unsigned char*,unsigned char);
void Read_Bytes_From_DS1307_RTC(unsigned char,unsigned char*,unsigned int);
void Set_DS1307_RTC_Time(unsigned char,unsigned char,unsigned char,unsigned char);
unsigned char* Get_DS1307_RTC_Time(void);
void Set_DS1307_RTC_Date(unsigned char,unsigned char,unsigned char,unsigned char);
unsigned char* Get_DS1307_RTC_Date(void);

void delay(unsigned int i)
{
    while(i--);
}

void cmd(unsigned char c)
{
unsigned int l,h;
l = c &0X0F;
h = c >>4;

        LATC5 = 0;
        LATC = h;
        LATC4 = 1;
        delay(5);
        LATC4 = 0;

        LATC = l;
        LATC4 = 1;
        delay(5);
        LATC4 = 0;



}


void dat(unsigned char c)
{
unsigned int l,h;
l=c &0X0F;
h=c >>4;

        LATC = h;
        LATC4 = 1;
        LATC5 = 1;
        delay(5);
        LATC4 = 0;


        LATC = l;
        LATC4 = 1;
        LATC5 = 1;
        delay(5);
        LATC4 = 0;

}

void InitLCD(void)
{
cmd(0x02);
delay(1);
cmd(0x28);
delay(1);
cmd(0x01);
delay(1);
cmd(0x80);
delay(1);
cmd(0x0e);
delay(1);
}


void string(unsigned char *s)
{
while(*s!='\0')
{
dat(*s);
s++;
}
}


void clrscr(void)       // Clear the Screen and return cursor to zero position
{
cmd(0x01);    // Clear the screen
delay(160);              // Delay for cursor to return at zero position
}


void DisplayTimeToLCD( unsigned char* Time )   // Displays time in HH:MM:SS AM/PM format
{
clrscr();      // Move cursor to zero location and clear screen

// Display Hour
dat ((Time[2]/10)+0x30);
dat ((Time[2]%10)+0x30);

//Display ':'
dat(':');

//Display Minutes
dat ((Time[1]/10)+0x30);
dat ((Time[1]%10)+0x30);

//Display ':'
dat(':');

//Display Seconds
dat ((Time[0]/10)+0x30);
dat ((Time[0]%10)+0x30);

//Display Space
dat (' ');

// Display mode
switch(Time[3])
{
case AM_Time: string("AM"); break;
case PM_Time: string("PM"); break;

default: dat('H'); break;
}
}




void DisplayDateOnLCD( unsigned char* Date )   // Displays Date in DD:MM:YY @ Day format
{
cmd(0xc0);      // Move cursor to second line

// Display Date
dat ((Date[1]/10)+0x30);
dat ((Date[1]%10)+0x30);

//Display '/'
dat('/');

//Display Month
dat ((Date[2]/10)+0x30);
dat ((Date[2]%10)+0x30);

//Display '/'
dat('/');

//Display Year
dat ((Date[3]/10)+0x30);
dat ((Date[3]%10)+0x30);

//Display Space
dat(' ');

// Display Day
switch(Date[0])
{
case Mon: string("MONDAY"); break;
case Tue: string("TUEDAY"); break;
case Wed: string("WEDNESDAY"); break;
case Thu: string("THURSDAY"); break;
case Fri: string("FRIDAY"); break;
case Sat: string("SATURDAY"); break;
case Sun: string("SUNDAY"); break;

default: string("???"); break;
}
}






// Function Purpose: Set initial values of SCK and SDA pins
void InitI2C(void)
{
    SDA_ADC   = 1; // Make analog output
SCK_ADC  = 1; // Make analog output
// Make SDA and SCK pins input initially
SDA_DIR = 1;
SCK_DIR = 1;

// Write zero in output register of SDA and SCK pin
SDA = 0;
SCK = 0;

}


// Function Purpose: I2C_Start sends start bit sequence
void I2C_Start(void)
{
SDA = 0; // Write zero in output register
SCK = 0; // of SDA and SCK pin

Set_SCK_High; // Make SCK pin high
Set_SDA_High; // Make SDA pin High
delay(2); // Half bit delay
Set_SDA_Low; // Make SDA Low
delay(2); // Half bit delay
}


// Function Purpose: I2C_ReStart sends start bit sequence
void I2C_ReStart(void)
{
Set_SCK_Low; // Make SCK pin low

delay(1); // Data pin should change it's value,
// when it is confirm that SCK is low
Set_SDA_High; // Make SDA pin High

delay(1); // 1/4 bit delay
Set_SCK_High; // Make SCK pin high
delay(1); // 1/4 bit delay
Set_SDA_Low; // Make SDA Low
delay(1); // 1/4 bit delay
}


//Function : I2C_Stop sends stop bit sequence
void I2C_Stop(void)
{
Set_SCK_Low; // Make SCK pin low

delay(1); // Data pin should change it's value,
// when it is confirm that SCK is low
Set_SDA_Low; // Make SDA pin low

delay(1); // 1/4 bit delay
Set_SCK_High; // Make SCK pin high
delay(1); // 1/4 bit delay
Set_SDA_High; // Make SDA high
delay(1); // 1/4 bit delay
}



//Function : I2C_Send_ACK sends ACK bit sequence
void I2C_Send_ACK(void)
{
Set_SCK_Low; // Make SCK pin low
delay(1); // Data pin should change it's value,
// when it is confirm that SCK is low
Set_SDA_Low; // Make SDA Low
delay(1); // 1/4 bit delay
Set_SCK_High; // Make SCK pin high
delay(2); // Half bit delay
}


//Function : I2C_Send_NACK sends NACK bit sequence
void I2C_Send_NACK(void)
{
Set_SCK_Low; // Make SCK pin low
delay(1); // Data pin should change it's value,
// when it is confirm that SCK is low
Set_SDA_High; // Make SDA high
delay(1); // 1/4 bit delay
Set_SCK_High; // Make SCK pin high
delay(2); // Half bit delay
}


// Function Purpose: I2C_Write_Byte transfers one byte
bit I2C_Write_Byte(unsigned char Byte)
{
    static bit ACK = 0;
unsigned char i; // Variable to be used in for loop

for(i=0;i<8;i++) // Repeat for every bit
{
Set_SCK_Low; // Make SCK pin low

delay(1); // Data pin should change it's value,
// when it is confirm that SCK is low

if((Byte<<i)&0x80)  // Place data bit value on SDA pin
Set_SDA_High; // If bit is high, make SDA high
else // Data is transferred MSB first
Set_SDA_Low; // If bit is low, make SDA low

delay(1); // Toggle SCK pin
Set_SCK_High; // So that slave can
delay(2); // latch data bit
    }

// Get ACK from slave
Set_SCK_Low;
    Set_SDA_High;
    delay(2);
    Set_SCK_High;
    delay(2);
SDA_ADC  = 0; // Make digital input
ACK = SDA; // Read data pin status
SDA_ADC  = 1; // Make analog output

return ACK;
}


// Function Purpose: I2C_Read_Byte reads one byte
unsigned char I2C_Read_Byte(void)
{
unsigned char i, RxData = 0;

for(i=0;i<8;i++)
{
Set_SCK_Low; // Make SCK pin low
Set_SDA_High; // Don't drive SDA
delay(2); // Half bit delay
Set_SCK_High; // Make SCK pin high
delay(1); // 1/4 bit delay
SDA_ADC  = 0; // Make digital input
RxData = RxData|(SDA<<(7-i)); // Captured received bit
SDA_ADC  = 1; // Make analog output
delay(1); // 1/4 bit delay
}

    return RxData; // Return received byte
}





// Function Purpose: Write_Byte_To_DS1307_RTC writes a single byte on given address
// Address can have any value fromm 0 to 0xFF, and DataByte can have a value of 0 to 0xFF.
void Write_Byte_To_DS1307_RTC(unsigned char Address, unsigned char DataByte)
{
I2C_Start(); // Start i2c communication

// Send i2c address of DS1307 with write command
while(I2C_Write_Byte(RTC_ADDRESS + 0) == 1)// Wait until device is free
{ I2C_Start(); }

I2C_Write_Byte(Address); // Write Address byte
I2C_Write_Byte(DataByte); // Write data byte
I2C_Stop(); // Stop i2c communication
}



// Function Purpose: Read_Byte_From_DS1307_RTC reads a single byte from given address
// Address can have any value fromm 0 to 0xFF.
unsigned char Read_Byte_From_DS1307_RTC(unsigned char Address)
{
unsigned char Byte = 0; // Variable to store Received byte

I2C_Start(); // Start i2c communication

// Send i2c address of DS1307 with write command
while(I2C_Write_Byte(RTC_ADDRESS + 0) == 1)// Wait until device is free
{ I2C_Start(); }

I2C_Write_Byte(Address); // Write Address byte
I2C_ReStart(); // Restart i2c

// Send i2c address of DS1307 RTC with read command
I2C_Write_Byte(RTC_ADDRESS + 1);

Byte = I2C_Read_Byte(); // Read byte from EEPROM

I2C_Send_NACK(); // Give NACK to stop reading
I2C_Stop(); // Stop i2c communication
// Send start bit and then stop bit to stop transmission
Set_SDA_Low; // Make SDA Low
delay(1); // Half bit delay
Set_SDA_High; // Make SDA high
delay(1); // Half bit delay

return Byte;                // Return the byte received from 24LC64 EEPROM
}



// Function Purpose: Write_Bytes_To_DS1307_RTC writes mulitple bytes from given starting address.
// Address can have any value fromm 0 to 0xFF and pData is pointer to the array
// containing NoOfBytes bytes in it. NoOfBytes is the number of bytes to write.
void Write_Bytes_To_DS1307_RTC(unsigned char Address,unsigned char* pData,unsigned char NoOfBytes)
{
unsigned int i;

I2C_Start(); // Start i2c communication

// Send i2c address of DS1307 with write command
while(I2C_Write_Byte(RTC_ADDRESS + 0) == 1)// Wait until device is free
{ I2C_Start(); }

I2C_Write_Byte(Address); // Write Address byte

for(i=0;i<NoOfBytes;i++) // Write NoOfBytes
I2C_Write_Byte(pData[i]); // Write data byte

I2C_Stop(); // Stop i2c communication
}




// Function Purpose: Read_Bytes_From_DS1307_RTC reads a NoOfBytes bytes from given starting address.
// Address can have any value fromm 0 to 0xFF. NoOfBytes is the number of bytes to write.
// Read bytes are returned in pData array.
void Read_Bytes_From_DS1307_RTC(unsigned char Address, unsigned char* pData, unsigned int NoOfBytes)
{
unsigned int i;

I2C_Start(); // Start i2c communication

// Send i2c address of DS1307 with write command
while(I2C_Write_Byte(RTC_ADDRESS + 0) == 1)// Wait until device is free
{ I2C_Start(); }

I2C_Write_Byte(Address); // Write Address byte
I2C_ReStart(); // Restart i2c

// Send i2c address of DS1307 RTC with read command
I2C_Write_Byte(RTC_ADDRESS + 1);

pData[0] = I2C_Read_Byte(); // Read First byte from EEPROM

for(i=1;i<NoOfBytes;i++) // Read NoOfBytes
{
I2C_Send_ACK(); // Give Ack to slave to start receiving next byte
pData[i] = I2C_Read_Byte(); // Read next byte from EEPROM
}

I2C_Send_NACK(); // Give NACK to stop reading
// Send start bit and then stop bit to stop transmission
Set_SDA_Low; // Make SDA Low
delay(1); // Half bit delay
Set_SDA_High; // Make SDA high
delay(1); // Half bit delay // Stop i2c communication
}




// Function Purpose: Set_DS1307_RTC_Time sets given time in RTC registers.
// Mode can have a value AM_Time or PM_Time or TwentyFourHoursMode only.
// Hours can have value from 0 to 23 only.
// Mins can have value from 0 to 59 only.
// Secs can have value from 0 to 59 only.
void Set_DS1307_RTC_Time(unsigned char Mode, unsigned char Hours, unsigned char Mins, unsigned char Secs)
{
// Convert Hours, Mins, Secs into BCD
RTCArray[0] = (((unsigned char)(Secs/10))<<4)|((unsigned char)(Secs%10));
RTCArray[1] = (((unsigned char)(Mins/10))<<4)|((unsigned char)(Mins%10));
RTCArray[2] = (((unsigned char)(Hours/10))<<4)|((unsigned char)(Hours%10));

switch(Mode) // Set mode bits
{
case AM_Time: RTCArray[2] |= 0x40; break;
case PM_Time: RTCArray[2] |= 0x60; break;

default: break; // do nothing for 24HoursMode
}

// WriteRTCArray to DS1307
Write_Bytes_To_DS1307_RTC(0x00, RTCArray, 3);
}





// Function Purpose: Get_DS1307_RTC_Time returns current time from RTC registers.
// Pointer to RTCArray is returned, in this array
// RTCArray[3] can have a value AM_Time or PM_Time or TwentyFourHoursMode only.
// RTCArray[2] (Hours byte) can have value from 0 to 23 only.
// RTCArray[1] (Mins byte) can have value from 0 to 59 only.
// RTCArray[0] (Secs byte) can have value from 0 to 59 only.
unsigned char* Get_DS1307_RTC_Time(void)
{
// Read Hours, Mins, Secs register from RTC
Read_Bytes_From_DS1307_RTC(0x00, RTCArray, 3);

// Convert Secs back from BCD into number
Temp = RTCArray[0];

RTCArray[0] = ((Temp&0x7F)>>4)*10 + (Temp&0x0F);

// Convert Mins back from BCD into number
Temp = RTCArray[1];
RTCArray[1] = (Temp>>4)*10 + (Temp&0x0F);

// Convert Hours back from BCD into number
if(RTCArray[2]&0x40) // if 12 hours mode
{
if(RTCArray[2]&0x20) // if PM Time
RTCArray[3] = PM_Time;
else // if AM time
RTCArray[3] = AM_Time;

Temp = RTCArray[2];
RTCArray[2] = ((Temp&0x1F)>>4)*10 + (Temp&0x0F);
}
else // if 24 hours mode
{
Temp = RTCArray[2];
RTCArray[2] = (Temp>>4)*10 + (Temp&0x0F);
RTCArray[3] = TwentyFourHoursMode;
}


return RTCArray;
}





// Function Purpose: Set_DS1307_RTC_Date sets given date in RTC registers.
// Year can have a value from 0 to 99 only.
// Month can have value from 1 to 12 only.
// Date can have value from 1 to 31 only.
// Day can have value from 1 to 7 only. Where 1 means Monday, 2 means Tuesday etc.
void Set_DS1307_RTC_Date(unsigned char Date, unsigned char Month, unsigned char Year, unsigned char Day)
{
// Convert Year, Month, Date, Day into BCD
RTCArray[0] = (((unsigned char)(Day/10))<<4)|((unsigned char)(Day%10));
RTCArray[1] = (((unsigned char)(Date/10))<<4)|((unsigned char)(Date%10));
RTCArray[2] = (((unsigned char)(Month/10))<<4)|((unsigned char)(Month%10));
RTCArray[3] = (((unsigned char)(Year/10))<<4)|((unsigned char)(Year%10));

// WriteRTCArray to DS1307
Write_Bytes_To_DS1307_RTC(0x03, RTCArray, 4);
}




// Function Purpose: Get_DS1307_RTC_Date returns current date from RTC registers.
// Pointer to RTCArray is returned, in this array
// RTCArray[3] (Year byte) can have value from 0 to 99 only.
// RTCArray[2] (Month byte) can have value from 1 to 12 only.
// RTCArray[1] (Date byte) can have value from 1 to 31 only.
// RTCArray[0] (Day byte) can have value from 1 to 7 only.
unsigned char* Get_DS1307_RTC_Date(void)
{
// Read Hours, Mins, Secs register from RTC
Read_Bytes_From_DS1307_RTC(0x03, RTCArray, 4);

// Convert Date back from BCD into number
Temp = RTCArray[1];
RTCArray[1] = (Temp>>4)*10 + (Temp&0x0F);

// Convert Month back from BCD into number
Temp = RTCArray[2];
RTCArray[2] = (Temp>>4)*10 + (Temp&0x0F);

// Convert Year back from BCD into number
Temp = RTCArray[3];
RTCArray[3] = (Temp>>4)*10 + (Temp&0x0F);

return RTCArray;
}



// Main function
void main()
{
        TRISC = 0X00;
        InitLCD(); // Initialize LCD
InitI2C(); // Initialize i2c pins

// Set initial time
Set_DS1307_RTC_Time(PM_Time, 11, 59, 50); // Set time 12:40:59 AM

// Set initial date
Set_DS1307_RTC_Date(11, 11, 11, Fri); // Set 31-03-2014 @ Monday

while(1)
{
// Display RTC time on first line of LCD
DisplayTimeToLCD(Get_DS1307_RTC_Time());
               

// Display RTC date on second line of LCD
DisplayDateOnLCD(Get_DS1307_RTC_Date());

delay(5000); // 1 second delay

        }
}

No comments:

Post a Comment