Category Archives: i2c

1-wire 18F14K22 Accelerometer C i2c LEDs Microcontrollers PIC RS-232

WS2812 RGB and BNO055 IMU PIC Projects

This weekend I spent my Friday afternoon and Saturday at the NW Hobby Expo; talk about an intense desire to get another hobby.

RC Plane NW Hobby Expo

Oh wait… oops; don’t tell me wife 😉 Should be here tomorrow. A little small guy to get me started.

hk_order201602

I was out helping a friend sell 3D printers and interest people into joining our Makerspace.. mission success? I don’t know we’ll see at the next open house.

The makerspace has kept me busy every moment I haven’t been spending with my little man.. thankfully my makerspace activities have been more to my desires.. I developed a little code to run WS2812 LED drivers for a PIC… why we used a PIC (my fav) I’m unsure.. these maker-folks are all Arduino… I borrow a board and took a look. It’s cute.. micros with training wheels. Here is some basic code to generate colors.. maybe it’ll cut your dev time down on a real project.
RGB WS2812 PIC


/*
 * File:   main.c
 * Author: Charles M Ihler
 * Contact at: http://iradan.com
 *
 * Created on Janurary 1, 2015
 *
 * Target Device:
 * 18F14K22 
 *
 * Project: RGB Resistor Clock
 *
 
 * Version:
 * 0.1  Configuration, with reset test
 * 0.2  Send a single color to 1 neopixel (WS2811/WS2812)
 *
 */
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //16Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/16000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/16000.0)))
#endif

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

#include 
#include 
#include 
#include 


//config bits
#pragma config FOSC=IRC, WDTEN=OFF, PWRTEN=OFF, MCLRE=ON, CP0=OFF, CP1=OFF, BOREN=ON
#pragma config STVREN=ON, LVP=OFF, HFOFST=OFF, IESO=OFF, FCMEN=OFF

#define _XTAL_FREQ 64000000 //defined for delay

/*
 * Variables
 */

    int     device_present;             // 1 = 1-wire device on 1-wire bus
    int     i, x, y, temp, an4_value;               //
    long int    decm;
    int     itxdata, txdata;            //int RS232 tx data
    char    rxbuff[10], z[1], buf[4];                 //buffer for T-sense 1-wire device
    float    temperature, f, d;
    volatile unsigned int uart_data;    // use 'volatile' qualifer as this is changed in ISR

/*
 *  Functions
 */

    void interrupt ISR() {

    if (PIR1bits.RCIF)          // see if interrupt caused by incoming data .. unused currently
    {
        uart_data = RCREG;     // read the incoming data
        PIR1bits.RCIF = 0;      // clear interrupt flag
                                //
    }
    // I left this timer interrupt if I needed it later. This is unused.
    if (PIR1bits.TMR1IF)
    {
        //T1CONbits.TMR1ON = 0;
        
        PIR1bits.TMR1IF = 0;
        //T1CONbits.TMR1ON = 1;

    }
}


     void __delay_10ms(unsigned char n)     //__delay functions built-in can't be used for much at this speed... so!
 {
     while (n-- != 0) {
         __delay_ms(10);
     }
 }


void uart_send (unsigned int mydata_byte) {      //bytes

    while(!TXSTAbits.TRMT);    // make sure buffer full bit is high before transmitting
    TXREG = mydata_byte;       // transmit data
}

void write_uart(const char *txt)                //strings
{
                                //this send a string to the TX buffer
                                //one character at a time
       while(*txt)
       uart_send(*txt++);
}

//This code if from Microchip but is unused currently.
void uart_send_hex_ascii(unsigned char display_data)
{

	//unsigned char temp;
	//temp = ((display_data & 0xF0)>>4);
	//if (temp <= 0x09)
	//	Putchar(temp+'0');
	//else
	//	Putchar(temp+'0'+0x07);
        //
	//temp = display_data & 0x0F;
	//if (temp <= 0x09)
	//	Putchar(temp+'0');
	//else
	//	Putchar(temp+'0'+0x07);

	//Putchar('\r');
	//Putchar('\n');
}

void serial_init(void)
{

    // calculate values of SPBRGL and SPBRGH based on the desired baud rate
    //
    // For 8 bit Async mode with BRGH=0: Desired Baud rate = Fosc/64([SPBRGH:SPBRGL]+1)
    // For 8 bit Async mode with BRGH=1: Desired Baud rate = Fosc/16([SPBRGH:SPBRGL]+1)



    TXSTAbits.BRGH=1;       // select low speed Baud Rate (see baud rate calcs below)
    TXSTAbits.TX9=0;        // select 8 data bits
    TXSTAbits.TXEN=1;     // enable transmit
    BAUDCONbits.BRG16=0;

    RCSTAbits.SPEN=1;       // serial port is enabled
    RCSTAbits.RX9=0;        // select 8 data bits
    RCSTAbits.CREN=1;       // receive enabled


    SPBRG=25;               //38,400bps-ish
                            //BRG16=0, 7=31.25k, 25=9.615k

    PIR1bits.RCIF=0;        // make sure receive interrupt flag is clear
    PIE1bits.RCIE=1;        // enable UART Receive interrupt


         __delay_ms(10);        // give time for voltage levels on board to settle

}

void send_low(void){
    LATCbits.LATC0 = 1;
    _delay(5);
    LATCbits.LATC0 = 0;
    _delay(11);
}

void send_high(void){
    LATCbits.LATC0 = 1;
    _delay(11);
    LATCbits.LATC0 = 0;
    _delay(8);
}


