Show Posts
Pages: [1] 2 3 4
1  Using Arduino / Programming Questions / Re: I2C between arduinos on: February 28, 2014, 11:25:37 pm
Paul,
Thanks for taking the time to go through all this with me. If you're ever in the Bay Area, I owe you copious amounts of great coffee.

One major point that has provided some better results is the fact that I was telling the chip to write an array, but not telling it how many bytes of that array to write. It's in the notes here on arduino, but not emphasized. I really wish there were a way to enhance the documentation for arduino from users in something other than the forum. For all it's flaws, a digg model seems like it should have happened long ago. Upvoting good solutions to common problems needs to happen.

Still, I'm not getting exactly what I want and there are a few points for clarification.

1)
Quote
Doesn't matter if there is room in the array?

Yes, it does. With a well-structured program (which resets the index to zero in one of its functions before writing to the array), this doesn't seem completely necessary to check, though the code might prove more useful to others and applications outside what I'm intending. I'm thinking a while loop nested within that else if which checks that the index is less than the size of the array of inSerial might be a place to start.

2
Quote
NO! NEVER assume that strtok() will return something other than NULL

Yikes! Well, I was going on one of your previous posts here. I'm a little confused over the emphatic "NO!"  -- if strtok returns NULL, is that necessarily bad? At least for future strtok calls? For example, if I wanted to have an array which assigned values to variables, a NULL within an array would simply assign NULL to that variable, correct? That seems like it could be useful in some instances. Now, a check that what strtok returns isn not NULL might affect how one handles those bytes of the array -- i.e. not trying to convert ASCII to an int if NULL

3)
Quote
I don't like this.
Upon further inspection, I don't either. If a byte didn't transmit, things could get wonky real quick. Would something like while(Wire.available()==intBytesToCall) be a good check? Perhaps some sort of if/else schema that if the wire buffer does not contain the expected number of bytes, a re-transmit of the last (maybe command) and request?

4)
Quote
You are passing a non-NULL terminated array
Where?

On a couple of other notes/questions:

Variable names have been updated so if I want a $, that can be done easily.

The packet is contained within "<" and ">" I was using the ";" to signal the end of the packet so that if an application demanded it, ";" could be used within the array  if the ">" had not yet been transmitted (not important to my application, but I thought this might be useful). Somehow, I thought it better to have both > and ; indicate the end of relevant data. Any downfalls to keeping this? I kind of only see an upside -- at the expense of 1 byte transmitted, there would be a double check on the end of packet(">") and the terminator(";").

On missing something, you're not. Well, not really. I condensed my code so that issues could be identified with how I'm doing things in the code, rather than checking every step and it elicited exactly the type of critiques I was looking for from you. Mirrored code with Serial.println on the master and mySerial.print on the slave (yes, regrettably, I'm using a Parallax LCD on the slave for debugging, and software serial is involved) is on my computer, and that's what I'm applying the concepts to.
2  Using Arduino / Programming Questions / Re: I2C between arduinos on: February 26, 2014, 11:16:38 pm
Paul, Thanks for the suggestion. I've played around with this a bit, and keep hitting my head against the wall. Much of what is out there on I2C is painfully unclear. I've gone with multiple iterations, debugging with a LCD attached to the slave to see what is coming in, and printing from the master to the serial monitor. So, I'm including a revised copy of my code that is stripped down without the particulars for my LCD and most of my debug Serial.println entries, but still verbose enough that I think it should be clear to see what I'm trying to do, and where I must be going wrong (I hope). I know there are some issues you mentioned with globals and passing variables, but I'm really more concerned with the I2C communication right now, and passing variables can come later. Here goes:

Code:
//Serial to I2C and back Master
#include<Wire.h>
char inSerial[20];
char serInChar;
int index;



char I2CHandler;     
char I2CCommandArray[9];


//constants for charArray constructor
char openBracket = '<';
char token =':';
char closeBracket ='>';
char terminator =';';
char nullCharacter ='\0';

// currently still using globals here - haven't quite worked out the passing of variables to other functions
// Rx/Tx over I2C is the priority for now

int intSlaveID;
int intFunctionToCall;
int intBytesToCall;
int intParameterToPass;
int caseToUse;
char slaveIDHighByte;
char slaveIDLowByte;
char functionToCallHigh;
char functionToCallLow;
char parameterToPassHigh;
char parameterToPassLow;

char responseArray[12];

boolean startOfSerEvent = false;
boolean endOfSerEvent = false;


void setup ()
{
  delay(750); // to prevent errors in displaying initial comments -- probably
  //should not be commented out, even if the Serial.println's
  //called here are. Still trying to figure out why serial
  //monitor sometimes prints these lines twice.
  Serial.begin(9600);
  Serial.println("Initialize library for I2C Master Test");
  Wire.begin(1);
  delay(750);
  Serial.println("Wire initialized");
  caseToUse = 1;


}


void loop()
{
  switch(caseToUse)
  {
  case 1:
    SerialReceiveEvent();
    break;
  case 2:
    createCommandArray();
    break;
  case 3:
    sendCommand();
    break;
  case 4:
    requestResponse();
    break;
  }
}


void SerialReceiveEvent()
{
  while (Serial.available()>0)
  {
    char serInChar =(char)Serial.read();     

    if (serInChar == '<')
    {
      startOfSerEvent = true;
    } 
    else if (serInChar == '>')
    {
      endOfSerEvent = true;
    }
    if (serInChar == ';' && startOfSerEvent && endOfSerEvent)
    {
      inSerial[index] = '\0'; // Null terminate the string
      startOfSerEvent =false;
      endOfSerEvent =false;
      caseToUse = 2;
    }
    else if (startOfSerEvent && serInChar != '<' && serInChar != '>')
    {
      inSerial[index] = serInChar;
      index++;
    }
  }
}

void createCommandArray()
{

  intSlaveID = atoi(strtok(inSerial, ":"));
  intFunctionToCall = atoi(strtok(NULL, ":"));
  intBytesToCall = atoi(strtok(NULL, ":"));
  intParameterToPass = atoi(strtok(NULL, ":"));

  functionToCallLow = lowByte(intFunctionToCall);
  functionToCallHigh = highByte(intFunctionToCall);
  parameterToPassHigh = highByte(intParameterToPass);
  parameterToPassLow = lowByte(intParameterToPass);


  I2CCommandArray[0] = openBracket;
  I2CCommandArray[1] = functionToCallLow;
  I2CCommandArray[2] = functionToCallHigh;
  I2CCommandArray[3] = token;
  I2CCommandArray[4] = parameterToPassLow;
  I2CCommandArray[5] = parameterToPassHigh;
  I2CCommandArray[6] = token;
  I2CCommandArray[7] = closeBracket;
  I2CCommandArray[8] = terminator;
  I2CCommandArray[9] = nullCharacter;

  caseToUse = 3;

}


void sendCommand()
{
  Serial.println ("Send serial to i2c as command");
  Wire.beginTransmission(intSlaveID);
  Wire.write(I2CCommandArray);
  Wire.endTransmission();
  caseToUse = 4;
}



void requestResponse() //receive a byte array, and parse that array into appropriate variables.
{
  Serial.println("Requesting from I2C");
  int i;
  Wire.requestFrom(intSlaveID, intBytesToCall);
  while(Wire.available())
  {
    for(i=0; i<intBytesToCall; i++)
    {
      responseArray[i] = Wire.read();
      Serial.println(responseArray);
    }
    responseArray[i] ='\0';
  }
  // Serial.println(I2CRequestResponseArray);
  Serial.println("Read the response");
  Serial.println(responseArray);
  caseToUse = 1;
}

Code:
//I2C and back
#include <Wire.h>
int intSlaveID = 2;

//constants for charArray constructor -- just to make things easy
char openBracket = '<';
char token =':';
char closeBracket ='>';
char terminator =';';
char nullCharacter ='\0';

 // yes, this is all very verbose, but I've been all over the place trying to get this to work

char I2CinChar;
char inI2C[10];
                /*allocate space for the inI2C command array
                 this particular allocation is intended for the following:
                inI2C[0] = <                     |     start of incoming string
                inI2C[1] = functionToCall        |     low byte
                inI2C[2] = functionToCall        |     high byte
                inI2C[3] =  ':'                  |     token seperator
                inI2C[4] = parameterToUse        |     low byte
                inI2C[5] = parameterToUse        |     high byte
                inI2C[6] =  ':'                  |     token seperator
                inI2C[7] =  '>'                  |     end of incoming string
                inI2C[8] = ';'                   |     terminator
                inI2C[9] = null terminator       |     
                inI2C[10]                        | to keep array even - necessary?
                */
int functionToCall;
int parameterToUse;               
int I2CInIndex;


char outI2C[10];
                /*allocate space for the response array
                 this particular allocation is intended for the following:
                inI2C[0] = <               | start of out string
                inI2C[1] = functionIDLow   | low byte
                inI2C[2] = functionIDHigh  | high byte
                inI2C[3] =  ':'            | token seperator
                inI2C[4] = variableLow     | low byte
                inI2C[5] = variableHigh    | high byte
                inI2C[6] =  '>'            | end of out string
                inI2C[7] =  ';'            | terminator
                inI2C[8] = '\0'            | null character               
                */

//for the sake of getting this set up, I'm assiging arbitary values to the functionID and the variable

int functionID=19234;
char functionIDLow;
char functionIDHigh;
int variable=16523;
char variableLow;
char variableHigh;               
int I2COutIndex;


boolean startOfI2CEvent = false;
boolean endOfI2CEvent = false;



void setup ()
{
  Wire.begin(intSlaveID);
  Wire.onRequest(TxHandler);
  Wire.onReceive(RxHandler);
}


void RxHandler(int howMany)
{
  while(Wire.available()>0) 
      {
    for (int i = 0; i < 12; i++)
      inI2C[i] = Wire.read();
    }
    processI2CBuffer();
}


void TxHandler()
{
  Wire.beginTransmission(1);
  Wire.write(outI2C);
  Wire.endTransmission();
}


void processI2CBuffer()
{
  functionToCall = atoi(strtok(inI2C, ":"));
  parameterToUse = atoi(strtok(NULL, ":"));
  inI2C[10] = NULL;
  createCharOutI2C(); 
}

void createCharOutI2C()
{
  outI2C[0] = openBracket;
  functionIDLow = lowByte(functionID);
  outI2C[1] = functionIDLow;
  functionIDHigh = highByte(functionID);
  outI2C[2] = functionIDHigh;
  outI2C[3] = token;
  variableLow = lowByte(variable);
  outI2C[4] = variableLow;
  variableHigh = highByte(variable);
  outI2C[5] = variableHigh;
  outI2C[6] = token;
  outI2C[7] = closeBracket;
  outI2C[8] = terminator;
  outI2C[9] = nullCharacter;
}
//I know this is ugly, but I'm taking this stepwise.

void loop()
{

}

3  Using Arduino / Programming Questions / Re: I2C between arduinos on: February 02, 2014, 05:44:16 pm
Paul, I've updated my post per your suggestion on the Auto Format front. I hope that makes it a bit easier to decipher.

As far as global variables, I intend to use the variables within other function calls (not listed in this code). If the variables are not global, they disappear when the function they are defined in ends, correct?

I'm not sure how I'm casting a string to a byte. I was under the impression that I was casting the tokenized string to a short. Should I replace
Code:
(short)strtok(inCMD, ":");
with
Code:
atoi(strtok(inCMD, ":"));
?
4  Using Arduino / Programming Questions / I2C between arduinos on: February 02, 2014, 04:59:01 pm
I'm attempting to get a working example of sending commands from one Arduino to another, receiving information back via I2C and printing that to the serial monitor.  I've tried to set this up so that the master takes Serial input from the keyboard and parse the input into the commands used, only nothing gets printed to the serial monitor when i issue what I think should be a correct set of instructions. Here's the code I've come up with for master and slave. Any guidance?

Master:
Code:
//master
#include <Wire.h>
byte index;
short Variable1;
short Variable2;
short CMD;
int handler;
byte inI2Cbyte;
char inI2C[32];
byte I2Cindex;
char inChar;
char inCMD[32];
short I2CSystem;
short I2CStatus1;
short I2CStatus2;


void setup()
{
  Serial.begin(9600);
  Wire.begin();
  while(Serial.available() > 0)
  {
    inChar = Serial.read();
    if(inChar != ';' && index < 32) //":" is the terminator. Send ":" to indicate end of command?
      // while the inChar read from Serial.read does not contain terminator :, and the index is less than 15
    {
      inCMD[index] = inChar; //sets the inChar to the number in index, starting with 0
      index++; //increments the index by one
      inCMD[index] = '\0'; // this seems to add a null character to the char array. Is that necessary or desirable?
    }
    else if(inChar== ';')
    {
      Variable1 =(short)strtok(inCMD, ":");
      Variable2 =(short)strtok(inCMD, ":");
      CMD = (short)strtok(inCMD, ":");
      handler = 1;
      index = 0;
    }
  }

  inI2Cbyte = Wire.read();
  if(inI2Cbyte != ';') // ; terminates the read and causes a serialprint
  {
    inI2C[index] = inI2Cbyte; //sets the inChar to the number in index, starting with 0
    index++; //increments the index by one
    inI2C[index] = '\0'; // this seems to add a null character to the char array. Is that necessary or desirable?
  }
  else if(inI2Cbyte == ';')  // Now, split the string to variables
  {
    I2CSystem = (short)strtok(inI2C, ":");
    I2CStatus1 = (short)strtok(NULL, ":");
    I2CStatus2 = (short)strtok(NULL, ":");
    I2Cindex = 0;
    Serial.print(I2CSystem);
    Serial.print(I2CStatus1);
    Serial.print(I2CStatus2);
  }
  else if(inI2Cbyte == '?')   
  {
    Serial.print("Error getting" + CMD);
  }
}

void loop()
{
  while(handler = 1)
  {
    Wire.beginTransmission(2);
    Wire.write(Variable1);
    Wire.write(":");
    Wire.write(Variable2);
    Wire.write(":");
    Wire.write(CMD);
    Wire.write(";");
    Wire.endTransmission();
    Wire.requestFrom(2, 32);
    CMD = 0;
    handler = 0;
  }

}



Code:
//slave
#include <Wire.h>
byte index;
short Variable1;
short Variable2;
short CMD;
byte inI2Cbyte;
char inI2C[32];



void setup()
{
  Wire.begin(2);                // join i2c bus with address #2 (slave)
  Wire.onRequest(requestEvent); //declares that when I2C sends an onRequest, the function
  //requestEvent() gets called
  Wire.onReceive(recieveEvent); // declares that when I2C sends a command, the variable
  //CMD gets updated by this function
}


void requestEvent()
{
  switch(CMD)
  {
  case 1:
    sendVariable1();
    break;
  case 2:
    sendVariable2();
    break;
  default:
    break;
  }   
}

void recieveEvent(int howMany)
{
  inI2Cbyte = Wire.read();
  if(inI2Cbyte != ';') //; will indicate there was an error getting temperature.
  {
    inI2C[index] = inI2Cbyte; //sets the inChar to the number in index, starting with 0
    index++; //increments the index by one
    inI2C[index] = '\0'; // this seems to add a null character to the char array. Is that necessary or desirable?
  }
  else if(inI2Cbyte == ';')  // Now, split the string to variables
  {
    Variable1 = (short)strtok(inI2C, ":");
    Variable2 = (short)strtok(NULL, ":");
    CMD = (short)strtok(NULL, ":");
    index = 0;
  }

}


void sendVariable1()
{
  Wire.write(Variable1);
}

void sendVariable2()
{
  Wire.write(Variable2);
}

void loop()
{
}
5  Using Arduino / Project Guidance / Re: Multiple Wire.OnRequest handlers on: November 22, 2013, 02:54:31 pm
Rob... wow. Excellent and comprehensive answers. Thank you. I still have some questions for clarification, which you seem to be extraordinarily apt in soliciting answers from on this topic.

In respect to pin state changes, telling a pin to go high or low in a function is super easy, but I'm left wondering if the command handler itself might not be the best place to implement a change in state like this.

There are a couple examples I can think of where including a pin high/low designation in the handler might be a good thing: i.e. to indicate the "CMD" sent is being implemented (like turning on an LED to indicate a function is running). However, most of the time, it seems like there would be more control over how and under what circumstances something like a pin state on a slave goes from high to low if it were in the function designated by the handler. i.e. setting a pin high if a temperature probe reaches some threshold.

You indicated
Quote
Yes, one step further you even can give parameters with the command, e.g. how lon a pulse should take or the precision of a sensor...

Can you give an example on how this is done? I'm guessing the parameters one would pass to a function would need to be predefined on the slave's command handler functions in a way like this:
Code:
void requestEvent()
{
  switch(CMD)
  {
  case 0x01: ABC(some parameter); break;
  case 0x02: ABC(some other parameter); break;

It doesn't seem like there is an easy way to have the master dynamically update a parameter the slave's handler function uses, as receiveEvent() assigns to the variable CMD, and I can't think of a great way to update another variable without some complicated test. So... assuming that using the variable CMD to indicate which pre-defined parameter you want to pass to a given function like ABC(), what are the options for variables to pass, and how would ABC() interpret what it is passed?


  
6  Using Arduino / Project Guidance / Re: Multiple Wire.OnRequest handlers on: November 22, 2013, 02:54:00 am
This is exactly what I've been looking for, but there are some things that I need some clarification on:
Code:
void ABC()
{
  byte value = readsensor();
  send(value);
}

It seems the function ABC() has a locally declared variable "value" that is updated by calling an external function: readsensor().
Am I correct there? If this is the case, sending one of those "CMD"s from the master to the slave might be a good way to initiate a state change on a pin from low to high, provided it is part of a function like readSensor(), right? Essentially, the master could send a slave a command from a list of functions the slave has, then call for that slave to execute the function corresponding to the command it just declared, whatever it entails.

If this is the case, I'm sitting pretty good. Still,  how would something like an int or a float (2 and 4 bytes, respectively for an Arduino other than the Due) be transmitted from the variable "value" on the slave to the master? Do you need to transmit strictly bytes, or could the slave define "value" to be something like an int, float, unsigned long, etc..  and get passed an int/float/unsigned long from whatever function a slave's handler function calls?

Perhaps more importantly, if I'm anywhere close to being on the right track here, how do you go about passing any information from the function called in the handler function to the handler? Is a local variable somehow nested?  i.e.  If the term used for a variable agree between the function called within the handler, and what the handler ends up sending, is there anything the function called needs to do to pass that information to the handler function, other than hold it's own copy of that variable?
7  Using Arduino / Installation & Troubleshooting / Re: AVRdude problem on: February 26, 2013, 01:28:42 am
And I feel like an Idiot. I was using the wrong sketch to upload. I need the Standalone AVR ISP programmer sketch from Adafruit, not the ArduinoISP sketch in the example folder. All seems to be well. Thanks everybody for trying to help me out.
8  Using Arduino / Installation & Troubleshooting / Re: AVRdude problem on: February 24, 2013, 06:15:06 pm
Coding Badly,

I uploaded the ArduinoISP sketch to a Mega2560, connected the appropriate pins (10-13, 5v,gnd) to the ICSP header on the Uno. Attempting to burn a bootloader with the board set to the Mega and Programmer with Arduino as ISP returns the same error. The yellow "L" LED stays lit on the uno until I reset it.
9  Using Arduino / Installation & Troubleshooting / Re: AVRdude problem on: February 24, 2013, 06:11:04 pm
Spatula, I'm already plugged into a powered usb hub.
10  Using Arduino / Installation & Troubleshooting / Re: AVRdude problem on: February 24, 2013, 05:16:32 pm
Uno on Mac OSX Lion.
11  Using Arduino / Installation & Troubleshooting / Re: AVRdude problem on: February 24, 2013, 02:56:23 am
Hmmm. Not really sure how to do that. Pressing reset on the board flashes the LED at L. If I try and upload any sketch, it hangs and the LED stays on. Not sure if that is helpful
12  Using Arduino / Installation & Troubleshooting / Re: AVRdude problem on: February 24, 2013, 01:39:54 am
Right board selection, and I'm pretty sure that is the right serial port.

I tried the loop-back test by connecting Rx and Tx with a jumper and setting the reset pin to ground. Nothing is echoed in terminal window.
13  Using Arduino / Installation & Troubleshooting / AVRdude problem [solved] on: February 24, 2013, 01:21:22 am
Here is the verbose output, cut to meet the 9500 character limit. Any ideas on a fix?

Code:

avrdude: Version 5.11, compiled on Sep  2 2011 at 18:52:52
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf"
         User configuration file is "/Users/aurelius/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/tty.usbmodemfd16311
         Using Programmer              : arduino
         Overriding Baud Rate          : 115200
avrdude: Send: 0 [30]   [20]
avrdude: Send: 0 [30]   [20]
avrdude: Send: 0 [30]   [20]
avrdude: ser_recv(): programmer is not responding
avrdude: stk500_recv(): programmer is not responding

avrdude done.  Thank you.
14  Using Arduino / Storage / Re: SD card file naming on: October 11, 2012, 07:13:22 pm
PaulS,

I would like one file, one reading and the date and time stamp to correlate DO to brix in a fermenting barrel of wine. The user defined number will be the 5 digit barrel number. We're looking to see with a few hits of oxygen from a stone at different intervals affects the rate of fermentation and temperature. I'm looking for an easy way to differentiate the different times we hit each barrel with O2. Since I can't use more than 8 characters for the file name, I'm thinking of adding a letter to the end of the number sequence to denote the time sequence. This however, runs into the problem that I would need to write out the letter to keep track of which is next in the sequence. If I'm doing that, I might as well write down the time and date as well on a paper list & rename the files to the format I originally suggested once on the computer. That is just more work, and I think there could be a more elegant solution that isn't causing me to spend a bunch of time cross referencing that paper list.
15  Using Arduino / Storage / Re: SD card file naming on: October 11, 2012, 07:07:07 am
ok, so I'm limited to 8. I suppose if the file has a date created stamp, it would have a time as well, and I could name the file simply the user defined number.
Pages: [1] 2 3 4