Map button matrix to integers

Hi Everyone, I have a button matrix - 64 buttons, below is some data from pressing the buttons down. I need to turn each buttons matrix position into an integer. The first value is the integer I need to convert to, the second is the row and the third is the column. I have sampled just a section of the button matrix presses. Please can someone help me with the algorithm to map to the integer. I cant get something that will work for all instances:

 I   C       R
----------------
48: 0x04 : 0x08
49: 0x04 : 0x04
50: 0x04 : 0x02
51: 0x04 : 0x01

52: 0x05 : 0x80
53: 0x05 : 0x40
54: 0x05 : 0x20
55: 0x05 : 0x10
56: 0x05 : 0x08
57: 0x05 : 0x04
58: 0x05 : 0x02
59: 0x05 : 0x01

60: 0x06 : 0x80
61: 0x06 : 0x40
62: 0x06 : 0x20
63: 0x06 : 0x10
64: 0x06 : 0x08
65: 0x06 : 0x04
66: 0x06 : 0x02
67: 0x06 : 0x01

68: 0x07 : 0x80
69: 0x07 : 0x40
70: 0x07 : 0x20
71: 0x07 : 0x10
72: 0x07 : 0x08

Thanks

Have you tried the Keypad library? http://arduino.cc/playground/

The problem with using the keypad library is I have to trial and error what row and what column values are what button pressed, and then store it in a map. From my test data there is clearly a pattern, so i would rather the algorithm that maps from one to the other and would like some help figuring it out, if anyone can help Thanks

So i was successfuly in mapping the posiiton in the array to the midi. now I am interested in optimizing polling the key matrix. Please can anyone suggest improvements to the following polling algorithm:

void KeyMatrix::pollKeys() {
	uint8_t cRows = 0, cCols = 0;
	for (uint8_t maskRows = 1; maskRows != 0; maskRows += maskRows) {
		PORTK = ~maskRows; //low one col with all others pull-up
		_delay_us(10); //after setting the state of a pin there may need to be a delay
		if (~PINH != 0) {
			for (uint8_t maskCols = 1; maskCols != 0; maskCols += maskCols) {
				if (~PINH & maskCols) {
					ATOMIC_BLOCK(ATOMIC_FORCEON)
						{
							button[cRows][cCols].time = flagmS;
						}	
					button[cRows][cCols].isPressed = true;
				} else
					button[cRows][cCols].isPressed = false;
					if (cRows > 4){
					sendNote(cRows, cCols);
					}
					
				cCols++;
			}
			cCols = 0;
		}
		cRows++;
	}
}

Thanks

Both

