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: