i2c arduino slave(ry)

I was going to try to continue a thread from the old system, but it looks like i must start a new one.

I have been playing with i2c multiplexers with some success, and want to use a slave arduino as an intelligent multiplexer/ io system.

Typically with mcp 23008 you send a "command byte" to either read or write a specific register, and then if writing, send a byte (or bytes) to write; or if reading, request a byte (or bytes) to get your answer.

I want to have some basic commands to ask my slave to read values (either the result of it's calculations or input readings).

I also want to be able to pass values to the slave to tell it what to do (maybe write to outputs, or run a predetermined subroutine)

I understand that in the setup i must put: Wire.onReceive(receiveEvent); which interrupts and runs receiveEvent when somebody on the i2c bus is trying to send the slave something.

(As an aside, i noticed in most examples, void receiveEvent(int howMany) without any further reference to howMany . Is that just sloppy that they left provision for howMany, but didn't use it, or is it required?)

What i did was to have receiveEvent read the first value as a Register, and read the rest into an array data[] which keeps collecting until the transmitter stops transmitting.

The writing routines seem simple in that, i can use switch /case based on the Register sent and decide where to write the data (i may need to work out global variables for that...)

void receiveEvent(int howMany) { int data[]; byte beer; byte i=0; byte Register = Wire.receive(); while( Wire.available()) // loop through all incoming data { data*= Wire.receive();* * i++;* * }* * Wire.endTransmission();* * switch(Register()){* * case 0x00: // write a/d 0* * digitalWrite(A0, data[0]);* * break;* * case 0x01: // write a/d 1* * digitalWrite(A1, data[0]);* * break;* [/quote] I am concerned about the reading routines. If i had a case statement for the reading routine that recognizes the master is looking for something. i need to find the easiest way to send it. if the master were to follow it's write with a read request: Wire.requestFrom(address, bytes); then the slave would jump into Wire.onRequest(requestEvent); subroutine . can i 1. not have a Wire.onRequest(requestEvent); so that the next statement in my case executes and sends the data back. 2. set a flag that tells the requestEvent which register was requested, and what data to send. 3. send the data automatically, and set my master up with a Wire.onRequest(requestEvent); to jump out and receive the data. thanks for the help doug

Ok, me again.

Here is my hardware setup:

On the left i have an arduino controller i made with LCD, pushbutons, i2c bus, i2c clock and i2c eeprom. i want to use this as my master.

On the right is my slaveduino, taking it’s power from i2c bus with a couple of mpx4250 pressure sensors on analog pins and some darlington drivers on digital outputs with protection diodes to i can operate solenoids without blowing everything up.

if it all works out, maybe i could share the eagle files to make the pc boards…

doug

(if i consider my time worth anything it would have been cheaper to buy arduinos, but i am stubborn)

slaveduino.jpg

(As an aside, i noticed in most examples, void receiveEvent(int howMany) without any further reference to howMany . Is that just sloppy that they left provision for howMany, but didn't use it, or is it required?)

That variable is what Wire.available() would give you the first time - that is, how big the receive buffer is.

What i did was to have receiveEvent read the first value as a Register, and read the rest into an array data[] which keeps collecting until the transmitter stops transmitting.

You are not doing that:

  byte Register = Wire.receive();
  while( Wire.available()) // loop through all incoming data
  {
    data= Wire.receive();
    i++;
  }

That just overwrites data, in fact I'm surprised it compiled. Maybe:

  byte Register = Wire.receive();
  while( Wire.available()) // loop through all incoming data
  {
    data [i++] = Wire.receive();
  }

Also you need to give data a size. Since the maximum buffer size for I2C is 32, this would be better:

int data[32];

This won't work:

  switch(Register()){

Register isn't a function, so you can't call it. This code didn't compile, right?

You really need two events, receive and request. I've got an example of reading a sensor right here:

http://www.gammon.com.au/forum/?id=10896

The master sends the data of what it wants - that goes into the receive event (and you just store it for now). Don't try to do too much in the interrupt service routine.

Then the master requests a reply (ie. "OK I asked you for stuff, what is the response?"). Now you end up in the request event. Now you send the results back. So in your case you would have "buf" somewhere in global code (not in the function where you had it) along with a counter of how many bytes were wanted. Then in the request event, you look at that counter, take that many readings and send them back.

With the caveat that you have to assemble a single Wire.send in your request event (not one per reading). So you need to assemble your results into another buffer and do a single send to send it back.

thanks, you're right, i hadn't tried to compile it yet. i tend to have to go over things to sort out the syntax. I am not a programmer, and Arduino is my first experience with c++. I usually manage to get things working, and when i do i invariably learn something. When i am away from it for a while, i get rusty.

i will try out your suggestions and get back.

doug