Newbie: Getting I2C to read slave's Analog input and more

Hello all,

Newbie (to the forum) here. Butterfingers is the moniker, probably reflecting my typing skills. :slight_smile:

I have an Uno R3 with the ATmega328P chip and am having (sometimes frustrating) fun learning about micro-controllers.

I developed a project where (simplified) the micro-controller polls the analog inputs for change from the previous polling. If a change is detected a portion of related code is executed. All 6 analog inputs are used as are all 14 digital outputs.

I bread-boarded the micro-controller for portability and, as knowledge grew, eventually found more inputs (and outputs) were required. Multiplexing would not work for the analog inputs. A second ATmega328 was added and, after wiring for I2C (having moved some analog inputs to the second micro-controller). I hacked and installed the Master / Slave examples found in the learning section. I called the Master 100 and the Slave 101. Everything worked as expected.

The problem is, I need to run my code between the micro-controllers. Everything seemed to need Hex numbers or binary registries. Wow! I downloaded the 660 page datasheet for the ATmega328 and spent some considerable time looking for, among other things, A0 analog input.

I found the Hex address for A0 == 0x08(0x28) == (PortC bit 0). I hacked the code and established a form of communication that required the Master to read the slave (theoretically) and display the results on the Serial Monitor. Unfortunately, the results were 14 (followed with no spaces) by 255 255 255 (eight times) no matter what setting of the pot. That didn't make a lot of sense to me. Obviously, I'm doing something wrong. So, I was hoping for a different approach. Perhaps one that didn't involve directly accessing the registries?

I have so many questions and the butterfingers are blathering. My apologies. What I would like to do is:

1/ Master U100: polls it's own analog inputs (A0 - A3), if it detects change processes code. It then needs to poll the analog inputs on U101. When it comes to polling the analog inputs on the Slave U101, I would like it to ask the slave, "What is the value of A0?" Can I do that the same way in the learning examples for reading an analog input?

i.e.

Master: U100

#include <wire.h>

void setup() {

wire.begin(100); // establishes connection to I2C with identity 100 which may be used
//in future if Master becomes the Slave.
}

void loop() {

Wire.requestFrom(101) // asks Slave 101

while (Wire.available()) { // slave may send less than requested

firstPotval = Wire.read(A0); // receive the value read in U101-A0

}
}

2/ The Slave would then read U101-A0 and return the value.

Slave U101

#include <Wire.h>

void setup() {

Wire.begin(101); // join i2c bus with address 101

Wire.onRequest(requestEvent); // register event // I'm not sure I understand this part.
// can "requestEvent" be renamed to something like "readfirstPot"?
}

void loop() {
delay(100);

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()

void requestEvent() { // Can this be written // void readfirstPot() { ?

int firstPotval = analogRead(A0)/4;

Wire.write(firstPotval); // respond with A0 reading
// as expected by master

}
}

instead of writing a stream of bytes? I tried a code like this and got errors.

3/ The master would then determine if there is a change, if so, process the related code.
// With the exception of the new I2C part, This already works.

4/ However, now the Master needs to command the Slave to set the digital output on slave U101 pin 4 to HIGH.

e.g.

//Master (appropriately placed in the existing processing code)

//void setup() { // already established previously

Wire.begin(100); // join i2c bus (address for master)

//}

// void loop() { // already established previously

// previously written code that detected change in U101-A0 now executes the following

Wire.beginTransmission(101); // transmit to Slave 101

Wire.write(digitalWriteA(4, HIGH)); //writes digital pin 4 HIGH - this part will fail but

// I don't know how to write in the correct format.

// It's called digitalWriteA because there will be others

// and each needs to be distinctly labelled.

Wire.endTransmission(); // stop transmitting

delay(TimerA); // previously defined timer setting e.g. 300ms
//}

Slave U101:

// #include <Wire.h> already established earlier

//void setup() { // already established earlier

Wire.begin(101); // join i2c bus with address #101
Wire.onReceive(receiveEvent); // register event

}

