Communicate between microcontrollers: Automatic address and request-less send?

Hi everybody,

I have a question about the wire I2C library.

I want to communicate with an unknown number of buttons. Every button is connected to a microcontroller (I think I can use a ATTiny for that part). Every button has his own housing with LEDS. Every housing has one cable with 4 wires and a male connector. Every housing also has a female connector to daisy chain button housings to each other. There’s one master controller box where the first button connector goes into. So, every button has Ground, 5V and two data lines.

Now the master controller box wants to know if there’s a button pressed. Does the master controller box needs to poll every button-controller address to ask if the button is pressed? Or is there a way the button-controller can send to the master his button is pressed without being asked by the master? (very fast response after button press is important)

Follow up question: I don’t know the number of button’s the user has daisy chained up. So how does a new hooked up button gets automatically his own unique address and let the master controller know it’s available (without setting dip switches)? One thing I can think of is to give every button-controller address 127. Controller polls if address 127 is available, and if so, the controller gives the button-controller a new address. But this won't work if multiple buttons are connected at the same time, or if the master controll box is enabled after the connection has been made. :( Maybe disconnect the pass-trough dataline with a transistor and connect it after the button-controller has received a new adress?

Another option I thought of is to use the serial communication to communicate with each other. The RX is connected to the TX of the other controller and so on. The master RX is connected to the last TX button controller in the chain. And every button-controller needs to re-transmit the received serial data. If the button-controller has to say something itself, it injects his own serial data in the stream. One disadvantage is that I need to “terminate” or short the data wire’s on the last button connector otherwise the loop is open.

Any Ideas?

Another option I thought of is to use the serial communication to communicate with each other. The RX is connected to the TX of the other controller and so on.

That would probably be my approach, I assume you are happy to use serial rather than I2C.

The only down side is determining the order in which buttons are pressed, for example if a button on node 2 is pressed just before one on node 22 the master will still see the press from 22 first.

Is this a problem with your application? If it’s a game where the first button pressed wins then maybe.

As for the addresses, you can have a simple self-discovery algorithm that sends 0 to the first node, it records that as it’s address, increments the number and passes it along. When the number returns all nodes have a unique address and you also know how many there are.

Also what is the distance between these boxes, I2C is not normally good for long runs.


Rob

So, I can think of a few approaches here.

1. When a device has it's button pressed, it sends out a 0 over the uart. When a device recieves a byte over uart, it increments it by one and passes it on. Device 0 will send directly to the reciever, device 3 will go through 4 hops and the final number will be 3.

Button press latency will be a little over the combined time it takes for all the hops in the chain. if a byte takes 0.1ms to send, with 100 devices it will probably take about 15 milliseconds. There will be a little bit of bias due to the fact device 0 takes less time to arrive than device 1. The post sounds a lot like you want to make a quiz buzzer system and for that you might want more accuracy or to randomly break ties instead of giving player 0 a 15 millisecond advantage over player 100, but it's simple and easy.

2. Don't daisy chain. Use CAN or RS485 and a bus protocol that allows devices to choose arbitrary times to send and handles collisions. Give each device a unique 128 bit UUID. When a device is pressed, it says "Hey, device #45632896598645 was pressed" Now, if two devices collide, we can't really tell how long it will take to sort out and it could be 25ms or more.

So we have a central node spewing out "Hey, it's 89835 microseconds past 05:00:2 PM right now" that devices use to synchronize their clocks. When a device is pressed, it includes the exact time at which it was pressed in its message. The accuracy is as good as the clock synchronization, and is totally independant of network delays, and you have a CAN or RS485 wire allowing you to connect whatever other devices you want to monitor or control(Scoreboards?) to the bus without compromising fairness. You also get a more robust physical layer than just connecting i2c pins.

3. Don't use MCUs at all. Give yourself a third data line. The buttons are actually shift registers. The master clocks data out of a big chain of shift registers, reading the state of a set of buttons. Better add a bit of logic to deal with switch bounces.

You guy’s guessed it, it’s for a game. And the person who presses the button the first is important. So the idea to use a synchronized clock is great.

Also what is the distance between these boxes, I2C is not normally good for long runs.

