Как mclopez отметил, что лучше, чтобы обеспечить хороший ответ, а не указывая только то, что есть недостатки из других, так что ... Вот и мы.
По моему мнению, решение ISR не является хорошим выбором, поскольку ISR блокируют нормальное выполнение. Единственной выполнимой реализацией с использованием прерываний является запись изменения смены, а затем отправка SMS-сообщений.
Это, на мой взгляд, не является хорошим решением. Для этой проблемы я бы пошел с автоматом для отправки SMS-сообщений; поскольку у вас есть состояния, вы можете ждать перехода, выполняя другие действия, например, проверять кнопки.
Я не знаю, как SIM900 отправляет SMS, поэтому я принимаю ваш рабочий процесс и реализую его на конечной машине. Я не уверен, что это оптимальное решение, особенно потому, что я не думаю, что вам действительно нужно перезагружать модуль каждый раз, но вы можете обрезать его позже.
Теперь рабочий процесс содержит семь действий, которые вы должны выполнить, каждый из которых следует ожиданию. Я пишу это здесь, так что это проще, чтобы увидеть все действия:
SIM900.print("AT+CMGF=1\r");
delay(100);
SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
delay(100);
SIM900.println("Message you want");
delay(100);
SIM900.println((char)26);
delay(100);
SIM900.println();
delay(100);
digitalWrite(9 ,HIGH);
delay(1000);
digitalWrite(9 ,LOW);
delay(5000);
Таким образом, мы имеем восемь состояний: незанятый (когда вы ждете государственной машины, чтобы начать, по имени SIM_IDLE), а затем пять «SEND» (я называю их SIM_SEND1..5) и двумя состояниями для сброса мощности (с именем SIM_POW1 и SIM_POW2). Обычно вы находитесь в режиме ожидания; когда нажата одна или несколько кнопок, вы переключаетесь на первую отправку, проезжаете через них, а затем перезагружаете питание и возвращаетесь в режим ожидания.
Нажатая кнопка изменяет только состояние SIM_SEND3 (когда вы действительно отправляете сообщение), поэтому всякий раз, когда нажимается кнопка, устанавливается логическая переменная (нажатие кнопки обнаруживается также во время выполнения конечного автомата) и сбрасывается только в это состояние после отправки правильного сообщения.
Теперь, вот код, который реализует этот:
const uint8_t DI = 2;
const uint8_t DT = 3;
const uint8_t DGP1 = 4;
const uint8_t DGP2 = 5;
const uint8_t SIMPOW = 9;
uint8_t value1_old = 0;
uint8_t value2_old = 0;
uint8_t value3_old = 0;
uint8_t value4_old = 0;
boolean value1_changed = false;
boolean value2_changed = false;
boolean value3_changed = false;
boolean value4_changed = false;
/********************************/
// SIM STATES
#define SIM_IDLE 0
//SEND1: SIM900.print("AT+CMGF=1\r");delay(100);
#define SIM_SEND1 1
//SEND2: SIM900.println("AT + CMGS = \"+212xxxxxxx\"");delay(100);
#define SIM_SEND2 2
//SEND3: SIM900.println("Message you want");delay(100);
#define SIM_SEND3 3
//SEND4: SIM900.println((char)26);delay(100);
#define SIM_SEND4 4
//SEND5: SIM900.println();delay(100);
#define SIM_SEND5 5
//POW1: digitalWrite(SIMPOW,HIGH);delay(1000);
#define SIM_POW1 6
//POW2: digitalWrite(SIMPOW,LOW);delay(5000);
#define SIM_POW2 7
/********************************/
unsigned long previousMillis;
uint8_t currentSimState;
#include<SoftwareSerial.h>
SoftwareSerial SIM900 (7, 8);
void setup()
{
pinMode(DI, INPUT);
pinMode(DT, INPUT);
pinMode(DGP1, INPUT);
pinMode(DGP2, INPUT);
pinMode(SIMPOW, OUTPUT);
SIM900.begin(19200);
digitalWrite(SIMPOW,HIGH);
delay(1000);
digitalWrite(SIMPOW,LOW);
delay(25000);
currentSimState = -1; // Force a state transition
}
void loop()
{
uint8_t value1 = digitalRead (DI);
uint8_t value2 = digitalRead (DT);
uint8_t value3 = digitalRead (DGP1);
uint8_t value4 = digitalRead (DGP2);
unsigned long currentMillis = millis();
if (value2 != value2_old && value2 == HIGH)
value2_changed = true;
if (value3 != value3_old && value3 == HIGH)
value3_changed = true;
if (value4 != value4_old && value4 == HIGH)
value4_changed = true;
value1_old = value1;
value2_old = value2;
value3_old = value3;
value4_old = value4;
// Check if a state transition is needed
uint8_t newSimState = currentSimState;
switch (currentSimState)
{
case SIM_IDLE: // Start sending if a value changed
if ((value2_changed) || (value3_changed) || (value4_changed))
newSimState = SIM_SEND1;
break;
case SIM_SEND1: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND2;
break;
case SIM_SEND2: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND3;
break;
case SIM_SEND3: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND4;
break;
case SIM_SEND4: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_SEND5;
break;
case SIM_SEND5: // Wait 100 ms
if ((currentMillis - previousMillis) >= 100)
newSimState = SIM_POW1;
break;
case SIM_POW1: // Wait 1000 ms
if ((currentMillis - previousMillis) >= 1000)
newSimState = SIM_POW2;
break;
case SIM_POW2: // Wait 1000 ms
if ((currentMillis - previousMillis) >= 1000)
newSimState = SIM_IDLE;
break;
default:
newSimState = SIM_IDLE;
break;
}
// If there was a transition, do the appropriate action
if (newSimState != currentSimState)
{
case SIM_IDLE:
// Do nothing
break;
case SIM_SEND1:
SIM900.print("AT+CMGF=1\r");
previousMillis = millis();
break;
case SIM_SEND2:
SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
previousMillis = millis();
break;
case SIM_SEND3:
if (value2_changed)
{
SIM900.println("Station 85: Defaut electrique");
value2_changed = false;
}
else if (value3_changed)
{
SIM900.println("Station 85: DefautGP1");
value2_changed = false;
}
else if (value4_changed)
{
SIM900.println("Station 85:DD>1000");
value2_changed = false;
}
else
{
// Should never arrive here. Just in case, you
// can either abort the SMS sending if you can
// or send another message
}
previousMillis = millis();
break;
case SIM_SEND4:
SIM900.println((char)26);
previousMillis = millis();
break;
case SIM_SEND5:
SIM900.println();
previousMillis = millis();
break;
case SIM_POW1:
digitalWrite(SIMPOW,HIGH);
previousMillis = millis();
break;
case SIM_POW2:
digitalWrite(SIMPOW,LOW);
previousMillis = millis();
break;
}
}
// Advance state
currentSimState = newSimState;
}
Это может показаться сложным, но это действительно очень просто. Цикл выполнен тремя «блоками».
Первый - проверка кнопки. Если какая-либо кнопка нажата, устанавливается соответствующий флаг valueX_changed
. Это очень тривиальная часть, просто проверьте, имеет ли какая-либо кнопка другое состояние, а затем установите флаг.
Вторая часть - это проверка перехода государства. В этом операторе switch программа определяет, нужно ли изменять состояние конечного автомата. Это происходит, когда кнопка была нажата, если состояние неактивное, или если указанное количество времени прошло, если в процессе отправки SMS.
Третья часть - действие, которое должно выполняться при изменении состояния. Поэтому, если состояние изменилось, выполните действие состояния, что ничего не значит для состояния ожидания, отправьте что-то для состояний SIM_SENDx и измените контакт для состояний SIM_POWx.
Просто примечание: в настройке вы добавили задержку в 20 секунд, не присутствующую в обычном рабочем процессе. Если вы хотите удалить это, вы можете просто удалить четыре строки из настройки, выполняющей сброс, и изменить корпус default
в первом коммутаторе, чтобы установить newSimState = SIM_POW1;
вместо SIM_IDLE
.
Там могут быть небольшие ошибки в этом коде, так как я не проверял, но он должен делать то, что вы хотели
ли вы сказать, что с помощью задержки вы тратите циклов ожидания на вещи, а не делать больше других потенциальных (время критических) задач? Если это так, я думаю, вам нужно посмотреть на использование прерываний (для выполнения критически важной задачи в ISR) или использования аппаратного таймера, присутствующего на самом AVR. – initramfs
Вместо этого используйте функцию millis(). Пример учебника [здесь] (http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay). –
Я думаю, что мне нужно использовать millis() вместо задержки, но я не знаю, как, потому что я новичок:/ –