I have this project of a "phone". It consists of:
- Arduino DUE,
- 4x4 Keypad,
- SD Data shield,
- a phone receiver detect (on/off)
- an Amp and a Speaker.
In the beginning, after the phone receiver is being picked, I am playing a .wav file of an intro on how to choose a language. And this .wav should be interrupted when the user presses the 4th row of a keypad (Buttons A/B/C/D). I only need one pin as far as I know, in this setup - pin 38 (Column 4 pin). As I understand, there is no proper way to declare a keypad input pin as an interrupt on DUE. Or is it?
So my question - how to wire a keypad input pin as an interrupt? I have read about wiring with a diode. But most of the threads lack any specifics.
Can someone push me in the right direction? Cheers!
Code:
#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Key.h>
#include <Keypad.h>
const byte ROW_NUM = 4;
const byte COLUMN_NUM = 4;
int code1 = 12345; //The code I used, you can change it
int code2 = 45678; //The code I used, you can change it
int code3 = 78900; //The code I used, you can change it
int tot, i1, i2, i3, i4, i5;
char c1, c2, c3, c4;
char hexaKeys[ROW_NUM][COLUMN_NUM] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte hookPinA = 23; // your interrupt pin
byte interruptPin = 22; // your interrupt pin
byte pin_rows[ROW_NUM] = {52, 50, 48, 46}; //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {44, 42, 40, 38}; //connect to the column pinouts of the keypad
int keyCounter = 0;
Keypad myKeypad = Keypad(makeKeymap(hexaKeys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM);
char keypresses[5];
char language;
char key;
int goIntoKeys = 0;
volatile uint8_t interruptState = 0;
volatile byte hookOffState = 0;
void setup() {
// debug output at 9600 baud
Serial.begin(9600);
SD.begin(10);
analogWriteResolution(12);
//for( int i=0; i< ROW_NUM; ++i) pinMode(pin_rows[i], INPUT_PULLUP);
//for( int i=0; i< COLUMN_NUM; ++i) pinMode(pin_column[i], INPUT_PULLUP);
pinMode(hookPinA, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(hookPinA), hookOffToggle, CHANGE);
// EIFR |= bit(INTF0); // clear INT0 interrupt flag
attachInterrupt(digitalPinToInterrupt(interruptPin), interruptToggle, RISING); //test interrupt with a regular button
pinMode(38, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(38), interruptToggle, RISING);
DACC->DACC_CHDR = DACC_CHDR_CH1; //disable DAC1
}
int state = 0;
const int STATE_OFF = 0;
const int STATE_IDLE = 1;
const int STATE_LISTEN_KEY = 2;
const int STATE_PLAYER = 3;
bool isLanguageKey(char customKey) {
return ('A' == customKey || 'B' == customKey || 'C' == customKey || 'D' == customKey);
}
void loop() {
switch (state) {
case STATE_OFF:
//listen for a telephone receiver to be removed
if (hookOffState == 1) {
Serial.print("HOOK OFF ");
Serial.println(hookOffState);
interruptState = 0;
state = STATE_IDLE;
}
else if (hookOffState == 0) {
Serial.print("HOOK ON ");
Serial.println(hookOffState);
}
break;
case STATE_IDLE:
//listen for a language key. Cannot dial a number before
Serial.print("interrupt IDLE ");
Serial.println(interruptState);
if (interruptState == 1) {
buttonBeep();
processLanguage();
state = STATE_LISTEN_KEY;
}
else if (hookOffState == 0){
state = STATE_OFF;
}
else {
playSound("intro.wav");
}
break;
case STATE_LISTEN_KEY:
//listen for any key
Serial.print("interrupt LISTEN KEY ");
Serial.println(interruptState);
if (isKeyPressed()) {
interruptState = 0;
if (isLanguageKey(key)) {
buttonBeep();
processLanguage();
}
else {
Serial.print("interruptStateF ");
Serial.println(interruptState);
buttonBeep();
keypresses[keyCounter] = key;
keyDial();
keyCounter++;
if (keyCounter > 4) {
state = STATE_PLAYER;
//when 5 numbers are pressed - try to open the .wav file
}
}
}
else if (hookOffState == 0){
state = STATE_OFF;
}
break;
case STATE_PLAYER:
//Play the audio and go back to state LISTEN
calculateAndPlay();
keyCounter = 0;
interruptState = 0;
state = STATE_LISTEN_KEY;
break;
default:
break;
}
}
void hookOffToggle(){
if (digitalRead(hookPinA) == 1) {
hookOffState = 1;
}
else {
hookOffState = 0;
}
}
void interruptToggle() {
interruptState = 1;
}
void kalba() {
Serial.println("Kalba? Language? Valoda? Yazik?");
}
bool isKeyPressed() {
key = myKeypad.getKey();
return key != NO_KEY;
}
bool langKeyPressed() {
key = myKeypad.getKey();
return key != NO_KEY && isLanguageKey(key);
}
void processLanguage() { //press A/B/C/D keys - select 1 out of 4 languages
//goIntoKeys = 1;
keyCounter = 0;
if (key == 'A') {
Serial.println(" LT ");
}
if (key == 'B') {
Serial.println(" EN ");
}
if (key == 'C') {
Serial.println(" LV ");
}
if (key == 'D') {
Serial.println(" RU ");
}
language = key;
}
void keyDial() { // LCD displays the number dialed in 3 slots.
keypresses[keyCounter] = 0x00;//null-byte
keypresses[keyCounter] = key;
if (key != NO_KEY) {
Serial.println(keypresses[keyCounter]);
}
}
void buttonBeep(){
for (int j = 0; j < 200; j++) {
for (int i = 0; i < 200; i++)
analogWrite(DAC0, i);
for (int i = 200; i >= 0; i--)
analogWrite(DAC0, i);
}
}
void backgroundHumm() {
for (int j = 0; j < 256; j++) {
for (int i = 0; i < 256; i++)
analogWrite(DAC0, j);
for (int j = 256; j >= 0; j--) {
for (int i = 256; i >= 0; i--)
analogWrite(DAC0, j);
}
}
}
void calculateAndPlay() {
//if we have 4+1 numbers - proceed
//the keys pressed are stored into chars I convert them to int then i did some multiplication to get the code as an int of xxxx
i1 = (keypresses[0] - 48) * 10000;
i2 = (keypresses[1] - 48) * 1000;
i3 = (keypresses[2] - 48) * 100;
i4 = (keypresses[3] - 48) * 10;
i5 = (keypresses[4] - 48) * 1;
tot = i1 + i2 + i3 + i4 + i5;
if (language == 'A') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiLT.wav");
}
else if (tot == code2)
{
playSound("zuvisLT.wav");
}
else if (tot == code3)
{
playSound("draugLT.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasLT.wav");
}
}
if (language == 'B') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiEN.wav");
}
else if (tot == code2)
{
playSound("zuvisEN.wav");
}
else if (tot == code3)
{
playSound("draugEN.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasEN.wav");
}
}
if (language == 'C') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiLV.wav");
}
else if (tot == code2)
{
playSound("zuvisLV.wav");
}
else if (tot == code3)
{
playSound("draugLV.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasLV.wav");
}
}
if (language == 'D') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiRU.wav");
}
else if (tot == code2)
{
playSound("zuvisRU.wav");
}
else if (tot == code3)
{
playSound("draugRU.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasRU.wav");
}
}
}
// Playing assigned filename
void playSound(const char* cName) {
File myFile = SD.open(cName);
const int S = 1024; // Number of samples to read in block
short buffer[S];
// until the file is not finished
Serial.println("playing ");
Serial.println(cName);
Audio.begin(44100, 200);
delay(200);
while (myFile.available()) {
myFile.read(buffer, sizeof(buffer));
// Prepare samples
int volume = 512;
//max volume 1024
Audio.prepare(buffer, S, volume);
Audio.write(buffer, S);
if ( interruptState ) break;
else if ( hookOffState == 0 ) break;
}
Audio.end();
myFile.close();
delay(50);
DACC->DACC_CHDR = DACC_CHDR_CH1; //disable DAC1
}
The schematics (if you can call it that) below:
EDIT: @Damago solution works! I just wanted to share here the solution for future searches. What you need to do is to get the 4th column of 4x4 keypad to work as an interrupt properly: Set all row pins as output and column pins as input with pullup.
for( int i=0; i< ROW_NUM; ++i) pinMode(pin_rows[i], OUTPUT);
for( int i=0; i< COLUMN_NUM; ++i) pinMode(pin_column[i], INPUT_PULLUP);
Set row pins to low:
for( int i=0; i< ROW_NUM; ++i) digitalWrite(pin_rows[i], LOW);
Attach the 4th column pin as interrupt:
attachInterrupt(digitalPinToInterrupt(pin_column[3]), interruptToggle, FALLING);
And of course, fix the syntax overall (it was a bit messy :) )
Full sketch below:
#include <DAC.h>
#include <SD.h>
#include <SPI.h>
#include <Audio.h>
#include <Keypad.h>
const byte ROW_NUM = 4;
const byte COLUMN_NUM = 4;
int code1 = 12345; //The code I used, you can change it
int code2 = 45678; //The code I used, you can change it
int code3 = 78900; //The code I used, you can change it
int tot, i1, i2, i3, i4, i5;
char c1, c2, c3, c4;
char hexaKeys[ROW_NUM][COLUMN_NUM] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte hookPinA = 23; // your interrupt pin
byte pin_rows[ROW_NUM] = {52, 50, 48, 46}; //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {44, 42, 40, 38}; //connect to the column pinouts of the keypad
Keypad myKeypad = Keypad(makeKeymap(hexaKeys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM);
char keypresses[5];
char language;
char key;
volatile uint8_t interruptState = 0;
volatile byte hookOffState = 0;
int keyCounter = 0;
void setup() {
// debug output at 9600 baud
Serial.begin(9600);
SD.begin(10);
analogWriteResolution(12);
for( int i=0; i< ROW_NUM; ++i) pinMode(pin_rows[i], OUTPUT);
for( int i=0; i< COLUMN_NUM; ++i) pinMode(pin_column[i], INPUT_PULLUP);
for( int i=0; i< ROW_NUM; ++i) digitalWrite(pin_rows[i], LOW);
pinMode(hookPinA, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(hookPinA), hookOffToggle, CHANGE);
attachInterrupt(digitalPinToInterrupt(pin_column[3]), interruptToggle, FALLING);
DACC->DACC_CHDR = DACC_CHDR_CH1; //disable DAC1
}
int state = 0;
const int STATE_OFF = 0;
const int STATE_IDLE = 1;
const int STATE_LISTEN_KEY = 2;
const int STATE_PLAYER = 3;
bool isLanguageKey(char customKey) {
return ('A' == customKey || 'B' == customKey || 'C' == customKey || 'D' == customKey);
}
void loop() {
switch (state) {
case STATE_OFF:
//listen for a telephone receiver to be removed
if (hookOffState == 1) {
interruptState = 0;
state = STATE_IDLE;
}
else if (hookOffState == 0) {
}
break;
case STATE_IDLE:
//listen for a language key. Cannot dial a number before
if (interruptState == 1) {
isKeyPressed(); //get the key input
buttonBeep();
processLanguage();
state = STATE_LISTEN_KEY;
}
else if (hookOffState == 0){
state = STATE_OFF;
}
else {
playSound("intro.wav");
}
break;
case STATE_LISTEN_KEY:
//listen for any key
if (isKeyPressed()) {
interruptState = 0;
if (isLanguageKey(key)) {
buttonBeep();
processLanguage();
}
else {
buttonBeep();
keypresses[keyCounter] = key;
keyCounter++;
if (keyCounter > 4) {
state = STATE_PLAYER;
//when 5 numbers are pressed - try to open the .wav file
}
}
}
else if (hookOffState == 0){
state = STATE_OFF;
}
break;
case STATE_PLAYER:
//Play the audio and go back to state LISTEN
calculateAndPlay();
keyCounter = 0;
interruptState = 0;
state = STATE_LISTEN_KEY;
break;
default:
break;
}
}
void hookOffToggle() { //detect a telephone receiver to be removed
hookOffState = digitalRead(hookPinA);
}
void interruptToggle() {
interruptState = 1;
}
bool isKeyPressed() {
key = myKeypad.getKey();
return key != NO_KEY;
}
bool langKeyPressed() {
key = myKeypad.getKey();
return key != NO_KEY && isLanguageKey(key);
}
void processLanguage() { //press A/B/C/D keys - select 1 out of 4 languages
keyCounter = 0;
if (key == 'A') {
Serial.println(" LT ");
}
if (key == 'B') {
Serial.println(" EN ");
}
if (key == 'C') {
Serial.println(" LV ");
}
if (key == 'D') {
Serial.println(" RU ");
}
language = key;
}
void buttonBeep(){
for (int j = 0; j < 200; j++) {
for (int i = 0; i < 200; i++)
analogWrite(DAC0, i);
for (int i = 200; i >= 0; i--)
analogWrite(DAC0, i);
}
}
void backgroundHumm() {
for (int j = 0; j < 256; j++) {
for (int i = 0; i < 256; i++)
analogWrite(DAC0, j);
for (int j = 256; j >= 0; j--) {
for (int i = 256; i >= 0; i--)
analogWrite(DAC0, j);
}
}
}
void calculateAndPlay() {
//if we have 4+1 numbers - proceed
//the keys pressed are stored into chars I convert them to int then i did some multiplication to get the code as an int of xxxx
i1 = (keypresses[0] - 48) * 10000;
i2 = (keypresses[1] - 48) * 1000;
i3 = (keypresses[2] - 48) * 100;
i4 = (keypresses[3] - 48) * 10;
i5 = (keypresses[4] - 48) * 1;
tot = i1 + i2 + i3 + i4 + i5;
if (language == 'A') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiLT.wav");
}
else if (tot == code2)
{
playSound("zuvisLT.wav");
}
else if (tot == code3)
{
playSound("draugLT.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasLT.wav");
}
}
if (language == 'B') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiEN.wav");
}
else if (tot == code2)
{
playSound("zuvisEN.wav");
}
else if (tot == code3)
{
playSound("draugEN.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasEN.wav");
}
}
if (language == 'C') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiLV.wav");
}
else if (tot == code2)
{
playSound("zuvisLV.wav");
}
else if (tot == code3)
{
playSound("draugLV.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasLV.wav");
}
}
if (language == 'D') {
if (tot == code1) //if the code is correct you trigger to play .wav
{
playSound("ledaiRU.wav");
}
else if (tot == code2)
{
playSound("zuvisRU.wav");
}
else if (tot == code3)
{
playSound("draugRU.wav");
}
else //if the code is wrong you get a beep and audio message
{
playSound("blogasRU.wav");
}
}
}
// Playing assigned filename
void playSound(const char* cName) {
File myFile = SD.open(cName);
const int S = 1024; // Number of samples to read in block
short buffer[S];
// until the file is not finished
Serial.println("playing ");
Serial.println(cName);
Audio.begin(44100, 200);
delay(200);
while (myFile.available()) {
myFile.read(buffer, sizeof(buffer));
// Prepare samples
int volume = 512;
//max volume 1024
Audio.prepare(buffer, S, volume);
Audio.write(buffer, S);
if ( interruptState ) break;
else if ( hookOffState == 0 ) break;
}
Audio.end();
myFile.close();
delay(50);
DACC->DACC_CHDR = DACC_CHDR_CH1; //disable DAC1
}