for (uint8_t maskCols = 1; maskCols != 0; maskCols += maskCols) {

and

for (uint8_t maskRows = 1; maskRows != 0; maskRows += maskRows) {

Make no sense.

maskCols / Rows will never be nor get to zero to exit the for loops, because your starting at 1 and incrementing. You could just have easily wrote "for(;;)"

How does this work?

How can you map readings of buttons to ints if they are boolean readings? They only have on/off states. However if you are talking about mapping them in the sense of their position, then consider using a multiple dimension array.

http://arduino.cc/forum/index.php?topic=44228.0

Or here is an example:

array [x][y] {
boolean read = digitalRead(array [x][y]);
}
array [x][y] {
boolean read = digitalRead(array [x][y]);
}

That does not make sense either. You cannot read 2 pins at the sametime with just one digital read. I don't know, maybe we finally can, and I just didn't get the memo.

Firstly you can read two pins at the same time, infact you can read 8 if you read the whole port:

uint8_t a = PINB;

would read the whole of PINB into a.

Secondly:

Both
Quote
for (uint8_t maskCols = 1; maskCols != 0; maskCols += maskCols) {
and
Quote
for (uint8_t maskRows = 1; maskRows != 0; maskRows += maskRows) {
Make no sense.

maskCols / Rows will never be nor get to zero to exit the for loops, because your starting at 1 and incrementing. You could just have easily wrote “for(;”

How does this work?

Is also not true.
When you bit shift a mask so the left so that the one goes off the end, what value do you think the mask is equal to?
Yes! 0.
i.e
take the following:
value = 0b00000001;
If I shift:
value = (1 << 7);
I get 0b10000000;
Shift it one more value to the left and now value = 0.

How can you map readings of buttons to ints if they are boolean readings?

Very easily. A boolean value firstly is just a 1 or a 0, not an on/off. This is just a way for us to think about it - like true false. It just so happens that it can be stored in 1 bit. That doesnt stop an integer being able to store it. You may need a cast but so what?
Secondly, I never said anything about an int.
Infact if I had thoguth it was necessary to the problem I would have displayed that button is a struct:

struct data {
	unsigned int time;
	bool isPressed;
	bool wasPressed;
	uint8_t midiNote;
};

see bools…

Anyway, I think I cracked it, so thank you for the efforts.

HazardsMind: That does not make sense either. You cannot read 2 pins at the sametime with just one digital read. I don't know, maybe we finally can, and I just didn't get the memo.

Maybee, we both didn't get the memo :D But what I meant in my code is reading the value of a button that is on a specific X Y coordinate. A 2D array must be used for this to work.

You cannot read 2 pins at the sametime with just one digital read

Direct port manipulation is different, that I know you can read multiple pins, but with a regular Digital/Analog read, you can't.

You should probably post your full code.

OK.
This is my class (.cpp):

KeyMatrix::KeyMatrix(Serial *serial, Midi *midi) {
	this->serial = serial;
	this->serial->printf("key matrix setup\n");
	this->midi = midi;

	//Prepare the rows for reading
	DDRH = 0b00000000; //All Ts are inputs
	PORTH = 0b11111111; //All pullups enabled
	//read from PINH

	DDRK = 0b11111111;//MK and BR are outputs - one is pulled low at a given time.
	PORTK = 0b11111111;	//Set them high for now. We can pull one low when scanning.
	for (uint8_t i = 0; i < 8; i++) {
		for (uint8_t j = 0; j < 7; j++) {
			button[i][j].isPressed = false;
			button[i][j].wasPressed = false;
			button[i][j].midiNote = 12 + i*8 + (7-log(j)/log(2));
		}
	}
}

void KeyMatrix::pollKeys() {
	uint8_t cRows = 0, cCols = 0;
	for (uint8_t maskRows = 1; maskRows != 0; maskRows += maskRows) {
		PORTK = ~maskRows; //low one col with all others pull-up
		_delay_us(10); //after setting the state of a pin there may need to be a delay
		if (~PINH != 0) {
			for (uint8_t maskCols = 1; maskCols != 0; maskCols += maskCols) {
				if (~PINH & maskCols) {
					ATOMIC_BLOCK(ATOMIC_FORCEON)
						{
							button[cRows][cCols].time = flagmS;
						}
					button[cRows][cCols].isPressed = true;
				} else {
					button[cRows][cCols].isPressed = false;
				}
					if (cRows >= 4 && cCols != 0){
					sendNote(cRows, cCols);
					}

				cCols++;
			}
			cCols = 0;
		}
		cRows++;
	}
}

void KeyMatrix::sendNote(uint8_t cRows, uint8_t cCols){

	if (button[cRows][cCols].isPressed != button[cRows][cCols].wasPressed) {
	//needs to be changed for midi output once debugging has confirmed the correct thing is occuring:
			serial->printf("i: %d, j: %d. Time: %u, Note: %u\n",cRows, cCols, (button[cRows][cCols].time - button[cRows-4][cCols].time), button[cRows][cCols].midiNote);//output the midi note & add to arpeggiator array?
			button[cRows][cCols].wasPressed = button[cRows][cCols].isPressed;
		}
}

In terms of compilation everything works. I dont have access to the header file from where I am, but the struct that you need the details of is in my previous post.
This line:

button[i][j].midiNote = 12 + i*8 + (7-log(j)/log(2));

is trying to map the matrix location to the integer value I am trying to get out, however if j is zero I have problems…

I have not used Arduino methods here as i want it to be as fast as possible to poll, hence my use of masks. However the fact that I am incrementing cRows and cCols worries me that I may be losing any benefits.