Make a Sound Board out of Keypad libray

Hi Y'all,

Newish to programming the arduino here and I am stuck on a problem. I am looking to make the board play a tone and hold it for as long as the corresponding button on the keypad is held for. I've tried multiple ways and currently have this code that is not working due to "while" state in the "tone" command.

Any suggestions?

#include <Key.h>
#include <Keypad.h>


const byte rows=4;
const byte cols=4;

byte rowpins[rows]={5,4,3,2};
byte colpins[cols]={6,7,8,9};

char buttons[rows][cols] = {
  {'C', 'S', 'D', 'E'},  // 1st row
  {'F', 'S', 'G', 'A'},  // 2nd row
  {'B', '1', '2', '3'},  // 3rd row
  {'4', '5', '6', '7'}   // 4th row
};

Keypad myPad = Keypad(makeKeymap(buttons),rowpins,colpins,rows,cols);

int tones[rows][cols] = {   // a frequency tone for each button
    {523,554, 587, 659},
    {698, 740, 784, 880},
    {988, 1047, 1109, 1175},
    {1319, 1397, 1480, 1568}

};


int buzzer = 10;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600); // Begin monitoring via the serial monitor
  pinMode(buzzer,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  int toneFreq=0;
char result = myPad.getKey();
char hold = myPad.getState();


if(result){
   for (byte j=0; j<rows; j++) {
        for (byte i=0; i<cols; i++) {
            if (result == buttons[j][i]) {   // found it, get the corresponding tone
                toneFreq=tones[j][i];
            }
        }
   }
Serial.print("Key: ");     //   send the result to serial...
    Serial.print(result);
    Serial.print("   Freq: ");
    Serial.println(toneFreq);



    tone(buzzer, toneFreq, while(myPad.getState==PRESSED));}
   delay(50);
    noTone(buzzer);

  }

This may not work the way you expect. The last parameter is duration, right? What actually happens, the tone function isn't called until after the while statement completes. And then, it returns an undefined value (because a while statement has no value AFAIK).

If you turn on compiler warnings, it will undoubtedly complain about this.

Don't try to be so fancy until you achieve guru status. :slight_smile:

Thanks aarg. I too think i'm making this more complicated than it needs to be. the Tone function has (pin, pwm value, duration) and i just can't figure out a way to make that duration to be as long as i have the button pressed, then stop when release.

Call tone() with no duration and then:
" A duration can be specified, otherwise the wave continues until a call to noTone()."

That reduces your question to just, how to call a function on key press and key release... I'm pretty sure the keypad library has functions to report key press and release events, you would have to look them up.

Indeed it does support keypad events. Look at this example

SOLVED!!! thanks for all the help below. here's the functioning code, though it may not be pretty


#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},  // 1st row
  {'4', '5', '6', 'B'},  // 2nd row
  {'7', '8', '9', 'C'},  // 3rd row
  {'*', '0', '#', 'D'}   // 4th row
};
int tones[ROWS][COLS] = {   // a frequency tone for each button
    {31, 93, 147, 208},
    {247, 311, 370, 440},
    {523, 587, 698, 880},
    {1397, 2637, 3729, 4978}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {6,7,8,9}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
byte ledPin = 13; 

boolean blink = false;
boolean ledPin_state;

void setup(){
    Serial.begin(9600);
    pinMode(ledPin, OUTPUT);              // Sets the digital pin as output.
    digitalWrite(ledPin, HIGH);           // Turn the LED on.
    ledPin_state = digitalRead(ledPin);   // Store initial LED state. HIGH when LED is on.
    keypad.addEventListener(keypadEvent); // Add an event listener for this keypad
}

void loop(){
    char key = keypad.getKey();
    int freq = 0;
if (key){                    // if a button is pressed
 
     for (byte j=0; j<ROWS; j++) {
        for (byte i=0; i<COLS; i++) {
            if (key == keys[j][i]) {   // found it, get the corresponding tone
                freq=tones[j][i];
               }
           
        }  // end i loop
     }  // end j loop
  
   
}
}

// Taking care of some special events.
void keypadEvent(KeypadEvent key){
  int freq = 0;
  if (key){                    // if a button is pressed
 
     for (byte j=0; j<ROWS; j++) {
        for (byte i=0; i<COLS; i++) {
            if (key == keys[j][i]) {   // found it, get the corresponding tone
                freq=tones[j][i];
               }
           
        }  // end i loop
     }  // end j loop
  
   
}
    switch (keypad.getState()){
    case PRESSED:
        if (key) {
          tone(10,freq,5000);
Serial.print(key);
Serial.println(" pressed") ;      // Remember LED state, lit or unlit.
        }
        break;

    case RELEASED:
        if (key) {
          noTone(10);
Serial.print(key);
Serial.println(" released") ;
        }
        break;

    case HOLD:
        if (key) {
          tone(10,freq);
 Serial.print(key);
Serial.println(" held") ;
        }
        break;
    }
}

There's no point in staying inside to complete both of the nested 'for loops' once you've found a match. It's impossible to find another match, so why keep going round and round wasting time? Break out!

  int freq = 0;
  if (key) {                   // if a button is pressed
    for (byte j = 0; j < ROWS; j++) {
      for (byte i = 0; i < COLS; i++) {
        if (key == keys[j][i]) {   // found it, get the corresponding tone
          freq = tones[j][i];
          break;
        }

      }  // end i loop
      if (freq != 0) {
        break;
      }
    }  // end j loop
  }

Also, PLEASE hit cntrl-t in the Arduino IDE to auto-format your code. It will make the indentation far less ugly.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.