Ohw… didn’t know that. About 2 meter per button. But if there are 6 buttons the total length adds up to 12. So I guess I2C is out of the question then. So that leaves serial, CAN or RS485. The goal is to keep the electronics as cheap as possible. Serial is already available in the microcontroller, but daisy-chaning makes it a bit unreliable. Especially if I want to use a ATTiny without a crystal the chance an error occurs along the path is high. So that leaves CAN or RS485. I’ve looked into RS485, and a MAX485 chip is pretty cheap. Haven’t looked if there are Arduino libraries available for it, but this is probably the easiest and reliable way to suit my needs.

Don't use MCUs at all.

I also want to control the (RGB) leds inside every individual button (By the master), and maybe add a score display in every button housing. So I really need an microcontroller to communicate with the master.

Is there something wrong with using digital pins for the button presses? Use one digital pin from each remote microcontroller to the core Arduino to determine "first press" and use the serial for transferring stuff like scores, etc.

So that leaves serial, CAN or RS485...but daisy-chaning makes it a bit unreliable. Especially if I want to use a ATTiny without a crystal the chance an error occurs along the path is high...So that leaves CAN or RS485.

CAN and RS485 are serial, they are just transceivers for the data to/from the UART (unless you use a CAN controller), so if you aren't happy with using "serial" then using RS485 won't make any difference from a timing point of view, it will help with long cables though.

Haven’t looked if there are Arduino libraries available for it,

As I say, RS485 is just a hardware buffer, it has nothing to do with the the protocol, so the standard serial function is all you need. CAN is (or can be) the same.

How about all nodes control an open-collector "pressed" signal, when a button is pressed you test this signal, if it's not asserted you pull it low and that locks out all the other nodes. You then transmit the node address etc. There is still a tiny race condition but in this application that can be ignored I think.

This would need an extra wire though.


Rob

SurferTim:
Is there something wrong with using digital pins for the button presses? Use one digital pin from each remote microcontroller to the core Arduino to determine “first press” and use the serial for transferring stuff like scores, etc.

That makes a lot of wires and a big connector. I’m trying to make the wire count the bare minimum. I also don’t want to limit the amount of button-units.

Graynomad:

So that leaves serial, CAN or RS485…but daisy-chaning makes it a bit unreliable. Especially if I want to use a ATTiny without a crystal the chance an error occurs along the path is high…So that leaves CAN or RS485.

CAN and RS485 are serial, they are just transceivers for the data to/from the UART (unless you use a CAN controller), so if you aren’t happy with using “serial” then using RS485 won’t make any difference from a timing point of view, it will help with long cables though.

I understand they are serial, but CAN and RS485 is a single bus as I understand. This is the way I wanted to try the serial communication:

example of 3 buttons:
Attach Button 3 TX to the button 2 RX
Attach Button 2 TX to the button 1 RX
Attach Button 1 TX to the Master controller RX
Attach Master controller TX to Button 3 RX.
So it’s a loop.

Every button controller needs to retransmit what its receiving.
If Button 3 wants to send information button 2 receives it, and transfers it through. And so on until it is received by the master.
But if one of the nodes isn’t reliable the whole chain breaks. And since I want to use the ATTiny’s without crystals for the buttons, I think the asynchronous serial isn’t that reliable. But I can be totally wrong of course, I don’t have much experience with this.
I thought I2C was more reliable because of the single bus and its synchronized by a clock pulse. But since you’ve mentioned it can’t broadcast long cable lengths I figured this is also the wrong way to go.
So that leaves CAN or RS485. I believe these also aren’t synchronized by a clock-pulse, but if one of the button controllers fail, the whole chain stay’s intact.

Graynomad:
How about all nodes control an open-collector “pressed” signal, when a button is pressed you test this signal, if it’s not asserted you pull it low and that locks out all the other nodes. You then transmit the node address etc. There is still a tiny race condition but in this application that can be ignored I think.

This would need an extra wire though.

Well… I’d like to have a more universal system. So if I want to create a box with 3 buttons (A B C) in the future I could easy implement that into the system. Or if I want to generate a list of buttons that are pressed in order.