I have 61 digital inputs that are all switches. I have the understanding the MEGA's analog pins can also be used for digital inputs so each switch should conveniently have it's own digital input pin. Never will more than 10 be used at once but some buttons need to be single clicked, double clicked or held with other switches simultaneously to print on the screen. I have no outputs, just printing something to a screen. I'm struggling bigtime here...tried if, for, while, switch and all sorts of millis(), pulseIn, situations and feel like I'm going in circles. Could anyone recommend a good guideline or starting place for something this this?
Start off simply with say three switches and build up what you want to do.
If you get stuck post the code and schematic, say what you want it to do and what it does.
Ok, here is a starter code for pushing buttons simultaneously and the problem is when two buttons are pushed it displays the result from the individual buttons also.
/*
Got help with TVout function here: Google Code Archive - Long-term storage for Google Code Project Hosting.
All input pins have external 10K pull-down resistors to keep a LOW signal and
minimize noise from neighboring inputs.
*/
#include <TVout.h>
#include <fontALL.h>
TVout TV;
#define pin2 2 //Momentary switches 1 through 61
#define pin3 3
#define pin4 4
boolean swtch1; //Each Momentary switch numbered
boolean swtch2;
boolean swtch3;
void setup() {
Serial.begin(9600); //initialize serial communications:
TV.begin(NTSC,120,96); //display configuration
TV.select_font(font6x8);
TV.println("Screen Check\n");
TV.delay(1500);
pinMode(pin2, INPUT); //Momentary switch inputs
pinMode(pin3, INPUT);
pinMode(pin4, INPUT);
}
void loop() {
swtch1 = digitalRead(pin2); //Read the value of the switch for each loop
swtch2 = digitalRead(pin3);
swtch3 = digitalRead(pin4);
if(swtch1 && swtch2 && swtch3 == 1) {
TV.println("Text for switch 1,2 & 3\n");
delay(2000);
}
else if(swtch1 && swtch2 == 1) {
TV.println("Text for switch 1 & 2\n");
delay(2000);
}
else if(swtch2 && swtch3 == 1) {
TV.print("Text for switch 2 & 3\n");
delay(2000);
}
else if(swtch1 == 1) {
TV.print("Text for switch 1\n");
delay(2000);
}
else if(swtch2 == 1) {
TV.print("Text for switch 2\n");
delay(2000);
}
else if(swtch3 == 1) {
TV.print("Text for switch 3\n");
delay(2000);
}
}
LOM_dig1.ino (1.46 KB)
cpjsparks:
if(swtch1 && swtch2 && swtch3 == 1) {
This produces the right behaviour in the specific situations where you're using it, but I suspect it's only by accident.
An alternate version, which is much safer for general use, would be:
if((swtch1 == HIGH) && (swtch2 == HIGH) && (swtch3 == HIGH)) {
the problem is when two buttons are pushed it displays the result from the individual buttons also.
Yes that is exactly what you have programmed it to do.
Replace:-
else if(swtch2 == 1) {
TV.print("Text for switch 2\n");
with
else if(swtch2 == 1 && swtch1 != 1 && swtch3 != 1) {
TV.print("Text for switch 2\n");
and so on for the other cases
Thanks, I made both of those changes! However if your going to push buttons 2 & 3 but push button 2 a moment before they it gets recognized as two actions and prints out the text from pushing button 2 and the text from pushing buttons 2 & 3. I also need to add a double click function for the buttons to do something else and wasn't getting anything to work for me there. I think it shouldn't print anything until all buttons are released?
Yes or you could read twice with a delay and only do stuff when you see a change.
That still leaves me with a couple issues tho.
- If I have 61 switches then I'll have to list '!=' for all the rest of the switches in each 'if' statement.
- If I do a delay then it won't know if it was a double click or if the switch was just held down.
If I have 61 switches then I'll have to list '!=' for all the rest of the switches in each 'if' statement.
Only if you do not learn how to use arrays
http://www.thebox.myzen.co.uk/Tutorial/Arrays.html
If I do a delay then it won't know if it was a double click or if the switch was just held down.
First mention of double click I have noticed, are you moving the goal posts?
Detecting a double click from a single click is a whole level harder and involves using the millis() system clock timer.
Basically you only do anything after the time interval for the double click has passed or until you get a second transition, which ever comes sooner.
I think you have to forget any algorithm that uses tests for millis() and if this switch and that switch. It will be difficult to get working and then you'll find that it's not scalable to 61 and you'll have to start again.
I did something similar once to debounce 32 inputs, it was quite simple but did not do all the things you need. I would break the problem up into probably 2 parts, reading and recording the switch states and deciphering the results.
I would start with an circular array/buffer, 61 wide and say 10 deep, then every 100mS read all the 61 switches and store the values in the top level of the buffer.
Now you have an array with all the switch states for the last second, looking something like this (let's pretend there are only 8 switches for now)
76543210 // switch number
00001100
00101100
00001100
00101100
00001100
00001100
01101100
01101100
00101100
00101100
Here we see that switches 2 and 3 have been held down for the full second and switch 6 was briefly pressed. Switch 5 bounced a couple of times then settled to being pressed.
In my debounce app I simply turned the columns into rows and if the value was all 1s or all 0s I had a valid debounced value, any other combination was noise.
You have a much harder thing to figure out but at least with this technique you have a stable array of data to parse. As for this parsing that's another story, it will not be easy I suspect but I've also not put much thought into it.
This is not a beginners technique and may do your head in, but I really think that trying to do this with "normal" procedural code will quickly become a nightmare of spaghetti code.
PS: There may be better ways as well, just trying to suggest you think outside the box.
Rob
To do double-click detection I would just use conventional debounce logic to detect button presses, and record the time of the most recent click for each input (i.e. in an array of unsigned longs). When a click occurs, if the preceding click was within the double-click interval then report it as a double click, otherwise it's another single click. With this scheme, a double click would be reported as a single click followed by a double-click. If you don't want that then you would need a slight variation where each single click doesn't get reported until the double-click interval has elapsed - that's a relatively simple change.
I've pulled an all-nighter and been studying the for loops and arrays since each of your last posts and can definitely see that's the direction to go here. (Grumpy_Mike...not moving the goal posts ...I wrote in my first posting I'll need double clicks). I like learning this stuff but feel I get caught up on simple things. After I get this array working I'll start working on the debounce. For some reason I could not get the digitalRead to read the right pin. In the following example I want it to read pin #4 but it's reading the actual pin number instead. What am I missing here? Thanks!!
int pins [12] = {2,3,4,5,6,7,8,9,10,12,14,15};
void setup() {
Serial.begin(9600);
for(int i=0; i<12; i++) {
pinMode(pins[i], INPUT);
}
}
void loop() {
for(int i=0; i<12; i++) {
Serial.println(i);
if(digitalRead(2) == HIGH) {
Serial.println("testing text");
}
}
}
What am I missing here?
Code tags
Rob
Ok Greynomad...how do I do code tags properly? and not sure how to get those boxes inserted into the forum...very appreciated!
sorry graynomad...didn't mean to misspell (attention to detail...doing my best!)
:), I get "grey" all the time
click "modify" about your post
highlight the code and click the "#" button
Rob
When you use an array you have to specify the nixes so the code knows what element of the array to use. So
pinMode(pins, INPUT);
Should be
pinMode(pins[i], INPUT)
Same whe you are reading a pin.
Here is something to get you started if you decide to use this method
int switchPins[] = {2,3,4,5,6,7,8,9};
#define N_SWITCHES (sizeof(switchPins)/sizeof(switchPins[0]))
#define N_SAMPLES 10
#define READ_INTERVAL 1000 // read switches every 1 second so we can see what's happening
int switchvals[N_SAMPLES][N_SWITCHES];
byte flag = N_SAMPLES + 1;
int index = 0;
void setup() {
Serial.begin(9600);
for(int i=0; i < N_SWITCHES; i++) { // this really isn't required but does no harm
pinMode(switchPins[i], INPUT);
}
}
void loop() {
if (millis() % READ_INTERVAL == 0) { // yes I know, this can miss a count occasionally
readSwitches();
analyseSwitches();
}
}
void readSwitches () {
for(int i=0; i < N_SWITCHES; i++) {
switchvals[index][i] = digitalRead(switchPins[i]);
}
index++; // next row in the array
if (index >= N_SAMPLES) index = 0; // wrap to 0 if required
}
void analyseSwitches() {
if (flag) { // don't analyse the first N_SAMPLES times
flag--;
return;
}
// analysing stuff will go here, meanwhile we just print out the array
int i = index; // point to the oldest samples
for(int sample=0; sample < N_SAMPLES; sample++) { // for each lot of samples
Serial.print(i,DEC); // print index into array
Serial.print(": ");
for(int sw=0; sw < N_SWITCHES; sw++) { // for eacn switch value
Serial.print(switchvals[i][sw],HEX);
Serial.print(" ");
i++;
if (i > N_SWITCHES) i = 0;
}
Serial.println(" ");
}
Serial.println("");
}
Note though that this is the easy part, it's not clear even to me how the data would be analysed. But see if you feel comfortable with the idea.
It seems to display the correct stuff but I don't have any hardware connected to my Arduino so I can't be sure.
Rob
Hello again! Sorry for the delay but I had to take care another project before I could continue. I recently got back on this project and just wanted to post my progress so it might help someone else along.
Recap: 61 momentary switches using the MEGA 2560. Each switch has it's own pin and passes the ground signal. There are 3 possible functions per switch (click, double click and click & hold). It's easy to change the time between double clicks and click & hold time. My only outputs are Serial.print and I only included the first 3 of 61 to shorten up the post. I still have to figure out another user option, and that's to do something if 2 or more switches are held down simultaneously.
int debounce = 10;
int dblClickGap = 300;
int holdTime = 700;
byte key[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
byte keyLast[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
byte keyDownWait[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte dblClick[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
long int keyDown[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
long int keyUp[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
byte keyHold[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte keyHoldPast[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int pin[] = {2,3,4,5,6,7,8,9,10,14,15,16,17,18,19,22,23,24,25,26,27,28,30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,48,49,50,51,52,53,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15};
void setup() {
Serial.begin(9600);
for(int i = 0; i < 61; i++) {
pinMode(pin[i], INPUT_PULLUP);
digitalWrite(pin[i], HIGH);
} }
void loop() {
for(int i = 0; i < 61; i++) {
int b = 0;
key[i] = digitalRead(pin[i]);
if(key[i] == 0 && keyLast[i] == 1 && (millis() - keyUp[i]) > debounce) {
keyDown[i] = millis(); keyHold[i] = 0; keyHoldPast[i] = 0;
if((millis()-keyUp[i]) < dblClickGap && dblClick[i] == 0 && keyDownWait[i] == 1)
dblClick[i] = 1;
else {
dblClick[i] = 0; keyDownWait[i] = 0;
} }
else if(key[i] == 1 && keyLast[i] == 0 && (millis() - keyDown[i]) > debounce) {
if(!keyHold[i]) {
keyUp[i] = millis();
if(dblClick[i] == 0)
keyDownWait[i] = 1;
else {
b = 2;
} } }
if(key[i] == 1 && (millis()-keyUp[i]) >= dblClickGap && keyDownWait[i] == 1 && dblClick[i] == 0) {
b = 1; keyDownWait[i] = 0;
}
if(key[i] == 0 && (millis() - keyDown[i]) >= holdTime) {
if(!keyHoldPast[i]) {
b = 3; keyHold[i] = 1; dblClick[i] = 0; keyHoldPast[i] = 1;
} }
keyLast[i] = key[i];
if(b == 1 && i == 0) Serial.println("\nSingle Click 1");
if(b == 2 && i == 0) Serial.println("\nDouble Click 1");
if(b == 3 && i == 0) Serial.println("\nClick & Hold 1");
if(b == 1 && i == 1) Serial.println("\nSingle Click 2");
if(b == 2 && i == 1) Serial.println("\nDouble Click 2");
if(b == 3 && i == 1) Serial.println("\nClick & Hold 2");
if(b == 1 && i == 2) Serial.println("\nSingle Click 3");
if(b == 2 && i == 2) Serial.println("\nDouble Click 3");
if(b == 3 && i == 2) Serial.println("\nClick & Hold 3");
} }