正如 mclopez 所指出的,最好提供一个好的答案,而不是只指出其他人的缺陷是什么,所以……我们开始吧。
在我看来,ISR 解决方案不是一个好的选择,因为 ISR 会阻止正常执行。使用中断唯一可行的实现是记录引脚变化,然后发送短信。
但是,在我看来,这不是一个好的解决方案。对于这个问题,我会使用状态机发送短信;因为你有状态,你可以在做其他事情的时候等待转换,比如检查按钮。
我不知道 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。
此代码中可能存在小错误,因为我尚未对其进行测试,但它应该可以满足您的需求