# Finger switch recognize if going up or down

so i dont have a rotary encoder, but I do have a finger switch:

that goes from 0 to 9. the following code workes out what number the user is on:

``````int readSwitch()
{
int total=0;
}
``````

but I want to use it like a rotary encoder, I know its not really designed for that but I feel it can be done, i just cant crack it!
I.e if new number > last number, going one way, otherwise going the other way. Except when I go from 0 to 9, or 9 to 0. Is the only way to use if's?
Any ideas greatly appreciated.
Thanks

Is the only way to use if's?

Yes.

``````int readSwitch()
{
return
}
``````

Then you can compare the new value to the old. Unfortunately you need to compare modulo 10:

``````int switchChange()
{
static int oldValue = 0;

if (newVale == oldValue)
return 0;

int returnValue = newValue - oldValue;

if (returnValue < -6)
returnValue += 10;  // Switch probably wrapped around from 9 to 0
else
if (returnValue > 6)
returnValue -= 10;  // Switch probably wrapped from 0 to 9;

oldValue = newValue;
return returnValue;
]
``````

Cheers for your answer. Im just trying to read normally from it at the moment, and I am getting 15 on my lcd (8+4+2+1). By checking on my multimeter, all four pins are getting 5 volts. i just wondered whether this was norm, because if I move the switch the number doesnt change from 15. i.e do I have a short, or is my wiring wrong. I have been going by this scematic:

My code is:

``````#include <Adafruit_GFX.h>
#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static unsigned char __attribute__ ((progmem)) logo16_glcd_bmp[]={
0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0xf8, 0xbe, 0x9f, 0xff, 0xf8, 0xc0, 0xc0, 0xc0, 0x80, 0x00,
0x20, 0x3c, 0x3f, 0x3f, 0x1f, 0x19, 0x1f, 0x7b, 0xfb, 0xfe, 0xfe, 0x07, 0x07, 0x07, 0x03, 0x00, };

#define q1 38
#define q2 39
#define q4 40
#define q8 41

void setup()
{
display.begin();
display.setContrast(40);
display.clearDisplay();   // clears the screen and buffer
// text display tests
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(0,10);
display.println("Hello World");
display.display();
delay(1000);

pinMode(q1, INPUT); // thumbwheel '1'
pinMode(q2, INPUT); // thumbwheel '2'
pinMode(q4, INPUT); // thumbwheel '4'
pinMode(q8, INPUT); // thumbwheel '8'
}

{
int total=0;
}

void loop()
{
//dispSAA1064(readSwitch()); // sends switch value to display shield
display.clearDisplay();
display.println(readSwitch()); // sends switch value to serial monitor box
display.display();
delay(200);
}
``````

Thanks

If your switch is reliably producing numbers from 0 to 16 you can use a table of structures to get the direction. In fact you don't care about all the values, just use the 2 LSBs.

EDIT: Maybe something like this

``````typedef struct {
byte newVal;
byte lastVal;
byte dir;
} encoder;

#define UP 1
#define DN -1

byte lastVal = 0;
byte direction;

encoder x[8] = {
{0, 1, UP},
{0, 3, DN},
{1, 2, UP},
{1, 0, DN},
{2, 3, UP},
{2, 1, DN},
{3, 0, UP},
{3, 2, DN}
};

void setup() {

}

byte getSwitchVal() {};

void loop() {
byte newVal = getSwitchVal();

for (int i; i < 4; i++) {
if ((x[i].newVal == newVal) && (x[i].lastVal == lastVal)) {
direction = x[i].dir;
break;
}
}
lastVal = newVal;

}
``````

Rob

Im getting there with the logic, but still havent nailed it. I couldn't quite understand your code Johnwasser, and it wasnt working quite correctly, so i tried to do it using a more stupid way:

``````int readSwitch()
{
int total=0;
}
void switchChange()
{
display.clearDisplay();
static int oldValue = 0;
if (newValue == oldValue)
display.println("No Change");
if (newValue > oldValue && newValue <= 9 && newValue >)
display.println("increase");
if (newValue < oldValue && newValue >= 0)
display.println("Decrease");
if (newValue > 9){
display.println("Increase (>9)");
oldValue = 0;
}
if (newValue < 0){
display.println("Decrease (<0)");
oldValue = 9;
}
display.display();
oldValue = newValue;
}
``````

