Sunspot Home

more notes for a bad memory - - -

Using an Arduino as an i2c Raspberry Pi slave

Inspired by Peter Mount's Blog - many thanks!

Objective
Drive fast led strip displays and use the A to D

NB!!!!!!
This is "Lesson 1 C code" (Google-copy-modify-pray-test-fix-Google again-run! - - ignore error checking)
It is saved here to back up versions that run.
They are NOT POLISHED YET - but they record progress so far

Start at the beginning
send a single byte to the Arduino and cause LED action

Arduino slave code - arduino_receive_byte.ino

#include <Wire.h>
int number = 0;
void setup()
{
Wire.begin(4); // join i2c bus with address #4
Wire.onReceive(receiveData); // register event
Serial.begin(9600); // start serial for output
Serial.println("hello!");

}
void loop() {
delay(100);
}

//received data
void receiveData(int byteCount){

//==============================================================
while(Wire.available()) {
number = Wire.read();
//================================
if (number == 1){
Serial.println ("1 received - go HIGH");
digitalWrite(13, HIGH); // set the LED on
delay(20000);

Serial.println ("go LOW");
digitalWrite(13, LOW); // set the LED off
delay(20000);
}

//================================
if(number==2) {
Serial.println ("2 received - go HIGH");
digitalWrite(13, HIGH); // set the LED on
delay(20000);

Serial.println ("go LOW");
digitalWrite(13, LOW); // set the LED off
delay(20000);

Serial.println ("go HIGH");
digitalWrite(13, HIGH); // set the LED on
delay(20000);

Serial.println ("go LOW");
digitalWrite(13, LOW); // set the LED off
delay(20000);
}
//================================
// number can be 0 to 255 - 1 byte
Serial.print("number: ");
Serial.println(number);
}
}

Pi C code to send a byte

/*
i2c_byteout_pi.c
----------------------
Send address and byte to arduino slave
--------------------------------------
use gcc i2c_byteout_pi.c -o i2c_byteout_pi

1) send the i2c address
2) send byte to arduino

usage :- type with spaces but without the < >
<PCF8574_addr_byteout_slug> <decimal address> <decimal byte out 0-255>

*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#define I2C_SLAVE 0x0703 /* Change slave address */

int i2c;
//char filename[20];
unsigned long address;

int rc;
unsigned char data[1];

int main(int argc, char *argv[])
{
if (argc != 3) { /* error if we are not getting just 2 inputs after the program name */
fprintf(stderr, "usage: %s <address> <databyte>\n",argv[0]);
exit(1);
}

/* address is the first number after the program name */
address = atoi(argv[1]);

/* the byte to send out to the arduino is the second number
place it into the first element of the buf array */
data[0] = atoi(argv[2]);

// i2c-0 for model B, i2c-1 for B+ and 2
i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */

rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */

write(i2c,data,1) ; /* send the byte */

i2c = close(i2c);
return(0);
}

/* Sunspot (thanks to Google friends) 201115 */