void init_io(void) {
    ANSEL = 0x00;         
    ANSELH = 0x00;

    TRISAbits.TRISA0 = 1; // PGD
    TRISAbits.TRISA1 = 1; // PGC
    TRISAbits.TRISA2 = 0; // output
    TRISAbits.TRISA4 = 1; // OSC
    TRISAbits.TRISA5 = 1; // OSC



    TRISBbits.TRISB4 = 0; // output
    TRISBbits.TRISB5 = 1; // input (RX UART)
    TRISBbits.TRISB6 = 0; // output
    TRISBbits.TRISB7 = 0; // output (TX UART)

    LATC = 0x00;

    TRISCbits.TRISC0 = 0; // WG2812 Output
    TRISCbits.TRISC1 = 1; // 
    TRISCbits.TRISC2 = 0; // 
    TRISCbits.TRISC3 = 0; // 
    TRISCbits.TRISC4 = 0; // 
    TRISCbits.TRISC5 = 0; // output
    TRISCbits.TRISC6 = 1; // input
    TRISCbits.TRISC7 = 1; // input

}

void send_black (void) {
        send_low(); //G1
        send_low(); //G2
        send_low(); //G3
        send_low(); //G4
        send_low(); //G5
        send_low(); //G6
        send_low(); //G7
        send_low(); //G8
        
        send_low(); //R1
        send_low(); //R2
        send_low(); //R3
        send_low(); //R4
        send_low(); //R5
        send_low(); //R6
        send_low(); //R7
        send_low(); //R8
        
        send_low(); //B1 00000 0000
        send_low(); //B2
        send_low(); //B3
        send_low(); //B4
        send_low(); //B5
        send_low(); //B6
        send_low(); //B7
        send_low(); //B8
}

void send_brown (void) {
        send_low(); //G1 64
        send_low(); //G2 
        send_high(); //G3 
        send_low(); //G4 
        send_low(); //G5 
        send_low(); //G6 
        send_low(); //G7 
        send_low(); //G8 
        
        send_low(); //R1 128
        send_high(); //R2 0
        send_low(); //R3 1
        send_low(); //R4 0
        send_low(); //R5 0
        send_low(); //R6 1
        send_low(); //R7 0
        send_low(); //R8 1      
  
        send_low(); //B1 0
        send_low(); //B2
        send_low(); //B3
        send_low(); //B4
        send_low(); //B5
        send_low(); //B6
        send_low(); //B7
        send_low(); //B8
}

void send_orange (void) {
        send_high(); //G1 165 / 1010 0101
        send_low(); //G2 
        send_high(); //G3 
        send_low(); //G4 
        send_low(); //G5 
        send_high(); //G6 
        send_low(); //G7 
        send_high(); //G8 
        
        send_high(); //R1 1111 1111
        send_high(); //R2 
        send_high(); //R3 
        send_high(); //R4 
        send_high(); //R5 
        send_high(); //R6 
        send_high(); //R7 
        send_high(); //R8       
  
        send_low(); //B1 00000 0000
        send_low(); //B2
        send_low(); //B3
        send_low(); //B4
        send_low(); //B5
        send_low(); //B6
        send_low(); //B7
        send_low(); //B8
}


void send_yellow (void) {
        send_high(); //G1 255 / 1111 1111
        send_high(); //G2 
        send_high(); //G3 
        send_high(); //G4 
        send_high(); //G5 
        send_high(); //G6 
        send_high(); //G7 
        send_high(); //G8 
        
        send_high(); //R1 1111 1111
        send_high(); //R2 
        send_high(); //R3 
        send_high(); //R4 
        send_high(); //R5 
        send_high(); //R6 
        send_high(); //R7 
        send_high(); //R8       
  
        send_low(); //B1 00000 0000
        send_low(); //B2
        send_low(); //B3
        send_low(); //B4
        send_low(); //B5
        send_low(); //B6
        send_low(); //B7
        send_low(); //B8
}

void send_blue (void) {
        send_low(); //G1
        send_low(); //G2
        send_low(); //G3
        send_low(); //G4
        send_low(); //G5
        send_low(); //G6
        send_low(); //G7
        send_low(); //G8
        
        send_low(); //R1
        send_low(); //R2
        send_low(); //R3
        send_low(); //R4
        send_low(); //R5
        send_low(); //R6
        send_low(); //R7
        send_low(); //R8        
  
        send_high(); //B1
        send_high(); //B2
        send_high(); //B3
        send_high(); //B4
        send_high(); //B5
        send_high(); //B6
        send_high(); //B7
        send_high(); //B8
}

void send_green (void) {
        send_high(); //G1
        send_high(); //G2
        send_high(); //G3
        send_high(); //G4
        send_high(); //G5
        send_high(); //G6
        send_high(); //G7
        send_high(); //G8
        
        send_low(); //R1
        send_low(); //R2
        send_low(); //R3
        send_low(); //R4
        send_low(); //R5
        send_low(); //R6
        send_low(); //R7
        send_low(); //R8        
  
        send_low(); //B1
        send_low(); //B2
        send_low(); //B3
        send_low(); //B4
        send_low(); //B5
        send_low(); //B6
        send_low(); //B7
        send_low(); //B8
}

void send_grey (void) {
        send_low(); //G1
        send_low(); //G2
        send_high(); //G3
        send_low(); //G4
        send_low(); //G5
        send_low(); //G6
        send_low(); //G7
        send_low(); //G8
        
        send_low(); //R1
        send_low(); //R2
        send_high(); //R3
        send_low(); //R4
        send_low(); //R5
        send_low(); //R6
        send_low(); //R7
        send_low(); //R8        
  
        send_low(); //B1
        send_low(); //B2
        send_high(); //B3
        send_low(); //B4
        send_low(); //B5
        send_low(); //B6
        send_low(); //B7
        send_low(); //B8
}

void send_violet (void) {
        send_low(); //G1
        send_low(); //G2
        send_low(); //G3
        send_low(); //G4
        send_low(); //G5
        send_low(); //G6
        send_low(); //G7
        send_low(); //G8
        
        send_high(); //R1
        send_high(); //R2
        send_high(); //R3
        send_high(); //R4
        send_high(); //R5
        send_high(); //R6
        send_high(); //R7
        send_high(); //R8        
  
        send_high(); //B1
        send_high(); //B2
        send_high(); //B3
        send_high(); //B4
        send_high(); //B5
        send_high(); //B6
        send_high(); //B7
        send_high(); //B8
}

void send_red (void) {
        send_low(); //G1
        send_low(); //G2
        send_low(); //G3
        send_low(); //G4
        send_low(); //G5
        send_low(); //G6
        send_low(); //G7
        send_low(); //G8
        
        send_high(); //R1
        send_high(); //R2
        send_high(); //R3
        send_high(); //R4
        send_high(); //R5
        send_high(); //R6
        send_high(); //R7
        send_high(); //R8        
  
        send_low(); //B1
        send_low(); //B2
        send_low(); //B3
        send_low(); //B4
        send_low(); //B5
        send_low(); //B6
        send_low(); //B7
        send_low(); //B8
}

void send_white (void) {
        send_high(); //G1 255 / 1111 1111
        send_high(); //G2 
        send_high(); //G3 
        send_high(); //G4 
        send_high(); //G5 
        send_high(); //G6 
        send_high(); //G7 
        send_high(); //G8 
        
        send_high(); //R1 1111 1111
        send_high(); //R2 
        send_high(); //R3 
        send_high(); //R4 
        send_high(); //R5 
        send_high(); //R6 
        send_high(); //R7 
        send_high(); //R8       
  
        send_high(); //B1
        send_high(); //B2
        send_high(); //B3
        send_high(); //B4
        send_high(); //B5
        send_high(); //B6
        send_high(); //B7
        send_high(); //B8
}


int main(void) {

    init_io();

    // set up oscillator control register, using internal OSC at 16MHz.
    OSCCONbits.IRCF = 0x07; //set OSCCON IRCF bits to select OSC frequency 16MHz
    OSCCONbits.SCS = 0x00; //set the SCS bits to select internal oscillator block
    OSCTUNEbits.PLLEN = 0x01;   //x4 PLL
    //RCONbits.IPEN = 0;          //disable priority levels

    INTCONbits.PEIE = 1;        // Enable peripheral interrupt
    INTCONbits.GIE = 1;         // enable global interrupt

    temp = 0x10000000;

    while (1) {
        //RGB high bit first
        //if (CHECK_BIT(temp, 0)) {
        //send_high(); //G1    
        //} else {
        //send_low(); //G1    
        //}
        
        send_brown();
        send_orange();
        send_yellow();
        
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);        
        
        send_black();    //1st LED
        send_grey();   //2nd LED
        send_white();     //3rd LED

        
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);    
        
        //send_green();
        //send_violet();
        //send_grey();
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10);
        __delay_ms(10); 
        __delay_us(100);

    }
    return (EXIT_SUCCESS);
}

It’s very very dirty and there is some un-used stuff… but it was a quick hack based on old code and I didn’t optimize the delays at all.
… This is work in progress for a resistor color code clock. I’ll obviously need to switch to a crystal, etc.

I also threw together some basic test code for the 9DOF BNO055 IMU. I bought one just for kicks in case I want to add it to my SRS Pop Can Challenge competition robot. I volunteered for the job left over on our makerspace robot group project… because power systems are a bit of a snooze, and I’m pretty much done, I decided to make my own. It won’t win (because I’m not going for all the points) but it’ll be another robot on the field. Here is some cBode to get you started if you’re interested… I used the Adafruit BOB.. pretty cool and they broke out just enough stuff it seems. I tried it with the UART interface first for kicks.. but then switched to I2C.


/*
 * File:   main.c
 * Author: Charles M Ihler
 * Contact at: http://iradan.com
 *
 * Created on February 8, 2014, 11:39 AM
 *
 * Target Device:
 * 18F14K22 on Tautic 20 pin dev board
 *
 * Project: IMU for PCC
 *
 *
 * Version:
 * 0.1  IO Confoiguration RS232/TX/I2C
 * 0.2  Test BNO055 by UART
 * 0.3  Dump UART interface and get cal status via I2C and send to UART 
 *
 */
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 16000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/16000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/16000.0)))
#endif

#include 
#include 
#include 
#include 


//config bits
#pragma config FOSC=IRC, WDTEN=OFF, PWRTEN=OFF, MCLRE=ON, CP0=OFF, CP1=OFF, BOREN=ON
#pragma config STVREN=ON, LVP=OFF, HFOFST=OFF, IESO=OFF, FCMEN=OFF

/*
 * Variables
 */

#define r_device_address  0x51 // BNO055 Default Address
#define w_device_address  0x50 // BNO055 Default Address

    unsigned int ACK_bit;
    int i;
    unsigned char byte, tempbyte1, tempbyte2;

    int     w0,w1,w2,w3,w4;     //confirguration words
    int     present;              //device present
    //int     itxdata;            //int RS232 tx data
    //char    buf[10];            //buff for iota
    volatile unsigned int uart_data;    // use 'volatile' qualifer as this is changed in ISR

/*
 *  Functions
 */

    void interrupt ISR() {

    if (PIR1bits.RCIF)          // see if interrupt caused by incoming data
    {
        uart_data = RCREG;     // read the incoming data
        if (uart_data == 0xBB)
        {
            LATAbits.LA0 = 1;
            present = 1;
        }
        PIR1bits.RCIF = 0;      // clear interrupt flag
                                //
    }
    if (INTCONbits.T0IF)
    {
        //LATAbits.LATA0 = 1;
        INTCONbits.T0IF = 0;
    }

}

void __delay_10ms(unsigned char n)     //__delay functions built-in can't be used for much at this speed... so!
 {
     while (n-- != 0) {
         __delay_ms(10);
     }
 }
     
void uart_tx(unsigned int mydata_byte) {
    while(!TXSTAbits.TRMT);    // make sure buffer full bit is high before transmitting
    TXREG = mydata_byte;       // transmit data
}

void write_uart(const char *txt){
    while(*txt != 0) uart_tx(*txt++);     //this send a string to the TX buffer
                                            //one character at a time
}

