/* ****************************************************************************
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()
Copyright © 2006 SourceBoost Technologies