Non-Delay Recording Timer ()

I wrote this code to send SMS if the input is HIGH, as you can see in it, but the problem is that I have 4 inputs, and delay() fatal and very wrong if I need to do more than one thing at a time (I use 4 entrances).

So I need to change delay() to millis() or something else in void loop() , Send_SMS() and initia() .

Can anyone help me and thanks in advance.

 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; } 
+7
source share
4 answers

As mclopez noted, itโ€™s better to give a good answer, and not just point out what are the disadvantages of others, so ... Here we go.

In my opinion, the ISR solution is not a good choice as ISRs block normal execution. The only possible implementation using interrupts is to record the change of the shift, and then send SMS messages.

This, however, is not a very good solution, in my opinion. For this problem, I would go with a machine to send SMS messages; since you have states, you can wait for the transition by doing other things, like checking buttons.

I do not know how the SIM900 sends SMS, so I take your workflow and implement it on the final machine. I'm not sure if this is the best solution, especially because I don't think you really need to reload the module every time, but you can trim it later.

Now the workflow contains seven actions that you must complete, each of which follows the wait. I write this here, so itโ€™s easier to see every action:

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

So, we have eight states: inactive (when you expect a state machine to start called SIM_IDLE), followed by five "SEND" states (I call them SIM_SEND1..5) and two states to reset power (called SIM_POW1 and SIM_POW2) . Usually you are in standby mode; when one or more buttons are pressed, you switch to the first sending, drive through them, and then reset the power and return to standby mode.

A pressed button only changes the state of SIM_SEND3 (when you really send a message), so whenever a button is pressed, a logical variable is set (the button is pressed also during execution of the state machine) and only reset in this state after sending the correct message.

Now here is the code that implements this:

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

It may seem complicated, but it is really very simple. The cycle is made in three โ€œblocksโ€.

The first is a button check. If any button is pressed, the corresponding valueX_changed flag is valueX_changed . This is a very trivial part, just check if any button has a different state, and then set the flag.

The second part is a state transition check. In this switch statement, the program determines whether to change the state of the state machine. This happens when the button was pressed, if the state is inactive, or if the specified amount of time has passed, if in the process of sending SMS.

The third part is the action that should be performed when the state changes. Therefore, if the state has changed, perform the state action, which means nothing for the idle state, send something for the SIM_SENDx states and change the contact for the SIM_POWx states.

Just a note: in the setup, you added a 20 second delay not present in the normal workflow. If you want to remove this, you can simply remove the four lines from the reset setting and change the default case in the first switch to set newSimState = SIM_POW1; instead of SIM_IDLE .

There may be small errors in this code since I have not tested it, but it should do what you need.

+1
source

Use the timer library https://playground.arduino.cc/Code/Timer/ . As stated by them:

The disadvantage of the delay approach is that nothing can go on during delay . You cannot refresh the display or check keystrokes, for example.

So instead of delay you can use:

  t.every(1000, doStuff); 

To call a function, leaving a loop to make it a business in the meantime.

Hope it helps.

+1
source

The millis() function will fail with an overflow of value. As @CPU_Terminator said, use interrupts. There are useful Arduino libraries for this, such as Timer1 .

EDIT . Assuming you want to send SMS every 100 ms, if some of your inputs have changed, you can use a code like this (I removed some delays that I don't think are necessary, add them again if I am wrong)

 #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 } 

Thus, the isr_timer() function will execute every 0.1 seconds.

-1
source

You can try using the code in the isr_timer () function:

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

Best wishes

-1
source

Source: https://habr.com/ru/post/985411/


All Articles