Hi-Tech C I2C Master Example Code

Hi-Tech C I2C Master Example Code

Here is some example code for a Microchip 12F1822 microcontroller which is setup as an I2C Master to communicate with one of our Servo*Pro chips (which is an I2C slave). Both read and write functions are used and it is written using the free Hi-Tech C compiler.

This code uses the MSSP port built into the microcontroller not bit-banged I2C. It should be easily modifyable for other mid-range Microchip PIC devices with an in-built MSSP.

There are 2 files

  • i2c.h contains all the i2c functions
  • servo_master.c is the main program

Download a zip file containing both files here

i2c.h

/*
 * Hi-Tech C I2C library for 12F1822
 * Master mode routines for I2C MSSP port to read and write to slave device 
 * Copyright (C)2011 HobbyTronics.co.uk 2011
 * Freely distributable.
*/

#define I2C_WRITE 0
#define I2C_READ 1

// Initialise MSSP port. (12F1822 - other devices may differ)
void i2c_Init(void){

   // Initialise I2C MSSP
   // Master 100KHz
   TRISA1=1;                    // set SCL and SDA pins as inputs
   TRISA2=1;

   SSPCON1 = 0b00101000; 	// I2C enabled, Master mode
   SSPCON2 = 0x00;
   // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) 
   SSPADD = 39;    		// 100Khz @ 16Mhz Fosc

   SSPSTAT = 0b11000000; 	// Slew rate disabled

}

// i2c_Wait - wait for I2C transfer to finish
void i2c_Wait(void){
    while ( ( SSP1CON2 & 0x1F ) || ( SSPSTAT & 0x04 ) );
}

// i2c_Start - Start I2C communication
void i2c_Start(void)
{
    i2c_Wait();
    SEN=1;
}

// i2c_Restart - Re-Start I2C communication
void i2c_Restart(void){
    i2c_Wait();
    RSEN=1;
}

// i2c_Stop - Stop I2C communication
void i2c_Stop(void)
{
    i2c_Wait();
    PEN=1;
}

// i2c_Write - Sends one byte of data
void i2c_Write(unsigned char data)
{
    i2c_Wait();
    SSPBUF = data;
}

// i2c_Address - Sends Slave Address and Read/Write mode
// mode is either I2C_WRITE or I2C_READ
void i2c_Address(unsigned char address, unsigned char mode)
{
    unsigned char l_address;

    l_address=address<<1;
    l_address+=mode;
    i2c_Wait();
    SSPBUF = l_address;
}

// i2c_Read - Reads a byte from Slave device
unsigned char i2c_Read(unsigned char ack)
{
    // Read data from slave
    // ack should be 1 if there is going to be more data read
    // ack should be 0 if this is the last byte of data read
    unsigned char i2cReadData;

    i2c_Wait();
    RCEN=1;
    i2c_Wait();
    i2cReadData = SSPBUF;
    i2c_Wait();
    if ( ack ) ACKDT=0;	        // Ack
    else       ACKDT=1;	        // NAck
    ACKEN=1;                    // send acknowledge sequence

    return( i2cReadData );
}

servo_master.c

#include <htc.h>
#include "i2c.h"
/*
 * Hi-Tech C Demo program for 12F1822
 *
 * Writes values to a slave servo chip and reads values from it
 * via I2C
 *
 * Copyright (C)2011 HobbyTronics.co.uk
 * Freely distributable.
*/

// MCLR Disabled, Code Protect on, Watchdog disabled, Brownout off, Internal Osc
__CONFIG(MCLRE_OFF & CP_ON & WDTE_OFF & BOREN_OFF & FOSC_INTOSC);

#define _XTAL_FREQ 16000000             // Used in __delay_ms() functions
#define I2C_SLAVE 40                    // Slave device I2C address

// Send a command to servo ic
void i2c_servo_command(unsigned char address, unsigned char command)
{
    i2c_Start();                        // send Start
    i2c_Address(I2C_SLAVE, I2C_WRITE);  // Send slave address - write operation
    i2c_Write(address);	                // Servo Speed 
    i2c_Write(command);	                // 2 seconds on servo 0
    i2c_Stop();	                        // send Stop
}

// Read a char from servo ic
unsigned char i2c_servo_read(unsigned char address)
{
    unsigned char read_byte;
    // Read one byte (i.e. servo pos of one servo)
    i2c_Start();                        // send Start
    i2c_Address(I2C_SLAVE, I2C_WRITE);  // Send slave address - write operation
    i2c_Write(address);	                // Set register for servo 0
    i2c_Restart();                      // Restart
    i2c_Address(I2C_SLAVE, I2C_READ);   // Send slave address - read operation	
    read_byte = i2c_Read(0);            // Read one byte
                          // If more than one byte to be read, (0) should
                          // be on last byte only
                          // e.g.3 bytes= i2c_Read(1); i2c_Read(1); i2c_Read(0);
    i2c_Stop();                         // send Stop
    return read_byte;                   // return byte. 
                                        // If reading more than one byte
                                        // store in an array
}

void main(void)
{
    unsigned char i;
    unsigned char result;
    unsigned char servo0_pos=0;

    OSCCON = 0b01111010;                // set internal osc to 16MHz
    TRISA = 0b000000;                   //
    PORTA = 0b000000;

    i2c_Init();	                        // Start I2C as Master 100KHz

    i2c_servo_command(63, 20);          // Set Servo Speed to 2s for servo 0
    i2c_servo_command(60, 1);           // Turn servo outputs ON

    while(1){

        i2c_servo_command(0, 255);              // Set servo 0 to position 255

        // Wait until Servo 0 has reached half way
        while(servo0_pos < 127)
        {
            __delay_ms(50);
            servo0_pos = i2c_servo_read(0);     // Read pos of servo 0
        }

        i2c_servo_command(1, 255);              // Set servo1 to position 255

        // Wait until Servo 0 has reached end
        while(servo0_pos < 255)
        {
            __delay_ms(50);
            servo0_pos = i2c_servo_read(0);     // Read pos of servo 0
        }

        i2c_servo_command(0, 0);                // Set servo 0 to position 0

        // Wait until Servo 0 has reached half way
        while(servo0_pos > 127)
        {
            __delay_ms(50);
            servo0_pos = i2c_servo_read(0);     // Read pos of servo 0
        }

        i2c_servo_command(1, 0);                // Set servo1 to position 0

        // Wait until Servo 0 has reached start
        while(servo0_pos > 0)
        {
            __delay_ms(50);
            servo0_pos = i2c_servo_read(0);     // Read pos of servo 0
        }

    }
}

Shopping Cart
0 items
 
DELIVERY/PAYMENT

   UK ORDERS OVER £50

UK - £2.40 orders below
                    £50.00
EU Airmail from £3.95
Worldwide from £7.95
More Details...

 
Specials
 
Brands
 
Follow us on: