Daily Archives: February 22, 2016

I2C Communications between Raspberry Pi and Arduino – Part Three

Today’s goal is to send a string from the Arduino to the Raspberry Pi. The setup is the same as from day two.

After several attempts and stupid mistakes, I was finally able to get a “Hello World” message from the Arduino to the Raspberry Pi.

Here is the code for the Arduino

#include <Wire.h>
#include "DHT.h"

#define SLAVE_ADDRESS 0x04

#define PIN_DHT 4
#define PIN_PHOTORESISTOR A3
#define PIN_LED 1

#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

int humidity = 0;
int temperatureCelsius = 0;
int lightReading = 0;

int number = 0;

unsigned long previousMillis = 0;
const long interval = 1000;

bool flashLed = true;
bool respondWithText = false;
String responseText = "The Message";

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(PIN_DHT, DHTTYPE);

void setup() {
  pinMode(PIN_DHT, INPUT);
  pinMode(PIN_PHOTORESISTOR, INPUT);
  pinMode(PIN_LED, OUTPUT);

  digitalWrite(PIN_LED, LOW);

  dht.begin();

  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);

  // define callbacks for i2c communication
  Wire.onReceive(On_WireReceive);
  Wire.onRequest(On_WireRequest);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (flashLed) {
      digitalWrite(PIN_LED, HIGH);
    }
    ReadDHT();
    ReadLightLevel();
    if (flashLed) {
      digitalWrite(PIN_LED, LOW);
    }
  }
}

// callback for received data
void On_WireReceive(int byteCount) {

  while (Wire.available()) {
    number = Wire.read();
    respondWithText = false;

    switch (number) {
      case 1: // Temperature in Celsius
        number = temperatureCelsius;
        break;
      case 2: // Humidity
        number = humidity;
        break;
      case 3: // Light Level
        number = lightReading;
        break;
      case 4: // LED On
        digitalWrite(PIN_LED, HIGH);
        flashLed = false;
        break;
      case 5: // LED Off
        digitalWrite(PIN_LED, LOW);
        flashLed = false;
        break;
      case 6: // LED Flash on read
        digitalWrite(PIN_LED, LOW);
        flashLed = true;
        break;
      case 250: // Send Model Info
        respondWithText = true;
        responseText = "TeelSys Data and Light Sensor";
        break;
      case 251: // Send Version Info
        respondWithText = true;
        responseText = "version 0.0.3";
        break;
      case 254: // Send Hello World
        respondWithText = true;
        responseText = "Hello World";
        break;
      default:
        break;
    }
  }
}

// callback for sending data
void On_WireRequest() {
  if(respondWithText) {
    ProcessRequestString();
  }
  else {
    sendData();
  }
}

void ReadDHT() {
  humidity = 0;
  temperatureCelsius = 0;

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  humidity = dht.readHumidity();
  // Read temperature as Celsius (the default)
  temperatureCelsius = dht.readTemperature();
}

void ReadLightLevel() {
  int photocellReading = analogRead(PIN_PHOTORESISTOR);
  lightReading = ((float)photocellReading / 1023.0) * 100.0;
}

void sendData() {
  Wire.write(number);
}

void ProcessRequestString() {
  Wire.write(responseText.c_str());
}

Here is the code for the Raspberry Pi

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-0";

int main(int argc, char** argv) {

  if (argc == 1) {
    printf("Supply one or more commands to send to the Arduino\n");
    exit(1);
  }

  printf("I2C: Connecting\n");
  int file;

  if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }

  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }

  int arg;

  for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
      fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
      exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);
      
      if(val<250) {	// Receiving int
	      char buf[1];
	      if (read(file, buf, 1) == 1) {
		    int temp = (int) buf[0];
		
		    printf("Received %d\n", temp);
		      }
		  }
      else {	// Receiving String
	      char buf[256];
	      int charCount=0;
	      
	      for(charCount=0; charCount<256; charCount++) {
	      	buf[charCount]=89;
	      }
	      
				if(read(file, buf, 256) == 256) {
					for(charCount=0; charCount<256; charCount++) {
	    			int temp = (int) buf[charCount];
	
	    			printf("%d:\tReceived %d\t%c\n", charCount, temp, temp);
	    		}
		    }
      }
		}
		
    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }

  close(file);
  return (EXIT_SUCCESS);
}

Compile the code
gcc testi2c03.c -o testi2c03
Config_I2C_103

Run the code
./testi2c03 254
Config_I2C_104
Config_I2C_105

We can see that once the string ends, the data on the I2C buss is 255. Let’s tweak the code on the Raspberry Pi to stop once we receive 255.

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-0";

int main(int argc, char** argv) {

  if (argc == 1) {
    printf("Supply one or more commands to send to the Arduino\n");
    exit(1);
  }

  printf("I2C: Connecting\n");
  int file;

  if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }

  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }

  int arg;

  for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
      fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
      exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);
      
      if(val<250) {	// Receiving int
	      char buf[1];
	      if (read(file, buf, 1) == 1) {
		    int temp = (int) buf[0];
		
		    printf("Received %d\n", temp);
		      }
		  }
      else {	// Receiving String
	      char buf[256];
	      int charCount=0;
	      
	      for(charCount=0; charCount<256; charCount++) {
	      	buf[charCount]=89;
	      }
	      
				if(read(file, buf, 256) == 256) {
					for(charCount=0; charCount<256; charCount++) {
	    			int temp = (int) buf[charCount];
	    			
	    			if(temp==255) {
	    				break;
	    			}
	
	    			printf("%d:\tReceived %d\t%c\n", charCount, temp, temp);
	    		}
		    }
      }
		}
		
    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }

  close(file);
  return (EXIT_SUCCESS);
}

Compile the code
gcc testi2c03b.c -o testi2c03b

Then run the application
./testi2c03b 254
Config_I2C_107

We can see that the output is now cleaner.

Let’s do even better and print the string as a string instead of a list of characters.

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-0";

int main(int argc, char** argv) {

  if (argc == 1) {
    printf("Supply one or more commands to send to the Arduino\n");
    exit(1);
  }

  printf("I2C: Connecting\n");
  int file;

  if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }

  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }

  int arg;

  for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
      fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
      exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);
      
      if(val<250) {	// Receiving int
	      char buf[1];
	      if (read(file, buf, 1) == 1) {
		    int temp = (int) buf[0];
		
		    printf("Received %d\n", temp);
		      }
		  }
      else {	// Receiving String
	      char buf[256];
	      int charCount=0;
	      char receivedText[256];
	      
	      for(charCount=0; charCount<256; charCount++) {
	      	receivedText[charCount]=0;
	      }
	      
				if(read(file, buf, 256) == 256) {
					for(charCount=0; charCount<256; charCount++) {
	    			int temp = (int) buf[charCount];
	    			
	    			if(temp==255) {
	    				break;
	    			}
	    			
	    			receivedText[charCount] = buf[charCount];
	
	    			//printf("%d:\tReceived %d\t%c\n", charCount, temp, temp);
	    		}
	    		printf("Received %s\n", receivedText);
		    }
      }
		}
		
    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }

  close(file);
  return (EXIT_SUCCESS);
}

Compile the code
gcc testi2c03c.c -o testi2c03c

Then run the application
./testi2c03c 1 2 3 254 250 251
Config_I2C_108

Yes, I included additional arguments this time. The code was setup to handle this which is really nice. This allows us to teak the code if we like to print out what the values actually are and get some additional information. So let’s create a new application which will do exactly that but will not take in any arguments. I am also going to add a few other things such as detecting if we are using a Raspberry Pi Rev 1 or Rev 2 as well as scanning the I2C Bus.

I was doing some searching on valid I2C addresses and found a great reference article from Total  Phase at 7-bit, 8-bit, and 10-bit I2C Slave Addressing. The article provides a diagram showing the valid range of 7-bit I2C addresses.

slave-address-fig3

From this diagram, we can see that the address used in the examples is a reserved address. I will change the address in the Arduino code so that it is in the valid address range.

Here is a modified version of the code which finds all connected I2C devices. Determines which ones are the sensors that we are interested in, and reads values from each one. This will be a great program for making certain that the design works and all of the sensors are working.

Arduino Code

#include <Wire.h>
#include "DHT.h"

#define SLAVE_ADDRESS 0x22

#define PIN_DHT 4
#define PIN_PHOTORESISTOR A3
#define PIN_LED 1

#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

int humidity = 0;
int temperatureCelsius = 0;
int lightReading = 0;

int number = 0;

unsigned long previousMillis = 0;
const long interval = 1000;

bool flashLed = true;
bool respondWithText = false;
String responseText = "The Message";

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(PIN_DHT, DHTTYPE);

void setup() {
  pinMode(PIN_DHT, INPUT);
  pinMode(PIN_PHOTORESISTOR, INPUT);
  pinMode(PIN_LED, OUTPUT);

  digitalWrite(PIN_LED, LOW);

  dht.begin();

  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);

  // define callbacks for i2c communication
  Wire.onReceive(On_WireReceive);
  Wire.onRequest(On_WireRequest);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (flashLed) {
      digitalWrite(PIN_LED, HIGH);
    }
    ReadDHT();
    ReadLightLevel();
    if (flashLed) {
      digitalWrite(PIN_LED, LOW);
    }
  }
}

// callback for received data
void On_WireReceive(int byteCount) {

  while (Wire.available()) {
    number = Wire.read();
    respondWithText = false;

    switch (number) {
      case 1: // Temperature in Celsius
        number = temperatureCelsius;
        break;
      case 2: // Humidity
        number = humidity;
        break;
      case 3: // Light Level
        number = lightReading;
        break;
      case 4: // LED On
        digitalWrite(PIN_LED, HIGH);
        flashLed = false;
        break;
      case 5: // LED Off
        digitalWrite(PIN_LED, LOW);
        flashLed = false;
        break;
      case 6: // LED Flash on read
        digitalWrite(PIN_LED, LOW);
        flashLed = true;
        break;
      case 250: // Send Model Info
        respondWithText = true;
        responseText = "TeelSys Data and Light Sensor";
        break;
      case 251: // Send Version Info
        respondWithText = true;
        responseText = "version 0.0.3";
        break;
      case 254: // Send Hello World
        respondWithText = true;
        responseText = "Hello World";
        break;
      default:
        break;
    }
  }
}

// callback for sending data
void On_WireRequest() {
  if(respondWithText) {
    ProcessRequestString();
  }
  else {
    sendData();
  }
}

void ReadDHT() {
  humidity = 0;
  temperatureCelsius = 0;

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  humidity = dht.readHumidity();
  // Read temperature as Celsius (the default)
  temperatureCelsius = dht.readTemperature();
}

void ReadLightLevel() {
  int photocellReading = analogRead(PIN_PHOTORESISTOR);
  lightReading = ((float)photocellReading / 1023.0) * 100.0;
}

void sendData() {
  Wire.write(number);
}

void ProcessRequestString() {
  Wire.write(responseText.c_str());
}

Raspberry Pi Code

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>

#define CMD_GET_TEMPERATURE 1
#define CMD_GET_HUMIDITY 2
#define CMD_SET_LIGHT 3
#define CMD_SET_LED_ON 4
#define CMD_SET_LED_OFF 5
#define CMD_SET_LED_FLASH 6
#define CMD_GET_MODEL 250
#define CMD_GET_VERSION 251
#define CMD_GET_HELLO_WORLD 254

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
char *devName = "/dev/i2c-0";
int file;
int devices[128];
int sensorDevices[128];

float computeHeatIndex(float temperature, float percentHumidity, int isFahrenheit);
float convertCtoF(float c);
float convertFtoC(float f);
void displayConnectedI2cDevices();
void findAllI2cDevices();
void findI2cBus();
void findSensors();
int receiveInt();
void receiveString(char *str, int bufSize);
int sendCommand(int deviceAddress, int cmdCode);

int main(int argc, char** argv) {
	// Look for the I2C bus device

  printf("I2C: Connecting\n");
	findI2cBus();
  
  // Find Devices
  findAllI2cDevices();
  
  // Display devices found (Simlar to i2cdetect -y 0)
  displayConnectedI2cDevices();
  
  // Find the sensors for this project
  findSensors();
  
  printf("\n");
  
  // Read information from each sensor
  int deviceIdx = 0;
  
  while(sensorDevices[deviceIdx] > 0) {
  	int bufSize=256;
  	char buf[bufSize];
  	// int bufSize = sizeof(buf)/sizeof(buf[0]);
  	int val=0;
  	
  	/*
  		Model
  		Version
  		Temperature
  		Humidity
  		Light Level
  	*/
  	float degreesC=0.0;
  	float degreesF=0.0;
  	float humidity=0.0;
  	float lightLevel=0.0;
  	float heatIndexC=0.0;
  	float heatIndexF=0.0;
  	char model[bufSize];
  	char version[bufSize];
  	
  	// Get the values
  	sendCommand(sensorDevices[deviceIdx], CMD_SET_LED_ON);
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_MODEL)==1) {
  		receiveString(model, bufSize);
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_VERSION)==1) {
  		receiveString(version, bufSize);
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_TEMPERATURE)==1) {
  		val=receiveInt();
  		degreesC = (float)val;
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_HUMIDITY)==1) {
  		val=receiveInt();
  		humidity = (float)val;
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_SET_LIGHT)==1) {
  		val=receiveInt();
  		lightLevel = (float)val;
  	}
  	sendCommand(sensorDevices[deviceIdx], CMD_SET_LED_OFF);
  	
  	// Calculate Values
  	degreesF=convertCtoF(degreesC);
  	heatIndexC=computeHeatIndex(degreesC, humidity, 0);
  	heatIndexF=computeHeatIndex(degreesF, humidity, 1);
  	
  	// Display values
  	printf("Sensor Address: 0x%02x\n", sensorDevices[deviceIdx]);
  	printf("Model: %s\n", model);
  	printf("Version: %s\n", version);
		printf("Temperature: %3.2f C\n", degreesC);
		printf("Temperature: %3.2f F\n", degreesF);
  	printf("Humidity: %3.2f%% RH\n", humidity);
		printf("Heat Index: %3.2f C\n", heatIndexC);
		printf("Heat Index: %3.2f F\n", heatIndexF);
  	printf("Light Level: %3.2f%%\n", lightLevel);
  	printf("\n");
  	
  	deviceIdx++;
  }
  
  close(file);
  return (EXIT_SUCCESS);
}

float computeHeatIndex(float temperature, float percentHumidity, int isFahrenheit) {
  // Using both Rothfusz and Steadman's equations
  // http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml
  float hi;

  if (isFahrenheit==0)
    temperature = convertCtoF(temperature);

  hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094));

  if (hi > 79) {
    hi = -42.379 +
             2.04901523 * temperature +
            10.14333127 * percentHumidity +
            -0.22475541 * temperature*percentHumidity +
            -0.00683783 * pow(temperature, 2) +
            -0.05481717 * pow(percentHumidity, 2) +
             0.00122874 * pow(temperature, 2) * percentHumidity +
             0.00085282 * temperature*pow(percentHumidity, 2) +
            -0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);

    if((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0))
      hi -= ((13.0 - percentHumidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);

    else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))
      hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
  }

  return isFahrenheit ? hi : convertFtoC(hi);
}

float convertCtoF(float c) {
  return c * (9.0/5.0) + 32;
}

float convertFtoC(float f) {
  return (f - 32) * (5.0/9.0);
}

void displayConnectedI2cDevices() {
	int idx=0;
	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
	for(idx=0; idx<=0x7F; idx++) {
		if(idx%16==0) {
			printf("\n%d0:",idx/16);
		}
		if(idx>0x07 && idx<0x78) {
			if(devices[idx]>0) {
				if(devices[idx]==-9) {
					printf(" UU");
				}
				else {
					printf(" %02x", idx);
				}
			}
			else {
				printf(" --");
			}
		}
		else {
				printf("   ");
		}
  }
  printf("\n");
}

void findAllI2cDevices() {
	int idx=0;
  for(idx=0; idx<=0x7F; idx++) {
  	int device=0;
  	
  	if(idx>0x07 && idx<0x78) {
	  	if (ioctl(file, I2C_SLAVE, idx) < 0) {
	  		if(errno == EBUSY) {
	  			device = -9;
	  		}
	  		else {
		  		device = -1;
		  	}
	  	}
	  	else {
	  		char buf[1];
	  		if(read(file, buf, 1) == 1 && buf[0] >= 0) {
	  			device = idx;
	  		}
	  	}
  	}
  	
  	devices[idx] = device;
  }
}

void findI2cBus() {
	if ((file = open(devName, O_RDWR)) < 0) {
  	devName = "/dev/i2c-1";
  	if ((file = open(devName, O_RDWR)) < 0) {
	    fprintf(stderr, "I2C: Failed to access %d\n", devName);
	    exit(1);
	  }
  }
  
  printf("Found I2C bus at %s\n", devName);
}

void findSensors() {
	char *sensorType="TeelSys Data and Light Sensor";
	char buf[256];
	int idx=0;
	int sensorIdx=0;
	// sensorDevices
	// devices
	
	// Clear the sensorDevices array
	for(idx=0; idx<128; idx++) {
		sensorDevices[idx] = 0;
	}
	
  for(idx=0x08; idx<=0x78; idx++) {
  	int device=0;
  	
  	if(devices[idx]==idx) {
  		if(sendCommand(0x22, CMD_GET_MODEL)==1) {
  			int bufSize = sizeof(buf)/sizeof(buf[0]);
  			receiveString(buf, bufSize);
  			if(strlen(sensorType)==strlen(buf) && strcmp(sensorType, buf)==0) {
  				sensorDevices[sensorIdx]=devices[idx];
  				sensorIdx++;
  				printf("Found Sensor at: 0x%02x\n", devices[idx]);
  			}
  		}
  	}
  }
}

void receiveString(char *buf, int bufSize) {
  int charCount=0;
  
	if(read(file, buf, bufSize) == bufSize) {
		for(charCount=0; charCount<bufSize; charCount++) {
			int temp = (int) buf[charCount];
			
			if(temp==255) {
				buf[charCount]=0;
			}
		}
  }
}

int receiveInt() {
  char buf[1];
  int retVal=0;
  
  if (read(file, buf, 1) == 1) {
  	retVal=(int)buf[0];
  }
  
  return retVal;
}

int sendCommand(int deviceAddress, int cmdCode) {
	int retVal = 0;
	unsigned char cmd[16];
	cmd[0] = cmdCode;
	
	if (ioctl(file, I2C_SLAVE, deviceAddress) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", deviceAddress);
    exit(1);
  }
  
  if (write(file, cmd, 1) == 1) {
  	// As we are not talking to direct hardware but a microcontroller we
    // need to wait a short while so that it can respond.
    //
    // 1ms seems to be enough but it depends on what workload it has
    usleep(10000);
    retVal = 1;
  }
  
  return retVal;
}

 

Compiling the Raspberry Pi code is a bit different as we need to link the math library. In order to do this, we need to add -lm to the command line.

gcc testi2c03d.c -o testi2c03d -lm

Config_I2C_110

Here is the results of running the application.
Config_I2C_112

 

The passing of a string was successful however there are several standards which may be better suited to the goal that I have in mind. One worth further consideration is the System Management Bus (SMBus). For the moment, I am leaving the code as is since the information that I need to send may be sent as simple integer responses. A future enhancement will be to get a better messaging system in place.

The next step is to replace the Arduino with a ATTiny85 and get it all working.