void serial_init(void)
{

    // calculate values of SPBRGL and SPBRGH based on the desired baud rate
    //
    // For 8 bit Async mode with BRGH=0: Desired Baud rate = Fosc/64([SPBRGH:SPBRGL]+1)
    // For 8 bit Async mode with BRGH=1: Desired Baud rate = Fosc/16([SPBRGH:SPBRGL]+1)



    TXSTAbits.BRGH=1;       // 
    TXSTAbits.TX9=0;        // select 8 data bits
    TXSTAbits.TXEN = 1;     // enable transmit


    RCSTAbits.SPEN=1;       // serial port is enabled
    RCSTAbits.RX9=0;        // select 8 data bits
    RCSTAbits.CREN=1;       // receive enabled

    SPBRG=103;               //

    PIR1bits.RCIF=0;        // make sure receive interrupt flag is clear
    PIE1bits.RCIE=1;        // enable UART Receive interrupt
    INTCONbits.PEIE = 1;    // Enable peripheral interrupt
    INTCONbits.GIE = 1;     // enable global interrupt
    INTCONbits.T0IE = 0;

         __delay_10ms(5);        // give time for voltage levels on board to settle
}


void init_io(void) {
    TRISAbits.TRISA0 = 0; // output
    TRISAbits.TRISA1 = 1; // input
    TRISAbits.TRISA2 = 1; // 
    TRISAbits.TRISA4 = 1; // 
    TRISAbits.TRISA5 = 1; // 
    
    ANSEL = 0x00;         // no A/D
    ANSELH = 0x00;

    TRISBbits.TRISB4 = 1; // RB4 I2C SDA, has to be set as an input
    TRISBbits.TRISB5 = 1; // RB5 = nc
    TRISBbits.TRISB6 = 1; // RB6 I2C SCLK, has to be set as an input
    TRISBbits.TRISB7 = 0; // RS232 TX

    WPUBbits.WPUB4 = 0x01;        //PORT B WEAK PULL UPS
    WPUBbits.WPUB6 = 0x01;
    
    TRISCbits.TRISC0 = 1; // 
    TRISCbits.TRISC1 = 1; // input
    TRISCbits.TRISC2 = 1; // 
    TRISCbits.TRISC3 = 0; // 
    TRISCbits.TRISC4 = 0; // 
    TRISCbits.TRISC5 = 0; // 
    TRISCbits.TRISC6 = 1; // input
    TRISCbits.TRISC7 = 1; // input

    __delay_10ms(10);   //let voltage settle
    
    //write_uart("RESET\n");         // transmit some data

}

void I2C_ACK(void)
{
   PIR1bits.SSPIF=0;          // clear SSP interrupt bit
   SSPCON2bits.ACKDT=0;        // clear the Acknowledge Data Bit - this means we are sending an Acknowledge or 'ACK'
   SSPCON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
   while(!PIR1bits.SSPIF);    // Wait for interrupt flag to go high indicating transmission is complete
}

void Send_I2C_Data(unsigned int databyte)
{
    PIR1bits.SSPIF=0;          // clear SSP interrupt bit
    SSPBUF = databyte;              // send databyte
    while(!PIR1bits.SSPIF);    // Wait for interrupt flag to go high indicating transmission is complete
}

unsigned char RX_I2C_Data (void)
{
    RCEN = 1;               // 
    while( RCEN ) continue;
    while( !BF ) continue;
    byte = SSPBUF;
   return byte;
}

void I2C_Control_Write(void)
{
    PIR1bits.SSPIF=0;          // clear SSP interrupt bit
    SSPBUF = w_device_address;             // send the control byte (90 TCN75, EF BMP085)
    while(!PIR1bits.SSPIF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSPIF=0;

}

void I2C_Control_Read(void)
{
    PIR1bits.SSPIF=0;          // clear SSP interrupt bit
    SSPBUF = r_device_address;   // send the control byte (90 TCN75, EF BMP085)
    while(!PIR1bits.SSPIF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSPIF=0;
   }


void I2C_Start_Bit(void)
{
    PIR1bits.SSPIF=0;          // clear SSP interrupt bit
    SSPCON2bits.SEN=1;          // send start bit
    while(!PIR1bits.SSPIF)    // Wait for the SSPIF bit to go back high before we load the data buffer
        {
        i = 1;
        }
    PIR1bits.SSPIF=0;
}

void I2C_check_idle()
{
    unsigned char byte1; // R/W status: Is a transfer in progress?
    unsigned char byte2; // Lower 5 bits: Acknowledge Sequence, Receive, STOP, Repeated START, START

    do
    {
        byte1 = SSPSTAT & 0x04;
        byte2 = SSPCON2 & 0x1F;
    } while( byte1 | byte2 );
}
/*
 * Send the repeated start message and wait repeated start to finish.
 */
void I2C_restart()
{
    I2C_check_idle();
    RSEN = 1; // Reinitiate start
    while( RSEN ) continue;
}

void I2C_Stop_Bit(void)
{
    PIR1bits.SSPIF=0;          // clear SSP interrupt bit
    SSPCON2bits.PEN=1;          // send stop bit
    while(!PIR1bits.SSPIF)
    {
        i = 1;
        // Wait for interrupt flag to go high indicating transmission is complete
    }
}

void I2C_NAK(void)
{
    PIR1bits.SSPIF=0;           // clear SSP interrupt bit
    SSPCON2bits.ACKDT=1;        // set the Acknowledge Data Bit- this means we are sending a No-Ack or 'NAK'
    SSPCON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
    while(!PIR1bits.SSPIF)     // Wait for interrupt flag to go high indicating transmission is complete
    {
        i = 1;
    }
}

void read_imu_status(void){
    
    I2C_Start_Bit();                    // send start bit
    I2C_Control_Write();                // send control byte with read set
    Send_I2C_Data(0x00);                // register

    I2C_restart();                      // restart

    I2C_Control_Read();
    RX_I2C_Data();                      // read high
    tempbyte1=byte;
//    I2C_ACK();                          // ACK
//    RX_I2C_Data();                      // read low
//    tempbyte2=byte;
    I2C_NAK();                          // NAK
    //I2C_restart();
    I2C_Stop_Bit();                     // Send Stop Bit

    uart_tx(tempbyte1);               //send data off raw by UART

}

void read_imu_cal_status(void){
    
    I2C_Start_Bit();                    // send start bit
    I2C_Control_Write();                // send control byte with read set
    Send_I2C_Data(0x35);                // register

    I2C_restart();                      // restart

    I2C_Control_Read();
    RX_I2C_Data();                      // read high
    tempbyte1=byte;
//    I2C_ACK();                          // ACK
//    RX_I2C_Data();                      // read low
//    tempbyte2=byte;
    I2C_NAK();                          // NAK
    //I2C_restart();
    I2C_Stop_Bit();                     // Send Stop Bit

    uart_tx(tempbyte1);               //send data off raw by UART

}

void write_imu_9DOF(void)
{

    I2C_Start_Bit();                    // send start bit
    I2C_Control_Write();                // send control byte
    Send_I2C_Data(0x3D);                // address
    Send_I2C_Data(0x1C);                // enable 9dof
    I2C_Stop_Bit();

}

void i2c_muck(void)
{

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                  // send control byte with read set

    //if (!SSP1CON2bits.ACKSTAT)
    //LATCbits.LATC1 = 0;                   //device /ACked?

    Send_I2C_Data(0x01);                //pointer
    Send_I2C_Data(0xE1);                //1 shot, 12bit res
    I2C_Stop_Bit();

    __delay_10ms(50);                     //wait for conversion

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                  // send control byte with read set

    //    if (!SSP1CON2bits.ACKSTAT)
//    LATCbits.LATC1 = 0;

    Send_I2C_Data(0x00);                //pointer

    I2C_restart();                      //restart
    I2C_Control_Read();
    RX_I2C_Data();                      //read high
    tempbyte1=byte;
    I2C_ACK();                          //ACK
    RX_I2C_Data();                      //read low
    tempbyte2=byte;
    I2C_NAK();                          //NAK
    //I2C_restart();
    I2C_Stop_Bit();                     // Send Stop Bit

    uart_tx(tempbyte1);               //send data off raw by UART
    uart_tx(tempbyte2);
}


int main(void) {

    // set up oscillator control register, using internal OSC at 16MHz.
    OSCCONbits.IRCF = 0x07; //set OSCCON IRCF bits to select OSC frequency 16MHz
    OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block
    //OSCTUNEbits.PLLEN = 0x01;   // PLL ENABLE FOSC -> 64MHz
    //OSCTUNEbits.TUN = 0x63;     ///trim up that frequency to get closed to 115200

    init_io();
    serial_init();
  
    SSPCON1bits.SSPM=0x08;       // I2C Master mode, clock = Fosc/(4 * (SSPADD+1))
    SSPCON1bits.SSPEN=1;         // enable MSSP port
    SSPADD = 0x09;             // 100KHz

    // ***********************************************************************************
    __delay_10ms(100);

    
    //init -- check and wait for IMU
    
    // test
    tempbyte1 = 0xFF;
    
    uart_tx(tempbyte1);               //send data off raw by UART
    uart_tx(0xAA);
    
    __delay_10ms(100);
    
    read_imu_status();    
    //set IMU for 9DOF
    __delay_10ms(10);
    
    
    write_imu_9DOF();
    
    //     UART method
    //     uart_tx(0xAA);                   //Start
    //     uart_tx(0x00);                   //read
    //     uart_tx(0x3D);                   //address 
    //     uart_tx(0x01);                   //length 
    //     uart_tx(0x1C);                   //data 9DOF

    __delay_10ms(50);

    while (1) {
         __delay_10ms(10);                   //delay for debugging

        LATAbits.LA0 = 0;           //good rx flag off
        //LATCbits.LATC3 = 0;
        //__delay_ms(149);
        //LATCbits.LATC3 = 1;     //debugging
        read_imu_cal_status();
  
        LATAbits.LA0 = 1;           //good rx flag on
         __delay_10ms(150);                   //delay for debugging
        
     }                                      //... wash, rinse, repeat
    return;
}



So yeah, again also sloppy but maybe you can use some of it. Price is right anyways.

Okay well maybe you might have notices a TINY gap in posting… it seems I greatly underestimated the amount of time a baby consumes in your life. I have a 9 month old son now.. he is running around trying to chew on USB cables (his favorite)… he’s just now realizing a bit of independence and with a recent purchase of a nice Lenovo Yoga 900 to replace my couple month old dead Sony Vaio I now can develop from the couch.. though I have a porta-crib in the workshop 🙂

C Electronics Hardware Hacking i2c PIC

XC8 + PIC 16F1509 with the Wii Nunchuk (yet another…)

A quick and dirty PIC to Wii Nunchuk project
A quick and dirty PIC to Wii Nunchuk project

I needed a “quick fix” of bench time.. I’ve been working on hunny-dos replacing light switches with dimmers, replacing our HVAC control with a remote network interfaced controller, etc… I needed a little bench time! I took the first quick-looking project off my “shelf of unfinished or unstarted projects”. Wii Nunchuk + a little eBay interface board that cost me a dollar or two. I spent the evening getting some C code set up using the data sheet at robotshop and some 80s music.

The TAUTIC 20 Pin PIC dev board was an obvious, I already had done some recent I2C code on it; reuse, reduce, recycle!

I wrote the code to look for the “Z” button push. The C & Z buttons threw me off a bit because I think the datasheet was a little off in some of the text. The last two bits (LSB) of the 5th status response bytes indicate the button positions of BOTH buttons. It incorrectly states one bit is for one button and the other for the other. This is the table I figured out using the Saleae logic analyzer:

0Bxxxx xx11 no buttons pushed

0Bxxxx xx01 C pushed

0Bxxxx xx00 Z pushed

0Bxxxx xx10 both buttons pushed

This is a white original Wii remote…. I didn’t do any OR decoding, etc.. I didn’t really pay much attention to the other data other than verifying it actual works.

The code doesn’t do much; we initialize the *white* nunchuk and then turn on LATA1 port when the Z button is pressed (but not the C and Z simultaneously). From here everything is popped into a variable for your happy hardware hacking needs!

Well anyways.. what you’re here for! The code:


/*
 * File:   main.c
 * Author: Charles M Douvier
 * Contact at: http://iradan.com
 *
 * Created on January 26, 2014, 12:00 PM
 *
 * Target Device:
 * 16F1509 on Tautic 20 pin dev board
 *
 * Project:
 *  Wii Nunchuck
 *
 * Version:
 * 0.1  Start Bit, and Control Byte ... check
 * 0.2  Read_State Success

 *
 */
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
#endif

#include 
#include 
#include 
#include 

//config bits
#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=ON, MCLRE=ON, CP=OFF, BOREN=OFF, CLKOUTEN=OFF, FCMEN=OFF
#pragma config WRT=OFF, STVREN=OFF, LVP=OFF


#define _XTAL_FREQ 4000000 //defined for delay

    unsigned int ACK_bit;
    int i, x;   //garbage flags
    long int tempi, tempn, tempx, tempy, temp10, temp25;
    unsigned char byte, tempbyte1, tempbyte2;
    unsigned char StatusByte;
    unsigned char RESP1Byte, RESP2Byte, RESP3Byte, RESP4Byte, RESP5Byte;
    unsigned char RESP6Byte, RESP7Byte, RESP8Byte, RESP9Byte, RESP10Byte;
    char buf[10];

void init_io(void) {

    ANSELA = 0x00; // all port A pins are digital I/O
    ANSELB = 0x00; // all port A pins are digital I/O
    ANSELC = 0x00; // all port B pins are digital I/O

    TRISAbits.TRISA0 = 0; // 
    TRISAbits.TRISA1 = 0; // 
    TRISAbits.TRISA2 = 0; // 
    TRISAbits.TRISA3 = 1; // /MCLR
    TRISAbits.TRISA4 = 0; // 
    TRISAbits.TRISA5 = 0; // 

    TRISBbits.TRISB4 = 1; // RB4 I2C SDA, has to be set as an input
    TRISBbits.TRISB5 = 1; // RB5 NC (RESERVED RS232)
    TRISBbits.TRISB6 = 1; // RB6 I2C SCLK, has to be set as an input
    TRISBbits.TRISB7 = 0; // RB7 NC (RESERVED RS232)

    TRISCbits.TRISC0 = 0; // 
    TRISCbits.TRISC1 = 0; // 
    TRISCbits.TRISC2 = 0; // 
    TRISCbits.TRISC3 = 0; // 
    TRISCbits.TRISC4 = 1; // 
    TRISCbits.TRISC5 = 1; // 
    TRISCbits.TRISC6 = 1; // 
    TRISCbits.TRISC7 = 1; // 
}

/*
 *  I2C Functions
 *
 */

void I2C_ACK(void)
{
   PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
   SSP1CON2bits.ACKDT=0;        // clear the Acknowledge Data Bit - this means we are sending an Acknowledge or 'ACK'
   SSP1CON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
   while(!PIR1bits.SSP1IF);    // Wait for interrupt flag to go high indicating transmission is complete

}

void Send_I2C_Data(unsigned int databyte)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPBUF = databyte;              // send databyte
    while(!PIR1bits.SSP1IF);    // Wait for interrupt flag to go high indicating transmission is complete
}

unsigned char RX_I2C_Data (void)
{

    RCEN = 1;               //
    while( RCEN ) continue;
    while( !BF ) continue;
    byte = SSPBUF;
   return byte;
}

void I2C_Control_Write(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSP1BUF = 0xA4;             // send the control byte 
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSP1IF=0;

}

void I2C_Control_Read(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSP1BUF = 0xA5;             // send the control byte
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSP1IF=0;
   }

void I2C_Start_Bit(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPCON2bits.SEN=1;          // send start bit
    while(!PIR1bits.SSP1IF)    // Wait for the SSPIF bit to go back high before we load the data buffer
        {
        i = 1;
        }
    PIR1bits.SSP1IF=0;
}

void I2C_check_idle()
{
    unsigned char byte1; // R/W status: Is a transfer in progress?
    unsigned char byte2; // Lower 5 bits: Acknowledge Sequence, Receive, STOP, Repeated START, START

    do
    {
        byte1 = SSPSTAT & 0x04;
        byte2 = SSPCON2 & 0x1F;
    } while( byte1 | byte2 );
}
/*
 * Send the repeated start message and wait repeated start to finish.
 */
void I2C_restart()
{
    I2C_check_idle();
    RSEN = 1; // Reinitiate start
    while( RSEN ) continue;
}

void I2C_Stop_Bit(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPCON2bits.PEN=1;          // send stop bit
    while(!PIR1bits.SSP1IF)
    {
        i = 1;
        // Wait for interrupt flag to go high indicating transmission is complete
    }
}

void I2C_NAK(void)
{
    PIR1bits.SSP1IF=0;           // clear SSP interrupt bit
    SSP1CON2bits.ACKDT=1;        // set the Acknowledge Data Bit- this means we are sending a No-Ack or 'NAK'
    SSP1CON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom

    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
    {
        i = 1;
    }
}

/*
 *  nunchuk commands
 *
 */

void initialize_nunchuk(void)
{
// 0xA4 0x40 0x00

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x40);
    Send_I2C_Data(0x00);                 //

    I2C_Stop_Bit();
    __delay_ms(100);
}

void start_conversion_with_nunchuck(void)
{
// 0xA4 0x00

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Write();                 // send control byte

    Send_I2C_Data(0x00);                 //0x00

    I2C_Stop_Bit();
			
}



void read_state (void)
{
/*
 *   STATUS, 6 Bytes
 *  Joy X
 *  Joy Y
 *  Accel X
 *  Accel Y
 *  Accel Z
 *  Z, C bits and LSB Accel

*/
//0x52 RX_STATUS
//STATUS, RESP1, RESP2, RESP3, RESP4, RESP5, RESP6

    I2C_Start_Bit();                     // send start bit
    I2C_Control_Read();

    RX_I2C_Data();                      //Joy X
	StatusByte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //Joy Y
	RESP1Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //Acc X
	RESP2Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //Acc Y
	RESP3Byte = byte;
    I2C_ACK();

	RX_I2C_Data();                      //Acc Z
	RESP4Byte = byte;
    I2C_ACK();

    	RX_I2C_Data();                      //CZ Status LSB
	RESP5Byte = byte;
    I2C_ACK();

    RX_I2C_Data();                      //
	RESP6Byte = byte;
    I2C_NAK();                          //NAK

	I2C_Stop_Bit();                     // Send Stop Bit

}



int main(void) {

    OSCCONbits.IRCF = 0x0d;     //set OSCCON IRCF bits to select OSC frequency 4MHz
    OSCCONbits.SCS = 0x02;
    OPTION_REGbits.nWPUEN = 0;  //enable weak pullups (each pin must be enabled individually)

    init_io();

    __delay_ms(50);            //let the power settle


    TRISBbits.TRISB6 = 1;

    SSPSTATbits.SMP = 1;
    SSPCONbits.SSPM=0x08;       // I2C Master mode, clock = Fosc/(4 * (SSPADD+1))
    SSPCONbits.SSPEN=1;         // enable MSSP port
    SSPADD = 0x27;              //figure out which one you can ditch sometime (probably either)
    SSP1ADD = 0x27;             // 100KHz
                                //0x09 = 100KHz
    // **************************************************************************************


    initialize_nunchuk();
    x = 0;
    LATAbits.LATA1 = 0;
    __delay_ms(50);


    while (1) {
        x = 0;
        LATAbits.LATA1 = 0;

        start_conversion_with_nunchuck();
        __delay_ms(5);
        read_state();
        //RESP6Byte
        if (!(RESP5Byte & 0x02) && !(RESP5Byte & 0x01)){
            x = 1;
        }
        if (x) {
            LATAbits.LATA1 = 1;
        }
        __delay_ms(100);
    }
    return;
}

The only thing that might not work for your application right out of the box is the return through the loop turns off the output for just a bit while the button stays pressed… you would want to change this obviously.

C Electronics i2c Microcontrollers PIC

AD5246 I2C Digital Resistor+PIC 16F1509 Test Circuit

As part of a larger MIDI project I was looking for some digital resistors. With any project I try to tackle the parts I think I’m going to have the most problem with first, of course it rarely works out I choose the difficult bits… this was the case with these resistors, they’re super simple.

A simple circuit with the PIC dev board, the SC70-6 i2C resistor and some pull up resistors (don't forget those!) I'm running 5V using 10k here..
A simple circuit with the PIC dev board, the SC70-6 i2C resistor and some pull up resistors (don’t forget those!) I’m running 5V using 10k here..

My last adventure with I2C took me a while to beat into submission so I thought I would start with this. I have ordered a enough SOIC/SC70/TSSOP, etc. breakout boards to be considered borderline hoarding. All the fun stuff comes in small packages which makes sense for placing it in a product but it’s no fun when you’re just trying to check something out. I recommend grabbing some if you haven’t already. I’m not brave enough to shoot from the hip and have boards fabed without at least testing the stuff I’m questionable about… granted in this case I2C hardware is pretty simple.  I popped my first Analog Devices AD5246BKSZ10 (Digi-Key Part number: AD5246BKSZ10-RL7CT-ND )  on to a little SIP package breakout board.. I eventually gave up on the SIP package. I hand-soldered it and it must have had some little bits under the package. I grabbed a DIP package breakout and threw some chipquick down then used my 858D to reflow the tiny SC70-6 package.

A little breakout board, I bought a ton of these on eBay for SC70-6 and others..
A little breakout board, I bought a ton of these on eBay for SC70-6 and others..

On power up the resistor defaults to mid-span (with no command).. that’s kind of nice but I will have to consider that when integrating this to a project; In my case that is 5K (of 10k). I hacked up some recent I2C code for quick dev … it was a no-brainer really. The 10K resistor I have centers out at 5.00K but its top side is 9.90K .. not a big deal for me. The resistance data command is 7bit, 0x00 to 0x7F takes you from 0 Ohms to 10K. If you did the math that’s 78 Ohm steps… There is a 5K, 10K, 50K and a 100K version in this series and they can only handle 5mA of current. I will consider putting in a typical passive resistor in series to limit the possible current through the resistor if that will be an issue.

Some thoughts I had..

Pros:

  • Easily adaptable to an all analog circuit
  • tiny!
  • great for firmware calibration! no tiny pots in a case you have to open
  • Doesn’t power up at 0 Ohm!  (this might be  a con for you..)

Cons:

  • Not addressable (it’d be nice if it was a 8 pin package to select between 4 different addresses)
  • Tiny package if you’re trying to hand-solder a project
  • No so good if you need very fine resolution

 

No surprises really.. So here’s the goodies: a screen shot of the I2C write command for max resistance followed by the code.

The i2c command was super simple, start, address,n a 7-bit value 0x00 - 0x7F, stop!
The i2c command was super simple, start, address,n a 7-bit value 0x00 – 0x7F, stop!

 

 


/* 
 * File:   main.c
 * Author: Charles M Douvier
 * Contact at: http://iradan.com
 *
 * Created on September 14, 2014, 8:06 AM
 *
 * Target Device:
 * 16F1509 on Tautic 20 pin dev board
 *
 * Project: Digital Resistor Test
 *
 *
 * Version:
 * 1.0  Initial Code to Test Wiper
 *
 *
 *  AD5246BKSZ10-RL7
 *  I2C Address 0x5C (Write)
 *  Resistor I2C
 *  Write S 0 1 0 1 1 1 0 W A X D6 D5 D4 D3 D2 D1 D0 A P
 *  Read  S 0 1 0 1 1 1 0 R A 0 D6 D5 D4 D3 D2 D1 D0 A P
 */
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
#endif

#include 
#include 
#include 
#include 

//config bits
#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=ON, MCLRE=ON, CP=OFF, BOREN=OFF, CLKOUTEN=OFF, FCMEN=OFF
#pragma config WRT=OFF, STVREN=OFF, LVP=OFF

#define _XTAL_FREQ 4000000 //defined for delay

    unsigned int ACK_bit;
    int i;
    unsigned char byte, tempbyte1, tempbyte2;

/*
 * 
 */
void init_io(void) {

    ANSELA = 0x00; // all port A pins are digital I/O
    ANSELB = 0x00; // all port A pins are digital I/O
    ANSELC = 0x00; // all port B pins are digital I/O

    TRISAbits.TRISA0 = 0; // output
    TRISAbits.TRISA1 = 0; // output
    TRISAbits.TRISA2 = 0; // output
    TRISAbits.TRISA3 = 0; // output
    TRISAbits.TRISA4 = 0; // output
    TRISAbits.TRISA5 = 0; // output

    TRISBbits.TRISB4 = 1; // RB4 I2C SDA, has to be set as an input
    TRISBbits.TRISB5 = 1; // RB5 = nc
    TRISBbits.TRISB6 = 1; // RB6 I2C SCLK, has to be set as an input
    TRISBbits.TRISB7 = 0; // RB7 = nc

    TRISCbits.TRISC0 = 0; // output
    TRISCbits.TRISC1 = 0; // output
    TRISCbits.TRISC2 = 0; // output
    TRISCbits.TRISC3 = 0; // output
    TRISCbits.TRISC4 = 0; // output
    TRISCbits.TRISC5 = 0; // output
    TRISCbits.TRISC6 = 1; // input
    TRISCbits.TRISC7 = 1; // input
}


void I2C_ACK(void)
{
   PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
   SSP1CON2bits.ACKDT=0;        // clear the Acknowledge Data Bit - this means we are sending an Acknowledge or 'ACK'
   SSP1CON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
   while(!PIR1bits.SSP1IF);    // Wait for interrupt flag to go high indicating transmission is complete
}

void Send_I2C_Data(unsigned int databyte)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPBUF = databyte;              // send databyte
    while(!PIR1bits.SSP1IF);    // Wait for interrupt flag to go high indicating transmission is complete
}