Send 2 bytes from Pi to Arduino to create a 2 byte number
(result must be an Arduino 2 byte word (int fails - why?)- (long (4 bytes) also works)

Arduino slave code - arduino_receive_byte.ino

//Raspi_slave_2_bytes_for_word-works.ino - use with /home/pi/arduino_12c/i2c_twobytesout_pi 4 hi lo


#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int received_byte[6];
int x = 0;
int data[6];
word combined; //- - word or double needed here
//int does not handle ./i2c_twobytesout_pi 4 255 255 >>> 65535

//******************************************************************* START setup
void setup() {
pinMode(13, OUTPUT);

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

// define callbacks for i2c communication
Wire.onReceive(receiveData);
//Wire.onRequest(sendData);

Serial.begin(9600); // open the serial port at 9600 bps:
}
//********************************************************************* END setup


void loop() {

digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(10); // flash 10 msec
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second

// do something repeatedly with these numbers
}

// =================================================================START received data
void receiveData(int byteCount){
//get data from i2c
x = 0;
while(Wire.available()) {
data[x] = Wire.read();
x++;
}
// 1024 is sent as 4 0 (maximum for my sensors)

Serial.print ("data[0] - high byte = ");
Serial.println (data[0]); // the high byte of the 16 bit 1nt
Serial.print ("data[1] - low byte = ");
Serial.println (data[1]); // the low byte of the 16 bit int
Serial.println ("");

combined = data[0]; //send data[1] to rightmost 8 bits
combined = combined<<8; //shift data[1] over to leftmost 8 bits
combined |= data[1]; //logical OR keeps data[1] intact in combined and fills in rightmost 8 bits //rightmost 8 bits

Serial.print ("2 bytes combined into word = ");
Serial.println (combined);
Serial.println ("");


}
// =====================================================================END received data

 

Pi C code to send 2 bytes

/*
i2c_twobytesout_pi.c
----------------------
Send address and 2 bytes to arduino slave
-----------------------------------------
use use gcc i2c_twobytesout_pi.c -o i2c_twobytesout_pi

1) send the i2c address
2) send byte 1 to arduino
3) send byte 2 to arduino

usage :- type with spaces but without the < >
<i2c_twobytesout_pi> <decimal address> <decimal high byte out 0-255><decimal low byte out 0-255>

*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#define I2C_SLAVE 0x0703 /* Change slave address */

int i2c;
//char filename[20];
unsigned long address;

int rc;
unsigned char data[2]; // the received byte store

int main(int argc, char *argv[])
{
if (argc != 4) { /* error if we are not getting just 3 inputs after the program name */
fprintf(stderr, "usage: %s <address> <databyte1> <databyte2> \n",argv[0]);
exit(1);
}

/* address is the first number after the program name */
address = atoi(argv[1]);

/* the first byte to send out to the arduino is the second number
place it into the first element of the buf array */
data[0] = atoi(argv[2]);

/* the second byte to send out to the arduino is the second number
place it into the second element of the buf array */
data[1] = atoi(argv[3]);

// i2c-0 for model B, i2c-1 for B+ and 2
i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */

rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */

//printf("Sending %d\n", data[0]);
//write(i2c,data,1) ; /* send the byte */

//usleep(500000);

printf("Sending %d\n", data[0]);
printf("Sending %d\n", data[1]);
write(i2c,data,2) ; /* send the byte */

i2c = close(i2c);
return(0);
}

/* Sunspot (and thanks to Google friends) 211115 */


A discovery

The Arduino code above (Raspi_slave_2_bytes_for_word-works.ino)
also receives and combines 2 bytes from i2cset that comes with i2c tools
but the high byte cannot be bigger than 0xF9

i2cset -y 0 0x04 0xF9 0xFF b (0 is the unused register, address is 4, high byte, low byte, b means send byte)

The Arduino output is -

data[0] - high byte = 249

data[1] - low byte = 255

2 bytes combined into word = 63999



Send a command number and 2 bytes from Pi to Arduino to create a 2 byte number
and have the Arduino return a 2 byte number (up to 65535) back to the Pi

Pi C code

// /home/pi/arduino_i2c/Pi-Ard_2_bytes_both_ways.c

// general purpose arduino i2c driver - send 2 bytes - first is a command
// receive 2 bytes from the Arduino and combine into a 2 byte number (0-65535)
// use with Arduino code Pi-Ard_2_bytes_both_ways-1
// to compile use gcc Pi-Ard_2_bytes_both_ways.c -o Pi-Ard_2_bytes_both_ways

// use like ./Pi-Ard_2_bytes_both_ways 4 3 255 255 (for i2c address 4 command 3)

#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>

int i2c;
int rc;
unsigned char data[5]; // the received byte store
unsigned long address; // the i2c bus address of the Arduino
int combined;

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

// check for correct input structure
if (argc != 5) {
/* error if we are not getting just 4 inputs after the program name */
fprintf(stderr, "usage: %s <address> <command_byte> <high_byte> <low_byte>\n",argv[0]);
exit(1);
}

// --------------------------------------------------------the arduino i2c address
/* address is the first number after the program name */
address = atoi(argv[1]);
printf("address = %d\n", address);

// ----------------------------------------------------------the command byte
/* the second byte to send out to the arduino is the second number
place it into the first element of the data array - the command byte */
data[0] = atoi(argv[2]);
printf("command = %d\n", data[0]);

// ----------------------------------------------------------the two data bytes
/* the third byte to send out to the arduino is the third number
place it into the second element of the data array */
data[1] = atoi(argv[3]);
printf("data[1] = %d\n", data[1]);

/* the forth byte to send out to the arduino is the forth number
place it into the second element of the data array */
data[2] = atoi(argv[4]);
printf("data[2] = %d\n", data[2]);
// ----------------------------------------------------------------------------

printf("I2C: Connecting\n");

// use /dev/i2c-0 for Pi model B, /dev/i2c-0 for B+ and 2
i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */

printf("I2C: acquiring i2c address 0x%x\n", address);

rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */

unsigned char cmd[16];

printf("Sending command - data[0] %d\n", data[0]);
printf("Sending byte - data[1] %d\n", data[1]);
printf("Sending byte - data[2] %d\n", data[2]);

write(i2c, data, 3);

// 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);

char buf[2];
read(i2c, buf, 2);
int from_arduino1 = (int) buf[0]; // high byte
int from_arduino2 = (int) buf[1]; // low byte
printf("from_arduino1 = %d\n", from_arduino1);
printf("from_arduino2 = %d\n", from_arduino2);

combined = from_arduino1; //send data[1] to rightmost 8 bits
combined = combined<<8; //shift data[1] over to leftmost 8 bits
combined |= from_arduino2; //logical OR keeps data[1] intact in combined and fills in rightmost 8 bits

printf("combine arduino1 and arduino2 into 2 byte number = %d\n", combined);

// make Arduino derived data available for Blassic basic master programs
//save from_arduino1 to ramdisk
FILE *f;
f = fopen("/var/www/ramdisk/from_arduino1.dat","w");
fprintf(f, "%d", from_arduino1);
fclose(f);

//save from_arduino2 to ramdisk
f = fopen("/var/www/ramdisk/from_arduino2.dat","w");
fprintf(f, "%d", from_arduino2);
fclose(f);

//save 2BytesCombined to ramdisk
f = fopen("/var/www/ramdisk/2BytesCombined.dat","w");
fprintf(f, "%d", combined);
fclose(f);


// Now wait else you could crash the arduino by sending requests too fast (not tested)
usleep(10000);

close(i2c);
return(0);
}