It still has issues when crossing the 0-9 and 9-0 line in terms of an increase or a decrease.

Sorry Rob, didnt see your code there should getSwitchVal just be:

``````byte getSwitchVal()
{
int total=0;
}
``````

?

``````    if (newValue > oldValue && newValue <= 9 && newValue >)
``````

Does this even compile? And newValue greater than what?

soz, I thought I had removed that last condition! Must have been an Ctr-Z moment!
I was running it with just the condiiton:

`````` if (newValue > oldValue && newValue <= 9)
``````

How can newValue not be less than or equal to 9?

I think I'd take care of the limit conditions, first. If newValue is 9, do something. Else, if it is 0, do something else. Else, do a third thing.

should getSwitchVal just be:

Yes, except you don't need q4 and q8.

EDIT: Possibly easier with an array.

Rob

Here's a version that uses an array

``````#define UP 1
#define DN 2

byte lastVal = 0;
byte direction;

byte x[16] = {
/*New	Last 	Dir */
/*0, 	0*/  -1,	// 0	-1 = invalid combination
/*0, 	1*/  DN,	// 1
/*0, 	2*/  -1,	// 2
/*0, 	3*/  -1,	// 3
/*1, 	0*/  UP,	// 4
/*1, 	1*/  -1,	// 5
/*1, 	2*/  DN,	// 6
/*1, 	3*/  -1,	// 7
/*2, 	0*/  -1,	// 8
/*2, 	1*/  UP,	// 9
/*2, 	2*/  -1,	// 10
/*2, 	3*/  DN,	// 11
/*3, 	0*/  -1,	// 12
/*3, 	1*/  -1,	// 13
/*3, 	2*/  UP,	// 14
/*3, 	3*/  -1	// 15

};

void setup() {

}

byte getSwitchVal() {
int total=0;
};

void loop() {
byte newVal = (getSwitchVal() & 3);

direction = x[(newVal << 2) | lastVal];
lastVal = newVal;

}
``````

I hope I got the values right, I admit it was doing my head in for a while and it's real late here.

Rob

a.mlw.walker:
I am getting 15 on my lcd (8+4+2+1). By checking on my multimeter, all four pins are getting 5 volts. i just wondered whether this was norm, because if I move the switch the number doesnt change from 15.

Sounds like your switch is not wired correctly. I assume the switch has a 'common' pin an four data pins. What is the common pin connected to?

You have two choices:

1. Connect common to Ground and connect each data pin through a pull-up resistor to +5. You can use the internal pull-up resistors: pinMode(dataPin, INPUT); digitalWrite(dataPin, HIGH);

2. Connect common to +5 and connect each data pin through a pull-down resistor to Ground.

Choice 1 with the internal pull-ups uses fewer parts but gives a '1' for open and a '0' for closed. You can reverse the logic in the program by using the logical invert operator '!':

``````int readSwitch()
{
return
}
``````

I got something working with improved logic on my earlier post. You array ways sound like they are the better way to do it, purely because i think writing out the logic using ifs/else ifs seems amateur?
Yeah i have wired it common - 5V, my ground line had popped out of the arduino and i hadn't spotted it ..

a.mlw.walker:
i have wired it common - 5V

Do you have the four pull-down resistors? It won't work correctly without them.

array ways sound like they are the better way to do it,

Every time you see more than a few if/elses there's probably a better way to do it. That array version is not intuitive I admit but it uses a single line of code and is fast. It's also deterministic, no matter what the values it takes the same time.

For this simple project it doesn't matter but I thought I'd try to get you started thinking about alternative ways to do things.

Rob

No completely, im always up for learning the "better" way. Often i find myself starring at if else's and thinking how can this be done better. Usually i go about it the stupid way and then study the better way to work out what can be improved. I need to call other functions based on the outcome so hopefully i can see where I should do that...
(yeah i have the resistors..)
I'll look over your code and "re-energize" this thread when I've got another question :D.
Cheers guys

I need to call other functions based on the outcome so hopefully i can see where I should do that...

Look up "array of function pointers".

The array I had can be an array of function pointers instead of just bytes.

Rob