unsigned char RX_I2C_Data (void)
{

    RCEN = 1;               //
    while( RCEN ) continue;
    while( !BF ) continue;
    byte = SSPBUF;
   return byte;
}

void I2C_Control_Write0(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSP1BUF = 0x5C;             // send the control byte (90 TCN75, EF BMP085)
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSP1IF=0;

}
void I2C_Control_Write1(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSP1BUF = 0x92;             // send the control byte (90 TCN75, EF BMP085, change this)
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSP1IF=0;

}

void I2C_Control_Read0(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSP1BUF = 0x91;             // send the control byte (90 TCN75, EF BMP085, change this)
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
        {
        i = 1;
          // place to add a breakpoint if needed
        }
    PIR1bits.SSP1IF=0;
   }



void I2C_Start_Bit(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPCON2bits.SEN=1;          // send start bit
    while(!PIR1bits.SSP1IF)    // Wait for the SSPIF bit to go back high before we load the data buffer
        {
        i = 1;
        }
    PIR1bits.SSP1IF=0;
}

void I2C_check_idle()
{
    unsigned char byte1; // R/W status: Is a transfer in progress?
    unsigned char byte2; // Lower 5 bits: Acknowledge Sequence, Receive, STOP, Repeated START, START

    do
    {
        byte1 = SSPSTAT & 0x04;
        byte2 = SSPCON2 & 0x1F;
    } while( byte1 | byte2 );
}
/*
 * Send the repeated start message and wait repeated start to finish.
 */
void I2C_restart()
{
    I2C_check_idle();
    RSEN = 1; // Reinitiate start
    while( RSEN ) continue;
}

void I2C_Stop_Bit(void)
{
    PIR1bits.SSP1IF=0;          // clear SSP interrupt bit
    SSPCON2bits.PEN=1;          // send stop bit
    while(!PIR1bits.SSP1IF)
    {
        i = 1;
        // Wait for interrupt flag to go high indicating transmission is complete
    }
}

void I2C_NAK(void)
{
    PIR1bits.SSP1IF=0;           // clear SSP interrupt bit
    SSP1CON2bits.ACKDT=1;        // set the Acknowledge Data Bit- this means we are sending a No-Ack or 'NAK'
    SSP1CON2bits.ACKEN=1;        // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
    while(!PIR1bits.SSP1IF)     // Wait for interrupt flag to go high indicating transmission is complete
    {
        i = 1;
    }
}

void set_resistor(void)
{

    I2C_Start_Bit();                    // send start bit
    I2C_Control_Write0();               // send control byte with read set
    Send_I2C_Data(0x7F);                // Send Resistance Value Data
                                        // 0x00 - 0x7F
                                        // 0 - 10KOhm
    I2C_Stop_Bit();                     // Stop

}




int main(void) {

    // set up oscillator control register, using internal OSC at 4MHz.
    OSCCONbits.IRCF = 0x0d; //set OSCCON IRCF bits to select OSC frequency 4MHz
    OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block
    OPTION_REGbits.nWPUEN = 0; // enable weak pullups (each pin must be enabled individually)

    SSPCONbits.SSPM=0x08;       // I2C Master mode, clock = Fosc/(4 * (SSPADD+1))
    SSPCONbits.SSPEN=1;         // enable MSSP port
    SSPADD = 0x09;              // 100KHz
    // **************************************************************************************

    init_io();

    __delay_ms(100);             // let everything settle.

    set_resistor();

    while (1) {
        //do something
        PORTAbits.RA0 = 0;
        __delay_ms(100);
        PORTAbits.RA0 = 1;
        __delay_ms(100);
    }
    return (EXIT_SUCCESS);
}