写延迟计时器()

时间:2015-04-18 11:55:27

标签: c timer arduino delay

如果输入为HIGH,我写了这段代码来发送短信,你可以在其中看到,但问题是我有4个输入和延迟()是致命的,如果我需要做多个单一的话就非常错误一次一件事(我使用4个输入)。

所以我需要在void loop(),Send_SMS()和initia()中用millis()或其他东西来改变delay()。

有人可以帮助我,并提前感谢你。

const int DI = 2;
const int DT = 3;
const int DGP1 = 4;
const int DGP2 = 5;

int value1_old = 0;
int value2_old = 0;
int value3_old = 0;
int value4_old = 0;

unsigned long previousMillis = 0;
unsigned long interval=100;

#include<SoftwareSerial.h>
SoftwareSerial SIM900 (7, 8);

void setup() {
 pinMode(DI, INPUT);
 pinMode(DT, INPUT);
 pinMode(DGP1, INPUT);
 pinMode(DGP2, INPUT);

 SIM900.begin(19200);
 SIM900power();
 delay(20000);  

}

void SIM900power(){
  digitalWrite(9 ,HIGH);
  delay(1000);
  digitalWrite(9 ,LOW);
  delay(5000);
}

void initia(){
  SIM900.print("AT+CMGF=1\r");
  delay(100);
  SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
  delay(100);  
}

void Send_SMS(){
  SIM900.println((char)26);
  delay(100);
  SIM900.println();
  delay(100);
  SIM900power();
}

void loop() {
  int value1 = digitalRead (DI);
  int value2 = digitalRead (DT);
  int value3 = digitalRead (DGP1);
  int value4 = digitalRead (DGP2);

  if (value2 != value2_old && value2 == HIGH) {
    initia();
    SIM900.println("Station 85: Defaut electrique");
    delay(100);  
    Send_SMS();
    value2_old = value2;
  }

  if (value3 != value3_old && value3 == HIGH)  
   {
   initia();
   SIM900.println("Station 85: DefautGP1");
   delay(100);
   Send_SMS();
   value3_old = value3;
 }

if (value4 != value4_old && value4 == HIGH)  
{
  initia();
  SIM900.println("Station 85:DD>1000");    
  delay(100);
  Send_SMS();
  value4_old = value4;
 }
value2_old = value2;
value3_old = value3;
value4_old = value4;

}

5 个答案:

答案 0 :(得分:0)

您可以尝试使用isr_timer()函数中的代码:

if (changed2) {
    initia();
    SIM900.println("Station 85: Defaut electrique");
    delay(100);
    Send_SMS();
    changed2 = false;
}

祝你好运

答案 1 :(得分:0)

正如mclopez指出的那样,提供一个好的答案更好,而不是只指出其他的缺点,所以......我们走了。

在我看来,ISR解决方案不是一个好的选择,因为ISR会阻止正常执行。使用中断的唯一可行实现是记录引脚更改,然后发送SMS。

然而,在我看来,这不是一个好的解决方案。对于这个问题,我要使用状态机发送短信;由于你有状态,你可以在做其他事情时等待过渡,比如检查按钮。

我不知道SIM900如何发送短信,因此我将您的工作流程在状态机中实施。我不确定这是最佳解决方案,特别是因为我不认为您每次都需要重新启动模块,但您可以稍后修改它。

现在,工作流程必须执行七个操作,每个操作后面都有一个等待。我在这里写它,所以看到每个动作都比较简单:

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);

所以我们有8个状态:一个空闲状态(当你等待状态机启动时,命名为SIM_IDLE),然后是五个&#34; SEND&#34;状态(我将它们命名为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;
}

看起来很复杂,但确实非常简单。循环由三个&#34;块&#34;。

组成

第一个是按钮检查。如果按下任何按钮,则会设置相应的valueX_changed标志。这是一个非常简单的部分,只需检查是否有任何按钮具有不同的状态,然后设置标志。

第二部分是检查状态转换。在此switch语句中,程序确定是否需要更改状态机的状态。如果状态为空闲时按下按钮,或者如果在发送SMS的过程中已经过了指定的时间,则会发生这种情况。

