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.
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 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.