Go Down

Topic: 5x5 Button Matrix Diode speed + Timer PINS (Read 949 times) previous topic - next topic

Flub

Hi!

I am programming a 5x5 Button Matrix right now and I used 1n4148 diodes for every switch to prevent ghosting and masking.

Well this is the code :

Code: [Select]
void check_button() {
  PORTH |= (1 << 5);
    if ((PINH & (1 << 4)) != 0) { button_state[0][0]=1;} else { button_state[0][0]=0; }
    if ((PINE & (1 << 5)) != 0) { button_state[0][1]=1;} else { button_state[0][1]=0; }
    if ((PINE & (1 << 3)) != 0) { button_state[0][2]=1;} else { button_state[0][2]=0; }
    if ((PINH & (1 << 3)) != 0) { button_state[0][3]=1;} else { button_state[0][3]=0; }
    if ((PINE & (1 << 4)) != 0) { button_state[0][4]=1;} else { button_state[0][4]=0; }
  PORTH &= ~(1 << 5);
// delay(10);
  PORTB |= (1 << 4);
    if ((PINH & (1 << 4)) != 0) { button_state[1][0]=1;} else { button_state[1][0]=0; }   
    if ((PINE & (1 << 5)) != 0) { button_state[1][1]=1;} else { button_state[1][1]=0; }
    if ((PINE & (1 << 3)) != 0) { button_state[1][2]=1;} else { button_state[1][2]=0; }
    if ((PINH & (1 << 3)) != 0) { button_state[1][3]=1;} else { button_state[1][3]=0; }
    if ((PINE & (1 << 4)) != 0) { button_state[1][4]=1;} else { button_state[1][4]=0; }
  PORTB &= ~(1 << 4);
//  delay(10);
  PORTB |= (1 << 5);
    if ((PINH & (1 << 4)) != 0) { button_state[2][0]=1;} else { button_state[2][0]=0; }   
    if ((PINE & (1 << 5)) != 0) { button_state[2][1]=1;} else { button_state[2][1]=0; }
    if ((PINE & (1 << 3)) != 0) { button_state[2][2]=1;} else { button_state[2][2]=0; }
    if ((PINH & (1 << 3)) != 0) { button_state[2][3]=1;} else { button_state[2][3]=0; }
    if ((PINE & (1 << 4)) != 0) { button_state[2][4]=1;} else { button_state[2][4]=0; }
  PORTB &= ~(1 << 5);
// delay(10);
  PORTB |= (1 << 6);
    if ((PINH & (1 << 4)) != 0) { button_state[3][0]=1;} else { button_state[3][0]=0; }   
    if ((PINE & (1 << 5)) != 0) { button_state[3][1]=1;} else { button_state[3][1]=0; }
    if ((PINE & (1 << 3)) != 0) { button_state[3][2]=1;} else { button_state[3][2]=0; }
    if ((PINH & (1 << 3)) != 0) { button_state[3][3]=1;} else { button_state[3][3]=0; }
    if ((PINE & (1 << 4)) != 0) { button_state[3][4]=1;} else { button_state[3][4]=0; }
  PORTB &= ~(1 << 6);
//delay(10);
  PORTH |= (1 << 6);
    if ((PINH & (1 << 4)) != 0) { button_state[4][0]=1;} else { button_state[4][0]=0; }   
    if ((PINE & (1 << 5)) != 0) { button_state[4][1]=1;} else { button_state[4][1]=0; }
    if ((PINE & (1 << 3)) != 0) { button_state[4][2]=1;} else { button_state[4][2]=0; }
    if ((PINH & (1 << 3)) != 0) { button_state[4][3]=1;} else { button_state[4][3]=0; }
    if ((PINE & (1 << 4)) != 0) { button_state[4][4]=1;} else { button_state[4][4]=0; }
  PORTH &= ~(1 << 6);
  //delay(10);
  // Serial.println((PINE & (1 << 3)),BIN);
  button_process();
}   
void button_process() {
  for (int i = 0; i < 5; i++) {
    for (int x = 0; x < 5; x++) {
      if (button_state[i][x]) {Serial.println(i);Serial.println(x);}
    } 
  }
}


