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