I²C Library

I²C™ Functions: (Page # 25)

The I2C functions of the C18 libraries allow us to configure the SSP module in slave as well as master mode. Before checking out the code, please read through this document which describes how the I2C protocol is implemented in the PIC18:

ww1.microchip.com/downloads/en/devicedoc/i2c.pdf

Following is the list of the I2C functions:

OpenI2C(arguments)/ OpenI2Cx(arguments):

This function is used to configure the SSP[x] module. The x is used when multiple I2Cx modules are present.

IdleI2C()/IdleI2Cx():

This function checks for the state of the I2C peripheral and waits until the bus becomes idle.

DataRdyI2C()/DataRdyI2Cx():

This function checks whether there is any data present in the I2C buffer.

getcI2C()/getcI2Cx()/ReadI2C()/ReadI2Cx()::

These functions read a byte from the I2Cx bus.

getsI2C(arguments)/ getsI2Cx(arguments):

This function is used to read a string of specified length from the I2Cx bus which is operating in master mode.

WriteI2C(arguments)/ WriteI2Cx(arguments)/ putcI2C(arguments)/ putcI2Cx(arguments):

These functions are used to write a byte to the I2Cx bus.

AckI2C()/AckI2Cx():

Generate an I2C bus acknowledge condition.

NotAckI2C ()/NotAckI2Cx():

Generate an I2C bus Not acknowledge condition.

RestartI2C()/RestartI2Cx():

Generate an I2C bus Restart condition.

StartI2C()/StartI2Cx():

Generate an I2C bus Start condition.

StopI2C ()/StopI2Cx():

Generate an I2C bus Stop condition.

Here is the code(requires additional files to be added in the project, download the whole folder from the link):

Code

//This is a program that demonstrates the use of I2C Module with

//Microchips Libraries.It is a clock using the DS3232 with temperature monitoring

//The External LCD Section is documented on P#79 of C18 Libraries

// and the I2C library is documented on P#25.

//Use 18f4620i2c.DSN

//Replace this xlcd.h in the MCC18>h folder.

//Add all files in the folder in your project.Also present in MCC18 isntallation folder.

//Pin changes have been made in the provided xlcd.h file.

/* Baud Rate Calculation for 100Khz for the I2C bus*/

//BR=Fosc/(4*(SSPADD + 1))

//SSPADD=(Fosc/(4*BR))-1

//Fosc=4Mhz

//BR=100Khz

//SSPADD=(4MHZ/4*100Khz)-1

// =10-1

//SSPADD=9

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

/*

There is a flaw in this program due some problem in the DS3232

model in Proteus. Even after following the exact code exmaple as en

by MAXIM for generating an Alarm interrupt, the DS3232 model in Proteus

does not generate it. Since the sole purpose of this Demo is to

demonstrate the I2C library, i have used the square wave feature

but have mentioned the values of the specific registers for generating

an Interrupt persecond.Sorry for any inconvinience

*/

/*RTC Registers*/

#define Seconds 0x00

#define Minutes 0x01

#define Hours 0x02

#define Day 0x03

#define Date 0x04

#define Month_Century 0x05

#define Year 0x06

#define Alarm1_seconds 0x07

#define Alarm1_minutes 0x08

#define Alarm1_hours 0x09

#define Alarm1_day_date 0x0A

#define Alarm2_minutes 0x0B

#define Alarm2_hours 0x0C

#define Alarm2_day_date 0x0D

#define Control 0x0E

#define Control_Status 0x0F

#define Aging_offset 0x10

#define MSB_Temp 0x11

#define LSB_Temp 0x12

#include<p18f4620.h>// Include files and definitions for the Processor

#include<xlcd.h>// Include function definitions for the External LCD Library library

#include<delays.h>// Include function definitions for built in Delay routines

#include<i2c.h>//Include the function definitions for the I2C module

/*Function Definitions for user created functions*/

void Init_DS3232(void);//Initializes DS3232

void Write_DS3232(unsigned char,unsigned char);//Writes to the DS3232.Refer to the datasheet P#17

unsigned char Read_DS3232(unsigned char);//Writes to the DS3232.Refer to the datasheet P#17

void BCD2ASCII(unsigned char);//To convert the BCD time value to ASII for LCD

void conv_temp(unsigned char,unsigned char);//To convert the temperature value from Binary in to Decimal

void chk_isr(void);//Interrupt Handler

/* Some variables that have been used*/

unsigned char ascii_high,ascii_low,sign;

unsigned char temp_reading_int,temp_reading_dec,d1,d2,d3;

#pragma config OSC=INTIO67,WDT=OFF,DEBUG=ON,LVP=OFF,IESO=OFF,WRTD=OFF// Use internal Oscillator, Watchdog off, LVP off

void hi_prioriint(void)

{

_asm

GOTO chk_isr

_endasm

}

#pragma interrupt chk_isr

void chk_isr(void)

{

if(INTCONbits.INT0IF==1)//If RTC generates and Interrupt

{

unsigned char hour_time,minutes_time,seconds_time,check;

unsigned char data[]="Time : ";

unsigned char temp[]="Temp :";

hour_time=Read_DS3232(Hours);//Read Hours

minutes_time=Read_DS3232(Minutes);//Read Minutes

seconds_time=Read_DS3232(Seconds);//Read Seconds

SetDDRamAddr(0x80);//Choose first location on LCD

putsXLCD(data);

while( BusyXLCD() );// Wait till LCD finishes writing data

BCD2ASCII(hour_time);//Convert BCD Hours in to ASCII

putcXLCD(ascii_high);// Write the Hours high byte to LCD

while( BusyXLCD() );// Wait till LCD finishes writing data

putcXLCD(ascii_low);// Write the Hours low byte to LCD

while( BusyXLCD() );// Wait till LCD finishes writing data

putcXLCD(':');

while( BusyXLCD() );

BCD2ASCII(minutes_time);//Convert BCD Minutes in to ASCII

putcXLCD(ascii_high);// Write the Minutes high byte to LCD

while( BusyXLCD() );// Wait till LCD finishes writing data

putcXLCD(ascii_low);// Write the Minutes low byte to LCD

while( BusyXLCD() );// Wait till LCD finishes writing data

putcXLCD(':');

while( BusyXLCD() );// Wait till LCD finishes writing data

BCD2ASCII(seconds_time);//Convert BCD Seconds in to ASCII

putcXLCD(ascii_high);// Write the Seconds high byte to LCD

while( BusyXLCD() );// Wait till LCD finishes writing data

putcXLCD(ascii_low);// Write the Seconds low byte to LCD

while( BusyXLCD() );// Wait till LCD finishes writing data

/* This Do while routine checks whether the DS3232 is not already

performing a temperature conversion for updating the crystal capacitance

P#13 of datasheet*/

do

{

check=Read_DS3232(Control);

check=check&0x04;

}

while(check!=0x00);

/* Tells the DS3232 to start converting the temperature reading*/

Write_DS3232(Control,0x20);//0x25 for alarm interrupt

do

{

check=Read_DS3232(Control);

check=check&0x04;

}

while(check!=0x00);

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

temp_reading_int=Read_DS3232(MSB_Temp);//Read the MSB of Temperature

temp_reading_dec=Read_DS3232(LSB_Temp);

conv_temp(temp_reading_int,temp_reading_dec);

SetDDRamAddr(0xC0);

putsXLCD(temp);

while( BusyXLCD() );// Wait till LCD finishes executing command

/*This code checks whether the temperature is negative or positive

puts the apporpriate sign on the LCD*/

if(sign==0)

{

putcXLCD('+');

while( BusyXLCD() );// Wait till LCD finishes executing command

}

else

{

putcXLCD('-');

while( BusyXLCD() );// Wait till LCD finishes executing command

}

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

BCD2ASCII(d3);

putcXLCD(ascii_low);// Write the data to the LCD

while( BusyXLCD() );// Wait till LCD finishes executing command

BCD2ASCII(d2);

putcXLCD(ascii_low);// Write the data to the LCD

while( BusyXLCD() );// Wait till LCD finishes executing command

BCD2ASCII(d1);

putcXLCD(ascii_low);// Write the data to the LCD

while( BusyXLCD() );// Wait till LCD finishes executing command

putcXLCD('.');

while( BusyXLCD() );// Wait till LCD finishes executing command

BCD2ASCII(temp_reading_dec);//Convert decimal portion of the Temperature in to ASCII

putcXLCD(ascii_high);// Write the High byte of Decimal Temprature to the LCD

while( BusyXLCD() );// Wait till LCD finishes executing command

putcXLCD(ascii_low);// Write the Low byte of Decimal Temprature to the LCD

while( BusyXLCD() );// Wait till LCD finishes executing command

putcXLCD(223);//ASCII for the degree symbol

while( BusyXLCD() );// Wait till LCD finishes executing command

putcXLCD('C');

while( BusyXLCD() );// Wait till LCD finishes executing command

Write_DS3232(Control_Status,0x30);//for enabling alarm interrupt again.

INTCONbits.INT0IF=0;

}

}

void main(void)

{

OSCCON=0x64;//Internal 4MHZ Oscillator

ADCON1=0X0F;//Make all ports Digital

CMCON=0x07;//Turn off the comparators

OpenXLCD( EIGHT_BIT & LINES_5X7 );// Use 8 bit Data, 5x7 pixel Matrix per character

while( BusyXLCD());// Wait till LCD finishes executing command

WriteCmdXLCD( BLINK_OFF);// Turn Cursor Blinking OFF

while( BusyXLCD() );// Wait till LCD finishes executing command

WriteCmdXLCD( SHIFT_DISP_LEFT );//Shift Cursor Display Left

while( BusyXLCD() );// Wait till LCD finishes

SSPADD=0x09;//For choosing 100KHZ Baud Rate

OpenI2C(MASTER,SLEW_OFF);//I2C as Master, Turn slew off

Init_DS3232();//Set the time on the RTC, Interrupt(Square wave) Enable

INTCONbits.INT0IE=1;//Enable external hardware interrupt

INTCONbits.GIEH=1;//Enable Global Interrupt

while(1);// Wait here

}

void Init_DS3232(void)

{

Delay1KTCYx(500);// Wait for the RTC to Start up

Write_DS3232(Control,0x85);//Disable oscillator

Write_DS3232(Seconds,0x00);//Set Seconds to 00

Write_DS3232(Minutes,0x00);//Set Minutes to 00

Write_DS3232(Hours,0x12);//Set Hours to 00

Write_DS3232(Day,0x01);//Set Day to the 1st of the week

Write_DS3232(Date,0x01);//Set Date to the 1st of the month

Write_DS3232(Month_Century,0x01);//Set month to January

Write_DS3232(Year,0x11);//Set year to 2010

/* This writes the Alarm Registers to Generate an interrupt every Seond*/

Write_DS3232(Alarm1_seconds,0x80);

Write_DS3232(Alarm1_minutes,0x80);

Write_DS3232(Alarm1_hours,0x80);

Write_DS3232(Alarm1_day_date,0x80);

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

Write_DS3232(Control_Status,0x30);//for temperature conversion period

Write_DS3232(Control,0x00);//for alarm interrupts put 0x05;Enales the Oscillator

// the Square wave with a freq of 1Hz

}

/*Writes to the DS3232 see Pages 16 and 17 of datasheet*/

void Write_DS3232(unsigned char x,unsigned char y)

{

StartI2C();

WriteI2C(0b11010000);// Address of slave

while(SSPCON2bits.ACKSTAT!=0);// wait for ack from RTC

WriteI2C(x);

while(SSPCON2bits.ACKSTAT!=0);// wait for ack from RTC

WriteI2C(y);

while(SSPCON2bits.ACKSTAT!=0);// wait for ack from RTC

StopI2C();

}

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

/*Reads from the DS3232 see Pages 16 and 17 of datasheet*/

unsigned char Read_DS3232(unsigned char x)

{

unsigned char read_value;

IdleI2C();

StartI2C();

WriteI2C(0b11010000);// Address of slave

while(SSPCON2bits.ACKSTAT!=0);// wait for ack from RT

WriteI2C(x);

while(SSPCON2bits.ACKSTAT!=0);// wait for ack from RTC

RestartI2C();

WriteI2C(0b11010001);// Address of slave

while(SSPCON2bits.ACKSTAT!=0);// wait for ack from RT

read_value=ReadI2C();

NotAckI2C();

StopI2C();

return(read_value);

}

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

/*Convets BCD to ASCII and stores the vlaues in to ascii_high and ascii_low*/

void BCD2ASCII(unsigned char BCD)

{

unsigned char temp_var;

temp_var=(BCD&0x0f);

temp_var=temp_var|0x30;

ascii_low=temp_var;

temp_var=(BCD&0xf0);

temp_var=temp_var>>4;

temp_var=temp_var|0x30;

ascii_high=temp_var;

}

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

/*Converts Temperature in to Decimal, Determines its Sign*/

void conv_temp(unsigned char high, unsigned char low)

{

unsigned char x;

temp_reading_dec=0;

low=low>>6;

if(low<=0x03)

{

while(low!=0)

{

temp_reading_dec=temp_reading_dec+25;

low--;

}

}

else

{

high++;

}

sign=0x80&high;

high=high&0xFF;

x=high/10;

d1=high%10;

d2=x%10;

d3=x/10;

}

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

// As indicated in the C18 libraries manual

// These delays are required for LCD operation

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

// DelayFor18TCY =18 cycles.

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

void DelayFor18TCY(void)

{

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

_asm NOP _endasm

}

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

// DelayPORXLCD =15 ms.

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

void DelayPORXLCD(void)

{

Delay1KTCYx(15);

}

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

// DelayXLCD =5 ms.

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

void DelayXLCD(void)

{

Delay1KTCYx(5);

}

The code for the I2C functions and the additional files required to run it can be downloaded from:

http://www.box.net/shared/0ahcfg4a5m