Arduino code

// Pi-Ard_2_bytes_both_ways-1 (for Pi code Pi-Ard_2_bytes_both_ways.c)
// Pi first argument defines the i2c address of the Arduino
// then a command number
// then 2 bytes to be combined into a 2 byte word
// then respond to the Pi commands and return a 2 byte number (0-65535) to the Pi
// this program requires a request from the Pi - it is just a slave
// tested with i2c speed of 10,000 (slow for my long line)

#include <Wire.h>
#define SLAVE_ADDRESS 0x04
int number = 0;
int command = 0;
int data[6];
word combined; //- - word or double needed here - int fails (why??)
int x;
double temp;
word send_to_Pi = 0;

//=====================================================================setup START
void setup() {
pinMode(13, OUTPUT);

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

// define callbacks for i2c communication
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
Serial.begin(9600); // open the serial port at 9600 bps:
}
//=====================================================================setup END

//--------------------------------------------------------------------loop START
void loop() {
delay(100);
temp = GetTemp();

if (command==1) {
Serial.print ("command byte 1 received-LED 1 pulse, send_to_Pi is ->");
Serial.println (send_to_Pi);
PrintOut ();
Flash_LED_13();
}

if (command==2) {
Serial.print ("command byte 2 received-LED 2 pulses, send_to_Pi (temperature) is ->");
Serial.println (send_to_Pi);

PrintOut ();

Flash_LED_13();
Flash_LED_13();
}

if (command==3) {
Serial.print ("command byte 3 received-LED 3 pulses, send_to_Pi is ->");
Serial.println (send_to_Pi);
PrintOut ();
Flash_LED_13();
Flash_LED_13();
Flash_LED_13();
}
command = 0;
}
//-----------------------------------------------------------------------loop END

//________________________________________________________________ receive data START
// in this receiveData section do not do actions that take time - it will fail
// just change variables - test them in loop and call functions etc from within loop
void receiveData(int byteCount){
//get data from i2c
x=0;
while(Wire.available()) {
data[x] = Wire.read();
x++;
}

//++++++++++++++++++++++++++++++++++ data[0]=1
if (data[0] == 1){
command = 1;
send_to_Pi = 65535;
}

//++++++++++++++++++++++++++++++++++ data[0]=2
if(data[0] == 2) {
command = 2;
send_to_Pi = (int)temp;
}
//++++++++++++++++++++++++++++++++++data[0]=3
if(data[0] == 3) {
command = 3;
send_to_Pi = 33;
}
//for more than 3 commands use 4, 5, 6 etc for the 2nd argument of the Pi code
}
//___________________________________________________________________ receive data END

//_______________________________________________________________ send data to Pi START
void sendData(){
// enter as byte test[] = {high,low} to send 2 byte number (255 255 gives 65535)
// Pi can use int to contain 2 bytes, Arduino needs word, not int, for 2 bytes (why??)

byte test[] = {highByte(send_to_Pi),lowByte(send_to_Pi)};
Wire.write(test,2);
}
//_______________________________________________________________ send data to Pi END

