Hi everybody. I've been working on a project and I desperatly need some help regarding an issue i can't overcome.
First thing to mention is that I have a timer running in the background wich triggers an ISR every 1 second. In this ISR I only decrease the time of a countdown I have running.
I am also using a library to interface a Keypad I have connected. when I need to read a key from the keypad I use a function called kpd.getKey(). This function enters a loop which waits untill a key is pressed. The function is written in cpp and I have difficulty in understanding what is happening inside.
Untimatly what I would like to do is to check if the countdown has reached 0 seconds in the ISR and if so exit to another subroutine.
I have tried to do that by calling th function at the end of the ISR but that doesn't seam to work.
Thanks in advance to everyone for any sugestion.
Guessing at what code you've written isn't the way to do things. Post your code using code tags and we'll go from there.
An ISR always returns to the point in the code from which it was called. Any other behaviour would turn your program into a bowl of spaghetti.
You can arrange for the ISR to set a flag variable (for example readKeypad = true;) and for your other code to check for that variable and only act if it is true.
...R
You cannot force an ISR to exit anywhere, it can only return to where the program was interrupted.
Any checking should be done each time round the loop that's waiting, and any variables used
to communicate between the ISR and the main program should be volatile.
Thanks for the sugestions. I hadn't put any code because it was very long however I made a simple version to try and explain the problem.
#include <MultitapKeypad.h>
#include <Wire.h>
MultitapKeypad kpd( ROW0, ROW1, ROW2, ROW3, COL0, COL1, COL2, COL3 );
Key key;
int timer_s = 100; // start countdown with 100 seconds
int main_switch = 13; // button to enter code
int main_switch_state = 0; // state on the button
void setup() {
pinMode(main_switch, INPUT);
Timer1.initialize(1000000); // set a timer of length 1000000 microseconds/ 1 sec
Timer1.attachInterrupt( timerIsr );
}
void loop() {
main_switch_state = digitalRead(main_switch);
if (main_switch_state == 0) {
key = kpd.getKey();
// check key and continue
}
}
void timerIsr() {
timer_s -= 1; // decrease countdown by 1 second every time
if (timer_s <= 0) {
Time_out();
}
}
void Time_out() {
// Print on lcd the time is over and spin in an infinite loop
}
When i call the kpd.getKey() function I basicaly have no controll of what hapends and even if i set a flag I can not check it as the program is running in a loop inside the function (part of a libray).
From what I understand I have the folowing options:
- Try to understand the library code and modify it to check a flag. ( would try to avoid if possible as I have tried and ned no succes.
- Try to make my own get.key() function so I have full controll over the code. ( could manage to do that if it was the only option)
- other options????
You need a library that has a non-blocking call. Blocking calls are pretty much pointless for a microcontroller library. If you can write the equivalent of Serial libraries available() method for your keypad you can guard
all the calls to getKey() to avoid blocking.
I tried to emulate your case in my own setup using MEGA and 4x4 keypad under Keypad.h Library. I can concurrently enter codes from the keypad and also can observe time out event. The 1-sec time-tick interrupt has been generated using register level instructions as I have no access to Timer1 Library. The codes may be helpful for you.
#include <Keypad.h>
#include<LiquidCrystal.h>
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);
const byte ROWS = 4; //four rows
const byte COLS = 4;//3; //three columns
char keys[ROWS][COLS] = {
{'1', '2', '3', 'a'},
{'4', '5', '6', 'b'},
{'7', '8', '9', 'c'},
{'*', '0', '#', 'd'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};//connect to the row pin outs of the keypad
byte colPins[COLS] = {5, 4, 3, 2};//connect to the column pin outs of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
volatile int timer_s = 10; // start countdown with 10 seconds
int main_switch = 13; // button to enter code
int main_switch_state = 0; // state on the button
int curSorTracker=0;
void setup()
{
Serial.begin(9600);
lcd.begin(20, 4);
lcd.setCursor(0, 0);
pinMode(main_switch, INPUT_PULLUP);
TCCR1A = 0x00;
TCCR1B = 0x00;
TCNT1 = 0xC2F7; //pre-set value for 1-sec time delay
bitSet(TIMSK1, 0); //local interrupt enable bit
sei(); //global interrupt enable bit
TCCR1B = 0x05; //TC1 is running at clkTC1 = clkSYS/1024 = 15625 Hz
}
void loop()
{
main_switch_state = digitalRead(main_switch);
if (main_switch_state == 0)
{
char ch = keypad.getKey();
if(ch !=0)
{
lcd.write(ch);
curSorTracker++;
}
}
}
ISR(TIMER1_OVF_vect)
{
TCNT1 = 0xC2F7;
timer_s -= 1; // decrease countdown by 1 second every time
if (timer_s <= 0)
{
Time_out();
}
}
void Time_out()
{
lcd.setCursor(0, 1);
lcd.print("Time Out!");
while(1);
// Print on lcd the time is over and spin in an infinite loop
}
Are you using this library?
If so, use the ‘attachFunction()’ method to attach a callback function. Your callback will be called on every loop in ‘getKey()’ while it’s waiting. If you need to bail out, your callback should set ‘MultitapKeypad::isCanceled = true’.
gfvalvo:
Are you using this library?
GitHub - ZulNs/MultitapKeypad: Arduino Library which allows to interface with matrix 4 x 3 phone's keypad as well as 4 x 4.If so, use the ‘attachFunction()’ method to attach a callback function. Your callback will be called on every loop in ‘getKey()’ while it’s waiting. If you need to bail out, your callback should set ‘MultitapKeypad::isCanceled = true’.
You are a legend. Thank so much for the help. It worked perfectly. Savede so much time and work