The problem is that it only works with the delay(10) which i entered for testing.
I believe the 1N4148 Diodes switching time (4ns) might be to long and i should try schottkies, am I right or is there another problem?

The other thing i want to ask you guys deals with the timer pins, because i have only few pins left I need to use some pins which are affected by timers.
Can I use a timer without affecting its pins? or in other words, is it possible to detach pins from the Timers?
I mean I dont need 3 pins for my timers...

regards,
FLo

dc42

I think the main problem is that without the delay calls, the Serial.println() calls are blocking because of the large amount of data you are trying to send. Try modifying the code so that you only print changes in the button states to the serial port.

You might need a small delay (a few microseconds) between setting the bit in the column port and executing the bunch of if-statements, but no more than that.

Why not make the element type of the button array bool, and simplify the code? Like this:

Code: [Select]

void check_button() {
 const int columnSettleTime = 5;
 PORTH |= (1 << 5);
 delayMicroseconds(columnSettleTime);
 buttonState[0][0] = ((PINH & (1 << 4)) != 0);
 buttonState[0][1] = ((PINE & (1 << 5)) != 0);
...
 PORTH &= ~(1 << 5);
 PORTB |= (1 << 4);
 delayMicroseconds(columnSettleTime);
 buttonState[1][0] = ((PINH & (1 << 4)) != 0);
 buttonState[1][1] = ((PINE & (1 << 5)) != 0);


and so on.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Flub

Hi,
Thanks for your answer.

My fault was to not use Pulldown resistors for the Inputs...
this is the new code.
It is based on this one http://www.mikrocontroller.net/attachment/1924/Kbd_drvn.c51
which i used to understand the problem / find a solution

Code: [Select]
unsigned int check_button() {
 unsigned char input;
 int i = 0;
 int j = 0;
 unsigned char mask;
 unsigned char key;
 unsigned char key_nr = 0;
 for (j = 0; j < 5; j++) {
   switch (j) {
     case 0: PORTH |= (1 << 5);
     break;
     case 1: PORTB |= (1 << 4);
     break;
     case 2: PORTB |= (1 << 5);
     break;
     case 3: PORTB |= (1 << 6);
     break;
     case 4: PORTH |= (1 << 6);
     break;
   }
   input = (PINH & 0x18) | ((PINE & 0x38) >> 3);
   if( input != button_state[j] && key_nr == 0 ){
     
     if (input != button_state[j]) {
       for (mask = 1, i = 0; i <5; mask <<= 1, i++) {
         key = input & mask;
         if (key == (last_button_state[j] & mask)) {
           if (key != (button_state[j] & mask)) {
             button_state[j] = (button_state[j] & ~mask) | key;
             key_nr = j*5+i+1;    
             if (key != 0) {
               n_keys_pressed++;
             } else {
               n_keys_pressed--;
             }
             //break;
           }
         }
       }    
       
       last_button_state[j] = input;
     }
   }
   switch (j) {
     case 0: PORTH &= ~(1 << 5);
     break;
     case 1: PORTB &= ~(1 << 4);
     break;
     case 2: PORTB &= ~(1 << 5);
     break;
     case 3: PORTB &= ~(1 << 6);
     break;
     case 4: PORTH &= ~(1 << 6);
     break;
   }
 }
   if (key_nr != 0) {
     Serial.println(key_nr);
   }  
}  


What about those timer pins, can i use timer 4 and use the Timer 4 Pins as regular digital in/outs simultaneously? ?


dc42


My fault was to not use Pulldown resistors for the Inputs...


That would certainly explain the problem. it is more usual to design this kind of circuit to use pullup resistors rather than pulldown resistors, that way you can use the internal ones. To do this, you would set all the column bits high initially, than take them low one at a time and read the input pins. Inputs that are low indicate buttons that are pressed.


What about those timer pins, can i use timer 4 and use the Timer 4 Pins as regular digital in/outs simultaneously? ?


I presume you are using an Arduino Mega. Yes, you can use timer 4 for functions that don't need to use OCR4A/B/C when you use digital pins 6, 7 and 8. For example, you could use it to generate regular interrupt.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Go Up