//============================================================ functions below this line

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION GetTemp
// Get the internal temperature of the arduino
double GetTemp(void)
{
unsigned int wADC;
double t;
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
ADCSRA |= _BV(ADEN); // enable the ADC
delay(20); // wait for voltages to become stable.
ADCSRA |= _BV(ADSC); // Start the ADC
while (bit_is_set(ADCSRA,ADSC));
wADC = ADCW;
t = (wADC - 324.31 ) / 1.22;
return (t);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION PrintOut
void PrintOut(){
Serial.print ("data[0] - command byte = ");
Serial.println (data[0]); // the high byte of the 16 bit 1nt
Serial.print ("data[1] - 2nd byte received = ");
Serial.println (data[1]); // the low byte of the 16 bit int
Serial.print ("data[2] - 3rd byte received = ");
Serial.println (data[2]); // the low byte of the 16 bit int
combined = data[1]; //send data[1] to rightmost 8 bits
combined = combined<<8; //shift data[1] over to leftmost 8 bits
combined |= data[2]; //logical OR keeps data[1] intact in combined and fills in rightmost 8 bits
Serial.print ("data[1] (high byte) and data[2] (low byte) combined into 2byte arduino word = ");
Serial.println (combined);
Serial.println ("");
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION Flash_LED_13
void Flash_LED_13(){
digitalWrite(13, HIGH); // set the LED on
delay(300);
digitalWrite(13, LOW); // set the LED off
delay(300);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Pi ssh session

root@raspberrypi:/home/pi/arduino_i2c# gcc Pi-Ard_2_bytes_both_ways.c -o Pi-Ard_2_bytes_both_ways
root@raspberrypi:/home/pi/arduino_i2c# ./Pi-Ard_2_bytes_both_ways 4 1 0 255
address = 4
command = 1
data[1] = 0
data[2] = 255
I2C: Connecting
I2C: acquiring i2c address 0x4
Sending command - data[0] 1
Sending byte - data[1] 0
Sending byte - data[2] 255
from_arduino1 = 255
from_arduino2 = 255
combine arduino1 and arduino2 into 2 byte number = 65535
root@raspberrypi:/home/pi/arduino_i2c# ./Pi-Ard_2_bytes_both_ways 4 2 255 0
address = 4
command = 2
data[1] = 255
data[2] = 0
I2C: Connecting
I2C: acquiring i2c address 0x4
Sending command - data[0] 2
Sending byte - data[1] 255
Sending byte - data[2] 0
from_arduino1 = 0
from_arduino2 = 26
combine arduino1 and arduino2 into 2 byte number = 26
root@raspberrypi:/home/pi/arduino_i2c# ./Pi-Ard_2_bytes_both_ways 4 3 255 255
address = 4
command = 3
data[1] = 255
data[2] = 255
I2C: Connecting
I2C: acquiring i2c address 0x4
Sending command - data[0] 3
Sending byte - data[1] 255
Sending byte - data[2] 255
from_arduino1 = 0
from_arduino2 = 33
combine arduino1 and arduino2 into 2 byte number = 33
root@raspberrypi:/home/pi/arduino_i2c#

Arduino serial monitor

command byte 1 received-LED 1 pulse, send_to_Pi is ->65535

data[0] - command byte = 1

data[1] - 2nd byte received = 0

data[2] - 3rd byte received = 255

data[1] (high byte) and data[2] (low byte) combined into 2byte arduino word = 255

 

command byte 2 received-LED 2 pulses, send_to_Pi (temperature) is ->26

data[0] - command byte = 2

data[1] - 2nd byte received = 255

data[2] - 3rd byte received = 0

data[1] (high byte) and data[2] (low byte) combined into 2byte arduino word = 65280

 

command byte 3 received-LED 3 pulses, send_to_Pi is ->33

data[0] - command byte = 3

data[1] - 2nd byte received = 255

data[2] - 3rd byte received = 255

data[1] (high byte) and data[2] (low byte) combined into 2byte arduino word = 65535




Now add some sensors etc to the Arduino
NB just a first try!!

A 2000 ohm linear potentiometer feeds 0 to 5 volts to pin A2
A WS2812 8 LED 3 colour bar has the data lead connected to pin D8

I see
"Sketch uses 7,808 bytes (25%) of program storage space. Maximum is 30,720 bytes"
Thanks to Adafruit

Arduino code

// Pi-Ard_2_bytes_both_ways-pot-1 (for Pi code Pi-Ard_2_bytes_both_ways.c)
// Pi first argument defines the i2c address of the Arduino 23/11/15 20:26
// then a command number
// then 2 bytes to be combined into a 2 byte word
// then respond to the Pi commands and return a 2 byte number (0-65535) to the Pi
// this program requires a request from the Pi - it is just a slave
// tested wit i2c speed of 10,000 (slow for my long line)

#include <Wire.h>

#include <Adafruit_NeoPixel.h>
#define PIN 8
Adafruit_NeoPixel strip = Adafruit_NeoPixel(8, PIN, NEO_GRB + NEO_KHZ800);

#define SLAVE_ADDRESS 0x04


int number = 0;
int command = 0;
int data[6];
word combined = 0; //- - word or double needed here - int fails (why??)
int x;
double temp;
word send_to_Pi = 0;

int potPin = 2; // select the input pin for the potentiometer
int potval = 0; // variable to store the value coming from the sensor

//=====================================================================setup START
void setup() {

strip.begin();// Initialize all the variables
strip.show(); // Initialize all pixels to 'off'


pinMode(13, OUTPUT);


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

// define callbacks for i2c communication
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
Serial.begin(9600); // open the serial port at 9600 bps:
}
//=====================================================================setup END

//--------------------------------------------------------------------loop START
void loop() {

 

// BarDisplay(potval);

delay(100);
temp = GetTemp();

if (command==1) {
Serial.print ("command byte 1 received-LED 1 pulse, send_to_Pi is ->");
Serial.println (send_to_Pi);
PrintOut ();
Flash_LED_13();
BarDisplay(combined);

}

if (command==2) {
Serial.print ("command byte 2 received-LED 2 pulses, send_to_Pi (temperature) is ->");
Serial.println (send_to_Pi);

PrintOut ();

Flash_LED_13();
Flash_LED_13();
}

if (command==3) {
Serial.print ("command byte 3 received-LED 3 pulses, send_to_Pi is ->");
Serial.println (send_to_Pi);
PrintOut ();
Flash_LED_13();
Flash_LED_13();
Flash_LED_13();
}
command = 0;
}
//-----------------------------------------------------------------------loop END

//___________________________________________________________________ receive data START
// in this receiveData section do not do actions that take time - it will fail
// just change variables - test them in loop and call functions etc from within loop
void receiveData(int byteCount){
//get data from i2c
x=0;
while(Wire.available()) {
data[x] = Wire.read();
x++;
}

//++++++++++++++++++++++++++++++++++ data[0]=1
if (data[0] == 1){
command = 1;
send_to_Pi = 65535;
}

//++++++++++++++++++++++++++++++++++ data[0]=2
if(data[0] == 2) {
command = 2;
send_to_Pi = (int)temp;
}
//++++++++++++++++++++++++++++++++++data[0]=3
if(data[0] == 3) {
command = 3;
send_to_Pi = potval; //the potentiometer value (connected to E and 5V - centre pin gives 1 to 1023)
}
//for more than 3 commands use 4, 5, 6 etc for the 2nd argument of the Pi code
}
//_____________________________________________________________________ receive data END

//_______________________________________________________________ send data to Pi START
void sendData(){
// enter as byte test[] = {high,low} to send 2 byte number (255 255 gives 65535)
// Pi can use int to see contain this, Arduino needs word, not int, for 2 bytes (why??)

byte test[] = {highByte(send_to_Pi),lowByte(send_to_Pi)};
Wire.write(test,2);
}
//_______________________________________________________________ send data to Pi END

//============================================================ functions below this line

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION GetTemp
// Get the internal temperature of the arduino
double GetTemp(void)
{
unsigned int wADC;
double t;
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
ADCSRA |= _BV(ADEN); // enable the ADC
delay(20); // wait for voltages to become stable.
ADCSRA |= _BV(ADSC); // Start the ADC
while (bit_is_set(ADCSRA,ADSC));
wADC = ADCW;
t = (wADC - 324.31 ) / 1.22;
return (t);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION PrintOut
void PrintOut(){
Serial.print ("data[0] - command byte = ");
Serial.println (data[0]); // the high byte of the 16 bit 1nt
Serial.print ("data[1] - 2nd byte received = ");
Serial.println (data[1]); // the low byte of the 16 bit int
Serial.print ("data[2] - 3rd byte received = ");
Serial.println (data[2]); // the low byte of the 16 bit int
combined = data[1]; //send data[1] to rightmost 8 bits
combined = combined<<8; //shift data[1] over to leftmost 8 bits
combined |= data[2]; //logical OR keeps data[1] intact in combined and fills in rightmost 8 bits
Serial.print ("data[1] (high byte) and data[2] (low byte) combined into 2byte arduino word = ");
Serial.println (combined);
Serial.println ("");
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION Flash_LED_13
void Flash_LED_13(){
digitalWrite(13, HIGH); // set the LED on
delay(300);
digitalWrite(13, LOW); // set the LED off
delay(300);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION LED Strip
// function to creat bar of LEDs depending on value of 2 byte variable "combined" above
// color values chosen for even brightness
void BarDisplay(int x) {
// set all leds to go off unless state changed below
for (int i=0; i <= 7; i++){strip.setPixelColor(i, strip.Color(0, 0, 0));}
if (x >= 113) { strip.setPixelColor(0, strip.Color(30, 30, 30));} // white
if (x >= 227) { strip.setPixelColor(1, strip.Color(30, 30, 30));} // white
if (x > 340 && x <= 454)
{for (int i=0; i <= 2; i++){strip.setPixelColor(i, strip.Color(0, 60, 0));}} // green}
if (x > 454 && x<= 568)
{for (int i=0; i <= 3; i++){strip.setPixelColor(i, strip.Color(0, 60, 0));}} // green}
if (x > 568 && x<= 682)
{for (int i=0; i <= 4; i++){strip.setPixelColor(i, strip.Color(0, 0, 60));}} // blue
if (x > 682 && x<= 796)
{for (int i=0; i <= 5; i++){strip.setPixelColor(i, strip.Color(0, 0, 60));}} // blue
if (x > 796 && x<= 911)
{for (int i=0; i <= 6; i++){strip.setPixelColor(i, strip.Color(40, 0, 0));}} // red
if (x > 911)
{for (int i=0; i <= 7; i++){strip.setPixelColor(i, strip.Color(40, 0, 0));}} // red
strip.show();
}
// note - 8 steps as gaps between these numbers -0 113 227 340 454 568 682 796 911 1024
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

 

./Pi-Ard_2_bytes_both_ways 4 1 4 0
sends the maximum signal (1024) to the LED strip and it lights up all red





How fast will this crude code run ?
- remove all the delays and print statements

Pi code without print statements

// /home/pi/arduino_i2c/Pi-Ard_2_bytes_both_ways_save_to_ram_int_in.c

// general purpose arduino i2c driver - send 2 bytes - first is a command
// receive 2 bytes from the Arduino and combine into a 2 byte number (0-65535)
// use with Arduino code Pi-Ard_2_bytes_both_ways-1
// to compile use
// 1024

// use like ./Pi-Ard_2_bytes_both_ways 4 1 65535
// (for i2c address 4, command 1, number to send (max is 65535 for the 2 i2c 8 bit bytes to be sent)

#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>

int i2c;
int rc;
unsigned char data[5]; // the received byte store
unsigned long address; // the i2c bus address of the Arduino
int combined;
int input_int;

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

// check for correct input structure
if (argc != 4) {
/* error if we are not getting just 4 inputs after the program name */
fprintf(stderr, "usage: %s <address> <command_byte> <input_number>\n",argv[0]);
exit(1);
}

// --------------------------------------------------------the arduino i2c address
/* address is the first number after the program name */
address = atoi(argv[1]);
// printf("address = %d\n", address);

// ----------------------------------------------------------the command byte
/* the second byte to send out to the arduino is the command number
place it into the first element of the data array - the command byte */
data[0] = atoi(argv[2]);
// printf("command = %d\n", data[0]);

// ----------------------------------------------------------input_int
/* the third byte to send out to the arduino is the third number
we expect a number to be split below into 2 bytes, data[1] and data[2], for i2c */
input_int = atoi(argv[3]);
// printf("input_int; = %d\n", input_int);

// ----------------------------------------------------------------------------

data[2] = input_int & 0xff; // create the low byte
data[1] = (input_int >> 8); // create the high byte

// printf("data[2] low byte; = %d\n", data[2]);
// printf("data[1] high byte; = %d\n", data[1]);


// printf("I2C: Connecting\n");

// use /dev/i2c-0 for Pi model B, /dev/i2c-0 for B+ and 2
i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */

//printf("I2C: acquiring i2c address 0x%x\n", address);

rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */

unsigned char cmd[16];

// printf("Sending command - data[0] %d\n", data[0]);
// printf("Sending byte - data[1] %d\n", data[1]);
// printf("Sending byte - data[2] %d\n", data[2]);

write(i2c, data, 3);

// 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);

char buf[2];
read(i2c, buf, 2);
int from_arduino1 = (int) buf[0]; // high byte
int from_arduino2 = (int) buf[1]; // low byte
// printf("from_arduino1 = %d\n", from_arduino1);
// printf("from_arduino2 = %d\n", from_arduino2);

combined = from_arduino1; //send data[1] to rightmost 8 bits
combined = combined<<8; //shift data[1] over to leftmost 8 bits
combined |= from_arduino2; //logical OR keeps data[1] intact in combined and fills in rightmost 8 bits

// printf("combine arduino1 and arduino2 into 2 byte number = %d\n", combined);

// make Arduino derived data available for Blassic basic master programs
//save from_arduino1 to ramdisk
/* FILE *f;
f = fopen("/var/www/ramdisk/from_arduino1.dat","w");
fprintf(f, "%d", from_arduino1);
fclose(f);

//save from_arduino2 to ramdisk
f = fopen("/var/www/ramdisk/from_arduino2.dat","w");
fprintf(f, "%d", from_arduino2);
fclose(f);

//save 2BytesCombined to ramdisk
f = fopen("/var/www/ramdisk/2BytesCombined.dat","w");
fprintf(f, "%d", combined);
fclose(f);
*/
// Now wait else you could crash the arduino by sending requests too fast (not tested)
usleep(10000);

close(i2c);
return(0);
}

Arduino code without print statements
This could be much faster with better use of the NeoPixel LED code -
I am trying to determine whether the Pi should not be employed in the loop
when I display live changes in sound detected on a microphone

// Pi-Ard_2_bytes_both_ways-pot-1 (for Pi code Pi-Ard_2_bytes_both_ways.c)
// Pi first argument defines the i2c address of the Arduino 23/11/15 20:26
// then a command number
// then 2 bytes to be combined into a 2 byte word
// then respond to the Pi commands and return a 2 byte number (0-65535) to the Pi
// this program requires a request from the Pi - it is just a slave
// tested wit i2c speed of 10,000 (slow for my long line)

#include <Wire.h>

#include <Adafruit_NeoPixel.h>
#define PIN 8
Adafruit_NeoPixel strip = Adafruit_NeoPixel(8, PIN, NEO_GRB + NEO_KHZ800);

#define SLAVE_ADDRESS 0x04


int number = 0;
int command = 0;
int data[6];
word combined = 0; //- - word or double needed here - int fails (why??)
int x;
double temp;
word send_to_Pi = 0;

int potPin = 2; // select the input pin for the potentiometer
int potval = 0; // variable to store the value coming from the sensor

//=====================================================================setup START
void setup() {

strip.begin();// Initialize all the variables
strip.show(); // Initialize all pixels to 'off'


pinMode(13, OUTPUT);


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

// define callbacks for i2c communication
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
// Serial.begin(9600); // open the serial port at 9600 bps:
}
//=====================================================================setup END

//--------------------------------------------------------------------loop START
void loop() {

 

// BarDisplay(potval);

delay(100);
temp = GetTemp();

if (command==1) {
// Serial.print ("command byte 1 received-LED 1 pulse, send_to_Pi is ->");
// Serial.println (send_to_Pi);
PrintOut ();
//Flash_LED_13();
BarDisplay(combined);

}

if (command==2) {
// Serial.print ("command byte 2 received-LED 2 pulses, send_to_Pi (temperature) is ->");
// Serial.println (send_to_Pi);

PrintOut ();

//Flash_LED_13();
//Flash_LED_13();
}

if (command==3) {
// Serial.print ("command byte 3 received-LED 3 pulses, send_to_Pi is ->");
// Serial.println (send_to_Pi);
PrintOut ();
//Flash_LED_13();
//Flash_LED_13();
//Flash_LED_13();
}
command = 0;
}
//-----------------------------------------------------------------------loop END

//__________________________________________________________________________________ receive data START
// in this receiveData section do not do actions that take time - it will fail
// just change variables - test them in loop and call functions etc from within loop
void receiveData(int byteCount){
//get data from i2c
x=0;
while(Wire.available()) {
data[x] = Wire.read();
x++;
}

//++++++++++++++++++++++++++++++++++ data[0]=1
if (data[0] == 1){
command = 1;
send_to_Pi = 65535;
}

//++++++++++++++++++++++++++++++++++ data[0]=2
if(data[0] == 2) {
command = 2;
send_to_Pi = (int)temp;
}
//++++++++++++++++++++++++++++++++++data[0]=3
if(data[0] == 3) {
command = 3;
send_to_Pi = potval; //the potentiometer value (connected to E and 5V - centre pin gives 1 to 1023)
}
//for more than 3 commands use 4, 5, 6 etc for the 2nd argument of the Pi code
}
//____________________________________________________________________________________ receive data END

//_______________________________________________________________ send data to Pi START
void sendData(){
// enter as byte test[] = {high,low} to send 2 byte number (255 255 gives 65535)
// Pi can use int to see contain this, Arduino needs word, not int, for 2 bytes (why??)

byte test[] = {highByte(send_to_Pi),lowByte(send_to_Pi)};
Wire.write(test,2);
}
//_______________________________________________________________ send data to Pi END

//============================================================ functions below this line

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION GetTemp
// Get the internal temperature of the arduino
double GetTemp(void)
{
unsigned int wADC;
double t;
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
ADCSRA |= _BV(ADEN); // enable the ADC
delay(20); // wait for voltages to become stable.
ADCSRA |= _BV(ADSC); // Start the ADC
while (bit_is_set(ADCSRA,ADSC));
wADC = ADCW;
t = (wADC - 324.31 ) / 1.22;
return (t);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION PrintOut
void PrintOut(){
/*Serial.print ("data[0] - command byte = ");
Serial.println (data[0]); // the high byte of the 16 bit 1nt
Serial.print ("data[1] - 2nd byte received = ");
Serial.println (data[1]); // the low byte of the 16 bit int
Serial.print ("data[2] - 3rd byte received = ");
Serial.println (data[2]); // the low byte of the 16 bit int */
combined = data[1]; //send data[1] to rightmost 8 bits
combined = combined<<8; //shift data[1] over to leftmost 8 bits
combined |= data[2]; //logical OR keeps data[1] intact in combined and fills in rightmost 8 bits
//Serial.print ("data[1] (high byte) and data[2] (low byte) combined into 2byte arduino word = ");
//Serial.println (combined);
//Serial.println ("");
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION Flash_LED_13
void Flash_LED_13(){
digitalWrite(13, HIGH); // set the LED on
delay(300);
digitalWrite(13, LOW); // set the LED off
delay(300);
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FUNCTION LED Strip
// function to create bar of LEDs depending on value of 2 byte variable "combined" above
// color values chosen for even brightness
void BarDisplay(int x) {
// set all leds to go off unless state changed below
for (int i=0; i <= 7; i++){strip.setPixelColor(i, strip.Color(0, 0, 0));}
if (x >= 113) { strip.setPixelColor(0, strip.Color(30, 30, 30));} // white
if (x >= 227) { strip.setPixelColor(1, strip.Color(30, 30, 30));} // white
if (x > 340 && x <= 454)
{for (int i=0; i <= 2; i++){strip.setPixelColor(i, strip.Color(0, 60, 0));}} // green}
if (x > 454 && x<= 568)
{for (int i=0; i <= 3; i++){strip.setPixelColor(i, strip.Color(0, 60, 0));}} // green}
if (x > 568 && x<= 682)
{for (int i=0; i <= 4; i++){strip.setPixelColor(i, strip.Color(0, 0, 60));}} // blue
if (x > 682 && x<= 796)
{for (int i=0; i <= 5; i++){strip.setPixelColor(i, strip.Color(0, 0, 60));}} // blue
if (x > 796 && x<= 911)
{for (int i=0; i <= 6; i++){strip.setPixelColor(i, strip.Color(40, 0, 0));}} // red
if (x > 911)
{for (int i=0; i <= 7; i++){strip.setPixelColor(i, strip.Color(40, 0, 0));}} // red
strip.show();
}
// note - 8 steps as gaps between these numbers -0 113 227 340 454 568 682 796 911 1024
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


I like the ease of use of Blassic basic as a control script to schedule C programs and bash scripts

#!/usr/sbin/blassic

' /home/pi/arduino_i2c/pi_drive_arduino_scan.bas <address>
' ./pi_drive_arduino_scan.bas 4

address$ = programarg$(1)

command$ = "1"

LABEL StartAgain

for i=1024 to 0 STEP -114
input_int$ = STR$(i)

Arduino_C_driver$ = "/home/pi/arduino_i2c/Pi_send_int_to_ard_no_printout "+address$+" "+command$+" "+input_int$

'PRINT " i2c address is ",address$
'PRINT " number to send to Arduino = ",input_int$
'PRINT Arduino_C_driver$

SHELL Arduino_C_driver$
'PRINT " i = ",i
next i

GOTO StartAgain

SYSTEM

The 8 LEDs scan in just over 1 second
I think the function void BarDisplay(int x) could be driven faster with cleaner code

Long term objective
Try to display the sound of bee activity via a low frequency filter to detect swarms and use the bar graph as an active sound level display.
- ESP8266 with microphone, MSGEQ7as frequency filter, swarm noise frequency channel level sampling at the bee hive
- - wifi to LAN - - Pi to send amplitude to Arduino and NeoPixel .
Perhaps?
https://deadbird.fr/?p=671

- so more to come . . . .


Please email me if you want to swap notes

SUNSPOT HOME