void loop() {
delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(digitalWriteA) {

digitalWrite(4, HIGH); // Turns on the LED on pin 4

}

I know the above code likely will not work. The problem is there is not many examples to draw from.

Can anyone help me re-write the above so that I can use the basic principles in all the other stuff I need to write (including a, soon to be added, digital display on U101, and various analog inputs / digital outputs)?

Thank you for reading this tome.

Best regards,

Butterfingers

A second Arduino is not an extension to the first Arduino. They are two seperate Arduino boards. They can communication with each other (via Serial, SPI, I2C), but you should define how they communicate.

Please read number 7 about code tags on this page : http://forum.arduino.cc/index.php/topic,148850.0.html.

It is easier to use an Arduino Mega 2560 (more pins, 16 analog inputs).
Or use an Arduino Leonardo, that is the same size as the Arduino Uno but has 12 analog inputs.

Could you tell what is connected to all the pins ? There might be an easier way than to communicate with another Arduino board.

When you want to make a Arduino that communicates via I2C, then you have to think what data is transferred. I use a struct, but perhaps an array of data is also possible.
I see my Arduino I2C Slave as a "module". The Master checks which modules are connected and can work without them, and I can attach my "module" to other Arduino projects as well.

You could for example transfer an integer (two bytes). The Slave could fill it with data from an analog input and the Master can read the integer.

Hello Koepel,

I did mention that I'm a newbie to the forum. I went to the appropriate section of the forum and read the following:

https://forum.arduino.cc/index.php?PHPSESSID=sfkv91jna8sfokbpjm9c48r9d4&topic=149022.0 "How to use

this forum." I saw two items, i.e. "login" and "use the appropriate section" but failed to notice that it was linked. I didn't see a number 7 or even a number 3 etc.. My apologies!

Thank you for answering my post. However, as I mentioned, the two ATmega328s have been removed from the Arduino Uno board and are installed in a more portable format. Technically they are installed on a PC board. For this project I'll likely not be using an Ardiuno Mega 2560.

I thought I had established how the two ATmega328 chips communicate: via I2C. No?

As far as what's connected to the pins: all digital outputs are connected to opto-isolators via a 100 Ohm resistor. These are effectively the same as an LED. The inputs vary but essentially are different forms (values) of potentiometers each in a voltage divider circuit. Picture a TV remote being controlled by potentiometers where the analog meets the digital world. It's not exactly that but in effect it's much the same. Does that help?

I may be barking up the wrong tree. I really have no desire to communicate two bytes. Although I understand that you are specifically addressing the analogRead (A0) information request. Really that would only solve a tiny portion of the problem.

Ideally, I would like to have my ATmega328s communicate with each other - each case scenario pointing to a part of the others' loop and executing only the relative command - as if a 'goto' command were issued.

Is there a better protocol that would allow such a procedure? e.g. instead of I2C should I use Serial; configure the wiring using RX and TX (digital pins 0 and 1)?

Best regards,

Butterfingers

As Koepel said, each Arduino is an entity onto itself. However, they can communicate nicely via I2C as it's essentially an addressable party line. A slave cannot initiate a transaction but there's a way around that. If speed is a problem, the buss can be easily increased to 800Kbps.

The master periodically sends a one byte message to each slave via Wire.beginTransmission, message, Wire.endTransmission asking if it has something to send. The answer comes back via requestFrom/onRequest. The received message, always a fixed length, tells the master whether to request something or move on. Another requestFrom gets the data, if appropriate. The philosophy is "Do not speak unless spoken to". Keep in mind that the data buffer limit is 32 bytes. However, if the slave answers with 0 then there is nothing available to send back. Any value higher is the number of packets to be returned. The first packet can contain the type of data to follow and the remainder can be the data.

There are many ways of doing this but the above is just one. I use something like that in getting 1024 bytes of sonar data from each of four Nanos and store them in a Mega for subsequent transmission to shore via NRF24.

What about an output shift latch for the opto-couplers ?
There is a 595 that can drive leds. I forgot the exact type. That would solve your problem.

If you really want to do I2C, you have to know what kind of data you want to transfer. If two bytes is no good, how many bytes is ? perhaps 8 bytes ? that is possible.
It is not possible for one Arduino to peek into the other Arduino. They both run their own sketch.

Hello Arctic Eddie and Koepel,

Thank you for your answers. Your answers have shown me that I'm going about this the wrong way. Instead of trying to alter the other chips' sketch, I'll have the master do all the Input change > Process > output stuff. If one chip cannot 'peek' at the others' sketch, I'll have to live with that.

In fact as long as I can get the Master to read the Analog inputs and control the outputs of the slave, I'll be happy. The slave can sit and generate the display information**.

Changing to an Atmega256 would be almost impossible since the existing is on a printed circuit board - and there's a 'lot' of existing. There is no additional room for a shift latch or multiplexer. The PC board is relatively small and literally inside a black box. In order to get the number of analog inputs I have to work with two ATmega328 chips. If not, I'll have to scrap the existing and learn how to make a stand alone ATmega256 work on a PC board - a lot more work than I'm wanting to do.

My new questions then:

1/ Can the Master read the Slave's analog inputs?

2/ Can the Master control the Slave's digital outputs?

3/ Can the Slave read the Master's analog inputs?**

4/ I like the idea of the Master using the one byte message asking the Slave if it has anything to say. Can the slave be set to say 'yes' only if there has been a change in any analog input?

5/ What data does the EEPROM 0x1F contain if it's not the sketch? Is there anything in there worth looking at?

Let me tell you what feeling I get: You want to put a nail in the wall but can't find the hammer. So you build a rocket to the moon and try to hit the nail with the moon.

A 595 shift register that can drive the opto-couplers would work.
Or a I2C port expander: MCP23017 - i2c 16 input/output port expander : ID 732 : $6.95 : Adafruit Industries, Unique & fun DIY electronics and kits
That one can drive 25mA per pin (total max 125 or 150mA).

Hahaha ! Koepel, I wish it were that simple. I'm including the inertia and slingshot effect of rounding the planet Jupiter first, then the Sun in order to get to the back of the moon, hitting it hard enough to move towards my nail at sufficient velocity. You see, impact has to be a new moon for the right angle.

Back to planet earth.

While the port expander will add digital pins it does not add analog inputs. At least I could not detect that it does.

My circuitry needs at least 6 analog pins. The port expander wants two of them for I2C.

Any other suggestions or do I have to scrap my board and start all over again with a ATmega2560?

I forgot that the 2 out of 6 analog inputs are taken for I2C.

There are of course external analog input chips, but it is easier to use the ATmega328P for that.

If you need 14 digital outputs, then two 595 in cascade can be used for 16 digital outputs.

The 595 that can drive leds : TPIC6B595 High Power Shift Register [TPIC6B595] : ID 457 : $1.95 : Adafruit Industries, Unique & fun DIY electronics and kits

There are also I/O chips with SPI interface, for example the MCP23S08.

And you could use an analog input mux : Gammon Forum : Electronics : Microprocessors : 74HC4051 multiplexer / demultiplexer
It costs 3 digital pins. But the 6 analog pins can be digital pins as well. So you need one analog input, 3 digital, and you are able to still use I2C at A4 and A5, or keep D0 and D1 for the serial monitor.

There are more options.

The analog mux 74HC4051 is just one chip (simpler), but two output shift register chips TPIC6B595 will release many more digital pins (I prefer that).

Whatever you do, never add a capacitor to a latch pin, as is shown in this circuit : https://www.arduino.cc/en/Tutorial/ShiftOut

My new questions then:

1/ Can the Master read the Slave's analog inputs?

2/ Can the Master control the Slave's digital outputs?

3/ Can the Slave read the Master's analog inputs?**

4/ I like the idea of the Master using the one byte message asking the Slave if it has anything to say. Can the slave be set to say 'yes' only if there has been a change in any analog input?

5/ What data does the EEPROM 0x1F contain if it's not the sketch? Is there anything in there worth looking at?

  1. Yes. The master would send a message via "onReceive" that the next "onRequest" wants the analogue data. The data would come back via "onRequest" with enough delay so that the slave could gather the data.

  2. Yes. The master would send a slightly longer message via "onReceive" with the instruction of what to do and the digital pin data to be used by the slave.

  3. Yes. The master would ask the slave if it had anything to say via "onReceive". The slave would say yes with details via "onRequest". The master would then send the data via another "onReceive".

  4. No and Yes. The slave can be asked if there are any changes via "onReceive" but it must answer back with yes or no via "onRequest".

  5. Some Arduinos have a small amount of EEPROM in addition to the program storage area. If so, you can use the EPROMAnything.h library file I included in the Quadcopter post in this forum category. I'll attach it again if you want it or can't find it.

Thank you again for your replies.

"To the moon!" Too bad I never studied rocket science, or as Bugs Bunny might say, "I knew I should have made that left turn at Alba-coi-kee." Hehehe

Based on the answers to my questions, it looks like I may be able to make the two ATmega328P chips work for me.

I'll have to do more studying on exactly what code to write in the sketch.

Can anyone point me to more examples of Master Slave I2C sketches that are similar to what I'm asking?

P.S. I am being somewhat enigmatic in my project. Basically, I'm building a portable Model Diesel Control Stand Throttle that, using levers and switches, emulates the pressing of button combinations on a radio Digital Command Control device. I belong to a model train club with a huge walk around layout. I can walk with my model train and control it with a device that looks and 'feels' much like the real thing. Hence the analog potentiometers controlling the T.V. remote analogy. The coming display, which I also know nothing about, will have all the 'air brake meters', 'traction motor current meter, speedometer, etc.. There will be a lot of math involved because of the physical and dynamic properties of real trains (inertia, mass, etc.) based on length of train, acceleration, deceleration, etc..

I love to learn so this has been a fun project, albeit a somewhat frustrating project.

Thank you again for your help and I'll let you know if I need more help and/or how the project is proceeding.

Cheers,
Butterfingers (after spending all this time building it, I hope I don't drop it)

I suggest reading Nick Gammon's page on I2C and communicating between uCs.

Thank you Crossroads! After my last post I started searching and found the same. It is an excellent resource. Great suggestion!

Cheers,
Butterfingers