第三部分是状态变化时要执行的操作。因此,如果状态发生变化,请执行状态操作,这对于空闲状态没有任何作用,为SIM_SENDx状态发送一些内容并更改SIM_POWx状态的引脚。

只需注意:在设置中,您在正常工作流程中添加了20秒延迟而不是预先发送。如果您要删除此功能,只需从执行重置的设置中删除四行,然后在第一个开关中修改default个案例即可设置newSimState = SIM_POW1;而不是SIM_IDLE

此代码中可能存在小错误,因为我还没有对其进行测试,但它应该按照您的需要进行操作

答案 2 :(得分:0)

使用计时器库https://playground.arduino.cc/Code/Timer/。正如他们所说:

  

delay方法的缺点是其他任何事情都无法进行   delay发生时。您无法更新显示或检查   例如按键。

因此,您可以使用:

代替delay
 t.every(1000, doStuff);

要在触发功能的同时离开循环进行业务。

希望有帮助。

答案 3 :(得分:0)

不完全是原始问题的答案... 但是对于那些正在寻找不使用 delay() 来打印秒的简单解决方案的人来说:

if(millis() % 1000 == 0) {
   Serial.println(millis());
}

很简单,不是吗?

答案 4 :(得分:-1)

当值溢出时,函数millis()将失败。正如@CPU_Terminator所说,使用中断。有一些有用的Arduino库,例如Timer1

修改即可。假设您想要做的是每100分钟发送一条短信,如果您的某些输入发生了变化,您可以使用这样的代码(我删除了一些对我来说似乎不太必要的延迟,如果我和#39再次添加它们;我错了):

#include <SoftwareSerial.h>
#include "TimerOne.h"

const int DI = 2;
const int DT = 3;
const int DGP1 = 4;
const int DGP2 = 5;
const long interval = 100000; // in microseconds

int value1 = 0;
int value2 = 0;
int value3 = 0;
int value4 = 0;
int value1_old = 0;
int value2_old = 0;
int value3_old = 0;
int value4_old = 0;
boolean changed1 = false;
boolean changed2 = false;
boolean changed3 = false;
boolean changed4 = false;

SoftwareSerial SIM900 (7, 8);

void SIM900power(){
  digitalWrite(9, HIGH);
  delay(1000);
  digitalWrite(9, LOW);
  delay(5000);
}

void initia(){
  SIM900.print("AT+CMGF=1\r");
  SIM900.println("AT + CMGS = \"+212xxxxxxx\"");
}

void Send_SMS(){
  SIM900.println((char)26);
  SIM900.println();
  delay(20);
  SIM900power();
}

void isr_timer(){
  if (changed2) {
    initia();
    SIM900.println("Station 85: Defaut electrique");
    Send_SMS();
    changed2 = false;
  }

  if (changed3) {
    initia();
    SIM900.println("Station 85: DefautGP1");
    Send_SMS();
    changed3 = false;
  }

  if (changed4) {
    initia();
    SIM900.println("Station 85:DD>1000");
    Send_SMS();
    changed4 = false;
  }
}

void setup() {
  pinMode(DI, INPUT);
  pinMode(DT, INPUT);
  pinMode(DGP1, INPUT);
  pinMode(DGP2, INPUT);

  SIM900.begin(19200);
  SIM900power();
  delay(20000);
  Timer1.initialize(interval);
  Timer1.attachInterrupt(isr_timer);
}

void loop() {
  value1 = digitalRead (DI);
  value2 = digitalRead (DT);
  value3 = digitalRead (DGP1);
  value4 = digitalRead (DGP2);

  if (value1 != value1_old && value1 == HIGH) changed1 = true;
  if (value2 != value2_old && value2 == HIGH) changed2 = true;
  if (value3 != value3_old && value3 == HIGH) changed3 = true;
  if (value4 != value4_old && value4 == HIGH) changed4 = true;

  value1_old = value1;
  value2_old = value2;
  value3_old = value3;
  value4_old = value4;

  // Here the rest of your code
}

这样,函数isr_timer()将每0.1秒执行一次。