I am still struggling to get this sketch functional. The problem seems to lie with the interrupts, and relying on them to turn on and off the PIRtrigger when needed. Everything else seems to be OK. This is a slightly modified sketch from what I had uploaded earlier, with some changes that I thought would fix the problem. In general, a "correct" PIN disables the alarm from firing as it sets the "away" flag to "false", which works. An "incorrect" PIN sets "away" to "true" which, when a trigger is activated via an Interrupt, sounds the alarm. The program should then go to readKeypad for further function, which it appears to do. The following shows the result after an incorrect PIN:
Key_input[0] = #
@ checkPIN
@ incorrect PIN
away=1 PIRtrigger=0
at Alarm
after alarm
The trigger then doesn't seem to get activated. Can anyone HELP!? Thanks.
///////////////////////// initialize & includes //////////////////////////
#include "SIM900.h"
#include "sms.h"
#include "Keypad.h"
#include <GSM.h>
SMSGSM sms;
//To change pins for Software Serial, use the two lines in GSM.cpp.
int PIR_SensorPin = 2;
int LED_OutPin = 11; //green
int Alarm_OutPin = 12; //red
int alarm_count;
volatile boolean PIRtrigger = false;
boolean away = false;
const byte interruptPin = 2;
int z = 0;
int i = 0;
int timeout = 10000;
unsigned long time = millis();
//////////////////////////// setup keyPad //////////////////////////
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] =
{
{
'1', '2', '3', 'A'
}
,
{
'4', '5', '6', 'B'
}
,
{
'7', '8', '9', 'C'
}
,
{
'*', '0', '#', 'D'
}
};
byte rowPins[ROWS] = {
6, 7, A2, A3 // row pin# on keypad to Arduino pin#, ie Row Pin #1 goes to Arduino Pin #6, etc.
}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {
3, A0, A1, A4
}; // connect to the column pinouts of the keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS );
const char PIN[5] = {
'9', '6', '7', '9', '#'
}; // PIN number
char key_input[5] = {
0, 0, 0, 0, 0
}; // used for comparison
//////////////////////////////// setup ///////////////////////////////////
void setup() {
Serial.begin (9600); // Establish Serial connection;
pinMode (LED_OutPin, OUTPUT); // Set pinMode.
pinMode (Alarm_OutPin, OUTPUT); // Set pinMode.
pinMode (PIR_SensorPin, INPUT); // Set pinMode.
digitalWrite (LED_OutPin, LOW); // Set output pins to LOW for start.
digitalWrite (Alarm_OutPin, LOW); // Set output pins to LOW for start.
digitalWrite (PIR_SensorPin, LOW);
Serial.println ("Studio Alarm starting up."); // Serial message that GSM shield is starting up
if (gsm.begin(4800)) { // Set GSM shield to recommended 4800 baud rate.
Serial.println ("Status = Network READY");
digitalWrite (LED_OutPin, HIGH);
}
attachInterrupt (digitalPinToInterrupt (2), trigger, HIGH); // PIR as interrupt
Serial.println ("System Ready");
}
//////////////////////////////// void loop ///////////////////////////////////
void loop()
{
interrupts();
readKeypad(); Serial.println ("at keypad");
alarm();
}
////////////////////////// void trigger ///////////////////////////////////
void trigger() {
PIRtrigger = true;
// alarm();
}
///////////////////////////// void alarm ///////////////////////////////////
void alarm() {
// PIRtrigger = false;
time = millis(); // reset time.
interrupts();
Serial.print ("away="); Serial.print (away); Serial.print (" "); Serial.print ("PIRtrigger="); Serial.println (PIRtrigger);
Serial.println ("at Alarm");
if (away == true && PIRtrigger == true) {
// (sms.SendSMS("**********", "***Motion Detected in Studio!***"));
Serial.println ("MOTION detected: SMS Sent");
for (alarm_count = 0; alarm_count <= 5; alarm_count++) { // Cycle outputs if triggered
digitalWrite (Alarm_OutPin, HIGH); delay (1000); // On/Off/On/Off/Off
digitalWrite (Alarm_OutPin, LOW); delay (500);
digitalWrite (LED_OutPin, HIGH); // delay (1000);
Serial.println (alarm_count);
}
}
PIRtrigger = false;
// away = false;
Serial.println ("after alarm");
Serial.print ("away="); Serial.print (away); Serial.print (" "); Serial.print ("PIRtrigger="); Serial.println (PIRtrigger);
noInterrupts(); /////////////////////////////////
readKeypad();
}
///////////////////////////// read Keypad ///////////////////////////////////
void readKeypad() {
char key = keypad.getKey();
if (key != NO_KEY) { // if a keypad input
key_input[z] = key;
tone(10, 900, 100);
Serial.print ("Key_input["); Serial.print(z); Serial.print ("] = "); Serial.println(key);
z++;
if (z >= sizeof(key_input)) {
z = 0;
}
switch (key) {
case '*': // resets key_inputs to "0"
z = 0;
break;
case '#': // pressed to "enter"
z = 0;
for ( i = 0; i < 4 ; i++ ) {
// Serial.print(key_input[i]);
}
// Serial.println ("-------");
delay(100); // for extra de-bounce
checkPIN();
break;
}
}
}
///////////////////////////// check PIN ///////////////////////////////////
void checkPIN() {
Serial.println ("@ checkPIN ");
int correct = 0;
int i;
for ( i = 0; i < (sizeof(PIN) - 1) ; i++ ) {
if (key_input[i] == PIN[i]) {
correct++;
}
}
if (correct >= sizeof(PIN) - 1) {
// Serial.print ("# correct = "); Serial.println (correct); Serial.println (sizeof(PIN) - 1);
correctPIN();// go to correct PIN instructions
}
else {
incorrectPIN(); // go to incorrect PIN instructions
}
}
///////////////////////////// correct PIN ///////////////////////////////////
void correctPIN() { // do this if correct PIN entered
Serial.println ("@ correct PIN ");
// digitalWrite (LED_OutPin, HIGH);
digitalWrite (LED_OutPin, LOW); // on-board LED to show the status of alarm
PIRtrigger = false; // turn the PIR state to off
away = false; // turn the away state to off
noInterrupts();
readKeypad();
}
///////////////////////// incorrect PIN ///////////////////////////////////
void incorrectPIN() { // do this if incorrect PIN entered
// noInterrupts(); // Serial.println ("interrupt off 1");
Serial.println ("@ incorrect PIN ");
away = true;
digitalWrite (LED_OutPin, HIGH); // tied to Alarm output level
//Has time passed? delay(timeout) - allow time to leave premises
PIRtrigger = false;
alarm();
}
2 Answers 2
First, as AH L said, there is no HIGH interrupt on a Uno. Looking at Arduino.h we see:
#define HIGH 0x1
#define LOW 0x0
...
#define CHANGE 1
#define FALLING 2
#define RISING 3
Thus your HIGH interrupt (which doesn't exist) is really a CHANGE interrupt.
Next, you seem to be recursively calling stuff.
loop
callsreadKeypad
.readKeypad
callscheckPIN
checkPIN
callscorrectPIN
correctPIN
callsreadKeypad
So this code is digging itself deeper and deeper into function calls. It will eventually run out of stack.
i.e.
readKeypad -> checkPIN -> correctPIN -> readKeypad -> checkPIN ...
You need to restructure.
Also see my page about state machines.
-
I know that it is ugly code; from repeatedly making changes/additions to try to get it to work. I have cleaned up some and will continue on others. Thanks for your feedback. I wasn't thinking about a stack issue.nkuck– nkuck2017年03月13日 10:47:49 +00:00Commented Mar 13, 2017 at 10:47
-
How do I better manage the stack?nkuck– nkuck2017年03月13日 11:36:05 +00:00Commented Mar 13, 2017 at 11:36
-
Don't do recursive calls. For example don't have
a
callb
and insideb
calla
. Read the link I gave about state machines.2017年03月13日 23:06:16 +00:00Commented Mar 13, 2017 at 23:06 -
Thanks. I plan to try state machines in the very near future.nkuck– nkuck2017年03月13日 23:08:18 +00:00Commented Mar 13, 2017 at 23:08
Most Arduinos don't support interrupting when a pin is HIGH. Try changing attachInterrupt (digitalPinToInterrupt (2), trigger, HIGH)
to attachInterrupt (digitalPinToInterrupt (2), trigger, RISING)
.
-
Thanks. I had tried CHANGE and HIGH with same results. I will try RISING to see what happens.nkuck– nkuck2017年03月13日 10:40:01 +00:00Commented Mar 13, 2017 at 10:40