Hello,
I am working on a project where I want to control four relays for switching on and off devices. I am using arduino uno R3 board.
Input switch will be connected to 4 pins on the arduino and there will be four relays to control devices.
Now, the switches will be a momentary switches which makes the STATE of the PIN HIGH for few ms.
If some one quickly presses the two or three switches at the same time, then logic inside loop() may not detect the switch press. This is because ATMega328P which comes with Arduino Uno R3 does not have capability to do a parallel processing.
Is there a better way to achieve this using some alternative arduino board (with different chip)?
One thing which I was trying to see was interrupt based solution, but ATMega328P has only three interrupts (if i am correct) so may not be correct design for using 4 switches and relays.
Unless your code is based on use of delays or has other blocking problems there is nothing that a human can do fast enough for Arduino to not notice 100's of times.
In fact, that is often a problems for some code that people "fix" by adding delays!
Pin HIGH for a few ms?? Not with a finger on it. Even fast, over 100ms.
I have a multiple button examples (pin-per and multiplexed) that includes debounce and checks a few buttons per ms while flashing a status led and providing user serial I/O.
Arduinos are very capable of tasking without an OS getting in the way. Here's tutorials:
How to do multiple things at once ... like cook bacon and eggs
How to process incoming serial data without blocking
You will find more helpful pages on that man's blogs than some books.
I think he might sell books too, a nice way to support him would be to buy some.
And no no no, I am not Nick Gammon nor related to him and live clear across the world from him!
Lastly you might want to rewire your switches. AVR's have built-in pullup resistors for all the I/O pins. You set them up with pinMode( pin, INPUT_PULLUP ) and they read HIGH unless grounded, so the logic is reverse to what you use. The pullup resistors are 20k to 50k, current is pin safe and doesn't add much to the total draw at all. And it saves you a resistor per pin.
You don't need interrupts to keep up with humans and all 20 UNO pins can interrupt on state change.
Hang around and read threads in the different sections and you can learn a LOT. There's even a long running thread in Bar Sport on what people have bought lately that often names sources, a great resource for where to shop and where not.
If some one quickly presses the two or three switches at the same time, then logic inside loop() may not detect the switch press. This is because ATMega328P which comes with Arduino Uno R3 does not have capability to do a parallel processing.
If you can get your finger on and off of a button, quicker than an arduino can cycle through sampling a THOUSAND buttons. You're a superhuman. Even a humming bird isn't that fast!
Start with Blink Without Delay and work into Finite State Machines.
These are not that hard once you get going.
Instead of doing a whole checklist every time through loop(), plan on doing what is ready to be done with priority-first items up top. If anything takes more than 100 usecs, return when that 1 thing is finished instead of going down a list. Always have the priority checks hitting every msec if possible depending on how many you have. You want to keep loop() turning.
So when I have 16 buttons only 1 gets checked at a time and that is by a debounce routine that turns actual pin state changes to an abstracted button state. Each button may get read 20+ times before it is considered stabilized by the one routine that sets a variable telling the button state.
Other routine(s) not incorporated in the physical button code logic run on button state/change in state. There is no "where in the if-else does this part go?" because the variable(s) set are the link. The logic is separated and there are fewer indents. You can change how one part works without looking after the logic of the other, change from buttons to serial input, and it's all cleaner and easier as long as you keep the state variables straight.
And doing that, you can have many tasks related or not still working together on one simple MCU.
Code tags have a different symbol, second from the right on the top row. If you leave the mouse cursor over it a second of so a tool hint says code.
Your 9600 baud serial print statements do slow down the counter.
See what happens when you change that to 115200 baud, 12x as fast. Serial print blocks.
Here is a button watcher sketch with debounce timer and reporting in micros().
Note that checks shows checks since last stable press or release.
Micros in state change is reset whenever the state is stable for debounce micros which happens even when it is stable in the previous state so bounce values will never exceed debounce time.
Tested, enjoy and beginners take note of how fast these boards are.
// this is button_watcher, a test for button bounce --- free and open code Oct 25, 2014 by GFS
// this can be used to check buttons for needed debounce time.
// if you get multiple UP and DOWN messages for one press or release, increase debounce.
byte ledPin = 13;
byte buttonPin = 7; // my button is a jumper wire grounded on the metal USB port box.
byte pinStates; // always the current state is in bit 0 and the previous is in bit 1
// value --- meaning with pin mode INPUT_PULLUP.
// 0 --- no change, pressed now and pressed last check
// 1 --- changed, released now, pressed last check
// 2 --- changes, pressed now, released last check
// 3 --- no change, released now and released last check
byte buttonState; // this only changes when the pin states are stable for some time.
byte buttonPrev; // this only changes when the pin states are stable for some time.
unsigned long checkCounter; // how many checks since last stable change
void setup( void )
{
Serial.begin( 115200 );
Serial.println( "\n Button Bounce Check" );
pinMode( ledPin, OUTPUT ); // default os LOW
pinMode( buttonPin, INPUT_PULLUP ); // default is pullup HIGH
pinStates = 1; // sets initial pin state as not pressed
// buttonState logic will be 0=false for stable not pressed, 1=true for stable pressed
}
unsigned long btNow, btStart, btDebounce = 2000UL; // bt = button time. 2ms debounce
inline void buttonHandler( void ) // just so the cleanliness police don't freak out
{
pinStates &= 1; // mask off the old previous state bit, only bit 0 data is left
pinStates <<= 1; // move current pin state bit left 1 into previous pin state bit
pinStates += digitalRead( buttonPin ); // read the current pin state into bit 0
btNow = micros(); // time at loop start and read pin state to within 4 usecs
switch ( pinStates ) // IDE autoformat indents this line. Why?
{
case 0 : // 0 --- no change, pressed now and pressed last check
if ( btNow - btStart >= btDebounce )
{
buttonState = 1;
btStart = btNow;
}
break;
case 1 : // 1 --- changed, released now, pressed last check
Serial.print( '_' ); // show the bounce
Serial.println( btNow - btStart ); // show the micros since last stable or change
btStart = btNow;
break;
case 2 : // 2 --- changes, pressed now, released last check
Serial.print( '*' ); // show the bounce
Serial.println( btNow - btStart ); // show the micros since last stable or change
btStart = btNow;
break;
case 3 : // 3 --- no change, released now and released last check
if ( btNow - btStart >= btDebounce )
{
buttonState = 0;
btStart = btNow;
}
break;
}
}
void loop( void )
{
buttonHandler( );
checkCounter++;
if ( buttonState != buttonPrev ) // button stable state change event
{
buttonPrev = buttonState;
digitalWrite( ledPin, buttonState );
Serial.print( F( "\nButton is " ));
if ( buttonState ) // if not zero, it is true
{
Serial.print( F( " DOWN " ));
}
else
{
Serial.print( F( " UP " ));
}
Serial.print( F( "after " ));
Serial.print( checkCounter );
Serial.println( F( " checks.\n" ));
checkCounter = 0UL;
}
}