Source Code File:"I2C_Master_1.c"

/* ****************************************************************************
 SourceBoost C Code

 Processor:     PIC16F877A

 Filename:      I2C_Master_1.c
 Author:        RSABear
 Date:          8 January 2008
 Version:       1.00
 Description:
    
            Use Hardware UART - RS232
            Use Hardware MSSP - I2C

            I2C Master Code
    

******************************************************************************
Hardware:

    LED on RA2 - PIN 2
    4.0MHz Crystal on PINs 13 & 14
    100K Pull-up Resistor from PIN1 to Vdd

    Maxim DS275 Chip
    RX-Out - PIN 26
    TX-In  - PIN 25

    SLAVE 16F887A - Address 0xF0

    PIN 23 - SDA
    PIN 18 - SCL

    SLAVE 24FC512 - Address 0xA0

    PIN 23 - SDA
    PIN 18 - SCL

Revision History:
    
    10 January 2008 - Ver 1.00

Modified:



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

#include <system.h>
#include <stdlib.h>
#include <string.h>
#include <i2c_driver.h>
#include <icd2.h>

// Set the 16F877A device configuration bits - Page 
// External 4.0Mhz Crystal Oscillator
#pragma DATA _CONFIG, _CPD_OFF & _DEBUG_ON & _PWRTE_ON & _LVP_OFF & _BODEN_ON & _PWRTE_ON & _WDT_OFF & _XT_OSC

// 4.0 Mhz
#pragma CLOCK_FREQ 4000000

#define FOSC 4000000
#define spBAUD 9600
#define fSPBCLK (FOSC)  // UART Baud rate generator clock (high speed)
// #define fSPBCLK (FOSC / 4)   // UART Baud rate generator clock (low speed)
#define SPBRG_VAL ((fSPBCLK / (spBAUD * 16L)) - 1L)

// bit_time FOSC / 4 / BAUDRATE 
#define bit_time 104        // 9600 baud at 4MHz

// Hardware dependant defines RC6 & 7
#define RX_PIN      7
#define TX_PIN      6

// **** START OF DEFAULTS USED FOR HARDWARE USART ****
////////////////////////////////////////////////////////////////////////////
// USART hardwareware implementation template argument values
////////////////////////////////////////////////////////////////////////////
// variables cannot be passed as template arguments. The following constants map to
// the PIC registers and PIC's USART register locations. These constants are
// then used by the templated functions. When moving between PIC families the
// register mapping must be changed to map to the corresponding physical register
//
// PIC16F877A defaults for hardware USART support
// DS30292C-page 95 (TX) & DS30292C-page 104 (RX)

#define TX_PORT     PORTC
#define TX_TRIS     TRISC
#define TX_BIT      TX_PIN
#define RX_PORT     PORTC
#define RX_TRIS     TRISC
#define RX_BIT      RX_PIN
#define e_SPBRG     SPBRG
#define e_RCREG     RCREG
#define e_TXREG     TXREG
#define e_TXSTA     TXSTA
#define e_RCSTA     RCSTA
#define e_TXIF_PIR  PIR1
#define e_RCIF_PIR  PIR1
#define e_TXIF_BIT  TXIF
#define e_RCIF_BIT  RCIF
#define MODE        (USART_reset_wdt | USART_HW)

// **** END OF DEFAULTS USED FOR HARDWARE USART ****

#include "rs232_driver.h"

////////////////////////////////////////////////////////////////////////////
// i2c hardwareware implementation template arguments
////////////////////////////////////////////////////////////////////////////
#define i2c_ARGS    3, e_MSSP_PORT, e_MSSP_TRIS, 4, e_MSSP_PORT, e_MSSP_TRIS, e_SSPCON1, e_SSPCON2, \
                    e_SSPSTAT, e_SSPBUF, e_SSPIF_BIT, e_SSPIF_PIR,          \
                    e_BCLIF_BIT, e_BCLIF_PIR, 7, e_SSPADD, (i2c_reset_wdt | i2c_SMP |i2c_HW)

// variables cannot be passed as template arguments. The following constants map to
// the PIC registers and PIC's i2c register locations. These constants are
// then used by the templated functions. 
#define e_MSSP_PORT     PORTC
#define e_MSSP_TRIS     TRISC
#define e_SSPCON1       SSPCON
#define e_SSPCON2       SSPCON2
#define e_SSPSTAT       SSPSTAT
#define e_SSPADD        SSPADD
#define e_SSPBUF        SSPBUF
#define e_SSPIF_PIR PIR1
#define e_BCLIF_PIR PIR2
#define e_SSPIF_BIT SSPIF
#define e_BCLIF_BIT BCLIF

////////////////////////////////////////////////////////////////////////////
// I2C Device constants
////////////////////////////////////////////////////////////////////////////
    
// define External I2C slave (Hardware) addresses
#define xff_slave   0x06    // Base address of 16F877A device
#define xee_slave   0xA0    // Base address of the EEPROM

////////////////////////////////////////////////////////////////////////////
// Read from the External EEPROM
////////////////////////////////////////////////////////////////////////////
// s is a pointer to the destination buffer to data read from the EEPROM
// HW_address is the hardware address of the i2c device
// ic2_addr is the target internal address within the External EEPROM
// count is the number of bytes to be read starting at i2c_addr
void read_XEE(char *s, char HW_address, unsigned short i2c_addr, unsigned short count)
{
    short i;

    i2c_start();
    i2c_write(HW_address); // send XEE i2c address  
    i2c_write(i2c_addr >> 8); // send XEE internal HIGH address
    i2c_write((char) i2c_addr & 0x00ff); // send XEE internal LOW address
    i2c_restart(); // send i2c_restart

    // sending XEE read command via i2c_write
    i2c_write(HW_address | 0x01); // send device address + RD to I2C device

    // XEE read loop
    for (i=0;i<count-1;i++)
        *s++ = i2c_read(0);
    *s++ = i2c_read(1);
    *s = 0;

    i2c_stop();                                                                                             
}

////////////////////////////////////////////////////////////////////////////
// Write to the External EEPROM
////////////////////////////////////////////////////////////////////////////
// s is a pointer to the string to be written to the EEPROM
// HW_address is the hardware address of the i2c device
// ic2_addr is the target internal address within the External EEPROM
// count is the number of bytes to be written starting at i2c_addr
void write_XEE(char *s, char HW_address, unsigned short i2c_addr, unsigned short count)
{
    short i;

    i2c_start();
    i2c_write(HW_address); // send XEE i2c address                  
    i2c_write(i2c_addr >> 8); // send XEE internal HIGH address
    i2c_write((char) i2c_addr & 0x00ff); // send XEE internal LOW address

    // XEE write loop
    for (i=0;i<count;i++)
        i2c_write(*s++);
    i2c_stop();                                                                                         
}

////////////////////////////////////////////////////////////////////////////
// Read from the External 16F877A device
////////////////////////////////////////////////////////////////////////////
// s is a pointer to the destination buffer to data read from the EEPROM
// HW_address is the hardware address of the i2c device
// ic2_addr is the target internal address within the External EEPROM
// count is the number of bytes to be read starting at i2c_addr
void read_XFF(char *s, char HW_address, unsigned short i2c_addr, unsigned short count)
{
    short i;

    // First write the Address for the memory location to read to the device
    HW_address <<= 1;           // Shift the 7-bit address Left by 1
    HW_address &= 0xFE;     // LSB = 0 for address/data write operation 
    
    i2c_start();
    i2c_write(HW_address); // send XEE i2c address
    
    i2c_write(i2c_addr >> 8); // send XEE internal HIGH address
    i2c_write((char) i2c_addr & 0x00ff); // send XEE internal LOW address

    i2c_restart(); // send i2c_restart

    // sending XEE read command via i2c_write
    i2c_write(HW_address | 0x01); // send device address + RD to I2C device

    // XEE read loop
    for (i=0;i<count-1;i++)
        *s++ = i2c_read(0);
    *s++ = i2c_read(1);
    *s = 0;

    i2c_stop();                                                                                             
}

////////////////////////////////////////////////////////////////////////////
// Write to the External 16F877A device
////////////////////////////////////////////////////////////////////////////
// s is a pointer to the string to be written to the EEPROM
// HW_address is the hardware address of the i2c device
// ic2_addr is the target internal address within the External device
// count is the number of bytes to be written starting at i2c_addr
void write_XFF(char *s, char HW_address, unsigned short i2c_addr, unsigned short count)
{
    short i;

    HW_address <<= 0x01;        // Shift the 7-bit address Left by 1
    HW_address &= 0xFE;     // LSB = 0 for address/data write operation 

    i2c_start();
    i2c_write(HW_address); // send XFF i2c address
                
    i2c_write(i2c_addr >> 8); // send XFF internal HIGH address
    i2c_write((char) i2c_addr & 0x00ff); // send XFF internal LOW address

    // XFF write loop
    for (i=0;i<count;i++)
        i2c_write(*s++);
    i2c_stop();                                                                                         

}

void writes(char *source)
{
    while (*source != 0) // wait until tx register is empty
        putc(*source++);
}   


// Declare some logic defintions for later use
#define SET             1
#define CLEAR           0
#define RESET           0
#define TRUE            1
#define FALSE           0
#define ZERO            0

char buffer[32];
char value[32];
char *ee_mesg = "i2c Test String";
char *ff_mesg = "i2c Test String";
char *s1;
char *str_value;
char i, val_h, val_l;
unsigned int int_value;
unsigned short i2c_addr;    // used for internal addressing for the target I2C device

char i_counter, c_data;

void main()
{

    char i_counter;

    adcon0 = 0x00;      // Switch the ADC Unit Off
    ccp1con = 0x00; // Switch the comparator unit off

    trisa = 0x00;
    porta = 0x00;

    // User entertainment - show the RESET/REBOOT
    for ( i_counter = 1; i_counter < 20; i_counter++ )  {
        porta.0 = 0;
        delay_ms(50);
        porta.0 = 1;
        delay_ms(50);
    }

    clear_bit(porta , 0);

    // RS232 Communications
    uart_init(1,SPBRG_VAL);         // set high speed divisor mode and divisor value - 9600
    puts("PIC16F877A I2C Master");
    delay_ms(100);

    // I2C Communications
    //#define   I2C_divisor 0x7E
    #define I2C_divisor 0x09
    //I2C_divisor ((4000000/100000)/4) - 1) = 9 = 0b00001001
    // set the divisor for the I2C clock
    // for software I2C emulation this can be any value (such as 1)
    i2c_init(I2C_divisor); 

/*
    ///////////////////////////////////////////////////////////////////////////
    // Write/Read test of the EEPROM followed by the Microchip 16F877A device
    //////////////////////////////////////////////////////////////////////////
    // Write to address 0x0000 of the EEPROM
    i2c_addr = 0x0000;
    puts("ee ->");
    puts(ee_mesg);
    write_XEE(ee_mesg, xee_slave, i2c_addr, strlen(ee_mesg)+1);
    // The External EEPROM requires a delay to finish
    // programming the flash before it can be accessed again
    delay_ms(50);

    // Read 16 bytes from address 0x0000 in External EEPROM     
    i2c_addr = 0x0000;
    s1 = &buffer[0]; // point s1 to the work buffer
    read_XEE(s1, xee_slave, i2c_addr, 16);
    puts("ee <-");
    puts(s1);
*/

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


    // Write to the 16F877A, 1 bit, slave address 0x06
    i2c_addr = 0x0000;
    puts("ff ->");
    puts(ff_mesg);
    write_XFF(ff_mesg, xff_slave, i2c_addr, strlen(ff_mesg)+1);
    // The External device requires a delay to finish
    // programming the flash before it can be accessed again
    delay_ms(50);

    puts("ff <-");
    // Read 16 bytes from address 0x0000 of the 16F877A
    i2c_addr = 0x0000;
    s1 = &buffer[0]; // point s1 to the work buffer
    read_XFF(s1, xff_slave, i2c_addr, 16);
    puts(s1);



while(TRUE)
    {
    

        // For some strange reason toggle_bit() does not work...
        delay_ms(200);
        porta.0 = 0;
        delay_ms(200);
        porta.0 = 1;


// Not required
//      if (kbhit())
//          {
//              putc(getc());                                       // Get the input character from the UART
//          } // End Keyboard Hit

    } // End While Loop
}   // End main()

http://www.sourceboost.com

Copyright © 2006 SourceBoost Technologies