Address 0 is the broadcast address with I2C. But not all I2C slave devices support this.
That's how most I2C devices do it.
But I'm not shure if @shauntherailroadguy is asking about I2C at all. I think he is still testing RS485.
Address 0 is the broadcast address with I2C. But not all I2C slave devices support this.
That's how most I2C devices do it.
But I'm not shure if @shauntherailroadguy is asking about I2C at all. I think he is still testing RS485.
Unclear. The discussion started with RS485 but transitioned to I2C with code in post #36 for an I2C scenario.
Apologies, I am now testing I2C - looks to be far easier to implement for the pretty basic stuff I need
is there a way to change the title to prevent confusion?
I think, as the author of the thread, you can edit the title yourself.
Might also be worth adding to your initial post that the discussion has moved on to using I2C - possibly in bold - to catch other contributors eye.
will do, thanks! Sorry for the confusion too
Done, not as hard as I thought it would be!
That may be a big mistake.
I2C is much much more susceptible to noise then RS485 especially for wires longer than 10cm
I can't agree with that. I'm using I2C for my model railroads for years. My last railroad was about 4,5x5m and the I2C lines was about 3m max. I used a multiplexer to limit the length ( about 2m in one direction and 3m in the other). I never had problems with that.
Noise is not so much a problem than the capacitance of the lines. You have to pay attention to that. And of course you can reduce the clock speed. This is not so much a problem in this usage.
Of course you can have much longer lines with RS485. It is designed for line lenght of more than 1km. You seldom will find that on a model railroad .
If you only want IO pins to set high or low or to read inputs, a nano as slave is a little bit overkill. There are I2C IO devices that can do that out of the box - so no need to programme a slave.
in a few cases I want to be able to drive steppers or servos, so maybe they are needed for that.
Having said that, I'm interested in what devices you are talking about, can you give me more details?
Now a question regarding powering the slave nanos. As I see it I think there are three options, plug the USB connection into a powered USB hub or charger, supply 5v to the VIN pin or supply 5v to the 5v pin
What is the best option, bearing in mind for the 28BYJ-48 stepper drivers I already would have a 5v supply
Never; Vin requires 7V or higher.
Things like below (I2C devices) can be used for general purpose digital IO; note that this is local and only to give you pointers to search for
You can also search for 74HC595 (output) or 74HC165 (input) shift registers; finding modules might make your life easier. These are not I2C.
Hi all
Once more I request your assistance. Over the last few days I managed to make a little network over I2c with a master with switches and an LED driving three Nanos with LED's, and one with a switch. The master could command the LEDs to light based on which switch was pressed and I even had feedback where the switch connected to the slave would light the LED connected to the master depending on the position of the switch.
I was feeling quite good about myself but the next slave has so far has me stumped. I have broken it out to try with a dedicated master sketch, and I beg your assistance to understand why this one won't work when I effectively copied one of the working sketches (apparently - maybe there is a detail I missed) and just added another LED argument.
The idea is that when you flip a toggle switch connected to the master via pins 11 and 12, it will light or turn off two LED's connected to the slave pins 2 and 3. I want them as individual actions and not and or.
In theory, the master will transmit values 'tal' of either 0 or 2, and 'ual' of 1 or 3'. When I open the serial monitor on the master, that is indeed what is being transmitted
The slave is then supposed to use an 'if' argument to light LED1 and LED 2 depending on the received values, which I thought would be straightforward.
However when I open the serial monitor for the slave, the only received value I can see is -1 no matter what the output from the master. On the other sketches I could see the received values changing, but for some reason this sketch is acting as if the master is not transmitting
This is the master sketch
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR12 12
bool buttonState4, buttonState5;
const int buttonPin4 = 11;
const int buttonPin5 = 12;
const int ledPin1 = 6;
int tal = 0;
int ual = 0;
void setup() {
pinMode(buttonPin4, INPUT_PULLUP);
pinMode(buttonPin5, INPUT_PULLUP);
pinMode(ledPin1, OUTPUT);
// Initialize I2C communications as Master
Wire.begin();
}
void loop() {
buttonState4 = digitalRead(buttonPin4);
delay(10);
if (buttonState4 == LOW) {
tal = 1;
} //else {
if (buttonState4 == HIGH) {
tal = 0;
}
buttonState5 = digitalRead(buttonPin5);
delay(10);
if (buttonState5 == LOW) {
ual = 2;
} //
if (buttonState5 == HIGH) {
ual = 3;
}
Wire.beginTransmission(SLAVE_ADDR12);
Wire.write(tal);
Wire.write(ual);
Wire.endTransmission();
{
Wire.begin();
Serial.begin(9600);
Serial.println(F("-------------------------------------I am the Master"));
delay(1000);
Serial.print(F("tal : "));
Serial.println(tal);
Serial.print(F("ual : "));
Serial.println(ual);
}
}
here is the slave sketch
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 12
// Define LED Pin
int ledPin1 = 2;
int ledPin2 = 3;
// Variable for received data
int rd;
void setup() {
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
// Initialize I2C communications as Slave
Wire.begin(SLAVE_ADDR);
// Function to run when data received from master
Wire.onReceive(receiveEvent);
Serial.println("I2C Slave Demonstration");
Serial.begin(9600);
Serial.println("-------------------------------------I am Slave4");
//Wire.onRequest(requestEvent);
}
void receiveEvent() {
// read one character from the I2C
rd = Wire.read();
// Print value of incoming data
Serial.println(rd);
Wire.write(rd);
}
void loop() {
delay(10);
if (rd == 1) {
// turn LED on:
digitalWrite(ledPin1, HIGH);
}
if (rd = 2) {
/*} else {
// turn LED off:*/
digitalWrite(ledPin1, LOW);
}
if (rd == 0) {
// turn LED on:
digitalWrite(ledPin2, HIGH);
}
if (rd = 3) {}
digitalWrite(ledPin2, LOW);
}
void receiveEvent(int numBytes) {
Wire.begin();
Serial.begin(9600);
Serial.println(F("---> recieved events"));
Serial.print(numBytes);
Serial.println(F("bytes recieved"));
Serial.print(F("recieved value : "));
rd = Wire.read();
Wire.write(rd);
Serial.println(rd);
// Print value of incoming data
}
Am I misunderstanding the syntax, have I missed out a key line? It's probably a stupid error on my part but I just can't see it. If you can help resolve this I would be grateful
if (rd = 2) {
WHOOPS !
if (rd = 3)
and again
Thanks, and I wish I had your eyes, you were quick!
I have just realized that I cannot have two different values of the same int.
How do I get the slave sketch to recognize two different parameters to control two different master outputs?
EDIT
Just trying to use my head rather than leaning on you guys, would a conditional argument like
'if pin 11is high and pin 12 low then output 1',
'if pin 11is high and pin 12 high then output 2',
if pin 11is low and pin 12 low then output 3'.
if pin 11is low and pin 12 high then output 4'
Is that an option or not?
That is certainly an option but there are almost certainly better ways to to it. I am not overly familiar with I2C but I will see what I can find
In the meantime I suspect that someone more knowledgeable than will reply
Others may correct me here, but a couple of random thoughts:
I'm not into that while (Serial.available())
waiting for Strings String readString;
when all you really need is a char
. I feel like you're going twice around the world for a shortcut and I feel your frustration with the Serial comms stuff - that was me when first starting out. I was convinced it didn't work correctly and then one day I came across this tutorial by Legend of Arduino, @Robin2 :
You don't want a while loop. You also don't need Serial.flush();
.
I think you should be fine just passing chars to your accessory boards. If you don't plan on typing commands into a Serial monitor all the time once everything is done, there's no need to use commands like "on" or "off" when a simple char sent from the controller to the accessory boards will do. If you are pressing buttons that are read by your controller Arduino, you'll want to look at the IDE example StateChangeDetection so that the controller Arduino only sends out a char message to one of the accessory Arduinos if the button state has changed, so you're not spamming the Serial comms when that control button is just idle.
I managed to get the sketch to read the data, but I have to say that I am more confused that before
I replaced this
void receiveEvents(int numBytes) {
Wire.begin();
Serial.begin(9600);
Serial.println(F("---> recieved events"));
Serial.print(numBytes);
Serial.println(F("bytes recieved"));
Serial.print(F("recieved value : "));
rd = Wire.read();
Wire.write(rd);
Serial.println(rd);
// Print value of incoming data
with this copied from another sketch
void receiveEvent(int numBytes) {
Wire.begin();
Serial.begin(9600);
Serial.println(F("---> recieved events"));
Serial.print(numBytes);
Serial.println(F("bytes recieved"));
Serial.print(F("recieved value : "));
rd = Wire.read();
Wire.write(rd);
Serial.println(rd);
// Print value of incoming data
The only thing that I can see different is that the non-working sketch has 'void receiveEvents(int numBytes) {' instead of ' void receiveEvent(int numBytes) {', the difference being the extra 'S'
So I undid the copy and paste and restored the sketch to the non- functioning state, then deleted the offending 'S'. It still didn't work!
I then recopied and pasted the apparently now identical text from the working sketch, and it started working fine....
So with identical (apparently, I can't determine the difference) code in the sketch, one works and the other doesn't. Same hardware, and everything.
Is there some formatting of text or something that isn't visible but has an effect? If anyone can shed light on this, or point out something I am missing I'd love to understand
Certainly.
EDIT: @alto777 got me onto the ezButton library. If it's buttons that are sending chars from a central controller to accessory boards, this library is a great option and has been reliable for me.
It might look like (relevant sections copied from a project I'm working on)
#include <ezButton.h>
const byte returnButton = 2;
const byte changeDifficultyButton = 4;
const byte helpMenuButton = 5;
const byte reprogramButton = 7;
const byte retrieveButton = 8;
// make some buttons
ezButton aHelpMenuButton(helpMenuButton);
ezButton aDifficultyButton(changeDifficultyButton);
ezButton aReturnButton(returnButton);
ezButton aReprogramButton(reprogramButton);
ezButton aRetrieveButton(retrieveButton);
void setup() {
Serial.begin(115200);
aHelpMenuButton.setDebounceTime(25);
aDifficultyButton.setDebounceTime(25);
aReturnButton.setDebounceTime(25);
aReprogramButton.setDebounceTime(25);
aRetrieveButton.setDebounceTime(25);
gameControl = 0; // set initial game level
}
void loop() {
checkSwitches();
switch (gameControl) {
case 0:
terminal();
break;
case 1:
edensHacksMenu();
break;
case 2:
displayTerminalProgress();
password.reset();
currentLength = 0;
discardIncomingSerial(); // this needed to get clean password attempt
gameControl = 0;
break;
case 3:
disconnectFromPortal();
gameControl = 1;
break;
case 4:
hackerMenu();
break;
case 5:
robcoTunnel();
break;
case 7: // intermediate between hackerMenu() and robcoTunnel();
longFastScroll();
gameControl = 5;
break;
case 8: // use for edensHacksMenu() back to normal terminal
longFastScroll();
gameControl = 2;
break;
case 9: // use for clearing screen before disconnect robCoPortal
longFastScroll();
gameControl = 3;
break;
case 10:
journalMenu();
break;
case 20:
break;
case 99:
reprogramJournalPassword();
break;
}
}
void checkSwitches() {
aHelpMenuButton.loop();
aDifficultyButton.loop();
aReturnButton.loop();
aReprogramButton.loop();
aRetrieveButton.loop();
if (aHelpMenuButton.isReleased()) {
quickScroll();
Serial.println(F(" [ OR ] - RESETS PASSWORD"));
Serial.println(F(" ? - INQUIRY MODE"));
Serial.println(F(" + - SAVIOR REQUEST"));
delay(3000);
quickScroll();
displayTerminalProgress();
}
if (aDifficultyButton.isReleased()) {
gameDifficulty += 1;
switch (gameDifficulty) {
case 1:
password = Password("48273");
break;
case 2:
password = Password("BACKDOOR");
break;
default:
password = Password("SNAKE");
break;
}
if (gameDifficulty > 2) {
gameDifficulty = 0;
}
robcoChangePasswordProtocol();
}
if (aReturnButton.isReleased()) {
if (gameControl == 1) {
gameControl = 0;
} else if (gameControl == 0) {
gameControl = 1;
}
}
if (aReprogramButton.isReleased()) {
longFastScroll(); // form feed clears screen
lastGameControl = gameControl;
gameControl = 99;
Serial.println(F("User, select a new Pipboy Passcode..."));
}
if (aRetrieveButton.isReleased()) {
longFastScroll();
Serial.println("Pipboy Passcode:\t");
Serial.println(EEPROM.get(0, buffer));
delay(3000);
longFastScroll();
}
}
If you were sort of following along in this example, your central controller would maybe be reading buttons all the time, my checkSwitches();
function. In other words, everything you do involving the switches would be similar to the contents of that function and might be your entire void loop();
Point is, this button library is working well enough for my needs and does all the state change detection for you in the background.
You're really spamming the receiver here. In the IDE, look at File > Examples > 02. Digital > StateChangeDetection.
Just discovered that it does too!
I put this into the master
if (buttonState4 == LOW && buttonState5 == HIGH) {
tal = 0;
}
if (buttonState4 == HIGH && buttonState5 == LOW) {
tal = 1;
}
//{
if (buttonState4 == LOW && buttonState5 == LOW) {
tal = 2;
} //
//{
if (buttonState4 == HIGH && buttonState5 == HIGH) {
tal = 3;
}
and this in the slave
if (rd == 1) {
// turn LED on:
digitalWrite(ledPin1, HIGH);
digitalWrite(ledPin2, HIGH);
}
if (rd == 2) {
/*} else {
// turn LED off:*/
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, HIGH);
}
if (rd == 0) {
// turn LED on:
digitalWrite(ledPin1, HIGH);
digitalWrite(ledPin2, LOW);
}
if (rd == 3) {
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
and now that the sketch is actually reading an input it worked straight away.
It is a bit clunky, and as long as the variables aren't too many it should be manageable. However there must be a better way, a way of sending discrete data values to control individual LED's and things independently