Sunday, July 10, 2022

tinkercad keypad + pin change interrupt



The Arduino detects which button is pressed by detecting the row and column pin that’s connected to the button.

This happens in four steps:

1. First, when no buttons are pressed, all of the column pins are held HIGH, and all of the row pins are held LOW:

2. When a button is pressed, the column pin is pulled LOW since the current from the HIGH column flows to the LOW row pin:

3. The Arduino now knows which column the button is in, so now it just needs to find the row the button is in. It does this by switching each one of the row pins HIGH, and at the same time reading all of the column pins to detect which column pin returns to HIGH:

4. When the column pin goes HIGH again, the Arduino has found the row pin that is connected to the button:

----------------------
int row = 0;
int col = 0;
bool keypress = true;
int interrupt_count=0;
bool skip_interrupt = false;

char hexaKeys[4][4] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

void setup()
{
  Serial.begin(115200);
  
  DDRB = 0b00001111; //pin 8-11 as output
  PORTB |= 0b00001111; //set pin 8-11 high
  Serial.print("initial PINB ");
  printBin(PINB);
  Serial.println();
  Serial.print("initial PIND ");
  printBin(PIND);
  Serial.println();
  
  
  PCICR |= 0b00000100; //enable PCMSK2 (group 2: PCINT16 to PCINT23)
  PCMSK2 |= 0b11110000; //pin 4-7 could trigger interrupt
}

void loop()
{
  
}

ISR (PCINT2_vect){
  //1st interrupt happens when key is pressed, one input pin (col) goes high
  //2nd interrupt happens when output pins (row) are set to low one by one
  //to find which one casue the input pins (col) to go low. That's the row #
  //3rd interrupt happens when output pins are set to high for detecting next keypress
  //if key is pressed, input pins (col) goes high
  //4th interrupt happens when key is released, input goes low
  interrupt_count++;
  
  Serial.print("interrupt count ");
  Serial.println(interrupt_count);
  
  Serial.print("keypress ");
  Serial.println(keypress);
  
  Serial.print("skip interrupt ");
  Serial.println(skip_interrupt);
  
  if(skip_interrupt){
  skip_interrupt = false;
    return;
  }
  
  if(keypress){
          //detect keypressed and interrupt on rising edge of input pins
  //if pin8-11 are high(all rows are high)
  if(PINB & 0b00001111 == 0b00001111){
        Serial.println("finding column");
      
  switch(PIND & 0b11110000){
  case 0b10000000:
    col = 0;
    break;
    case 0b01000000:
    col = 1;
    break;
    case 0b00100000:
    col = 2;
    break;
    case 0b00010000:
    col = 3;
      break;
    }
  }
 
  //set pin8-11 low one by one
    for(int i=0; i< 4; i++){
      byte b = 0b00000000;
      
      switch(i){
      case 0:
         b=0b11110111; //set pin 11 low
         break;
        case 1:
         b=0b11111011; //set pin 10 low
         break;
        case 2:
         b=0b11111101; //set pin 9 low
         break;
        case 3:
         b=0b11111110; //set pin 8 low
         break;
      }
      
       Serial.print("loop to find row. Iteration ");
       Serial.println(i+1);
      
       PORTB = PINB & b;
       Serial.print("pinB ");
       printBin(PINB);
       Serial.println();
      
       Serial.print("pinD ");
       printBin(PIND & 0b11110000);
       Serial.println();
       
       //if pin7-4 are low after pin11-8 are set low
      if(!(PIND & 0b11110000)){
        //found row #
      row = i;
         
        keypress = false;
        break;
      }
    }
    
    Serial.print("row col ");
  Serial.print(row);
  Serial.print(" ");
  Serial.println(col);
    Serial.println();
    Serial.print("key pressed is ");
    Serial.println(hexaKeys[row][col]);
    Serial.println();
    
    //reset pin 11-8 high for detect next keypress,
    //next interrupt will be ignored to prevent extra code execution
    Serial.println("reset output pins high for detecting next keypress");
    skip_interrupt = true;
    PORTB = PINB | 0b00001111;
  }
  
  //enable keypress detection
  if(interrupt_count == 4){
  interrupt_count = 0;
    keypress = true;
  }
}

void printBin(byte aByte) {
  for (int8_t aBit = 7; aBit >= 0; aBit--)
    Serial.write(bitRead(aByte, aBit) ? '1' : '0');
}

reference:

pin change interrupt

No comments:

Post a Comment