everyone I'm designing a vehicle security system, basically I can already read amd i control all the components (GSM, GPS, Magnetic Sensor, Giroscop, buzzer...) connected to the microcontroller.
But then the functions are basically three main ones (at void loop) that I need to be working in "simultaneous", any idea of how I can do that?
Below the code, half long but that's all I need...
there are some comments in portuguese. i apologize for that, but the important thing is in the code thanks in advance
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
SoftwareSerial sgsm(3,2);
String number = "25884xxxxxxx" ;
unsigned char Buff[250];
unsigned char BuffIndex;
#include<Wire.h>
int sensorMag = 5; //SENSOR MAGNETICO
TinyGPSPlus gps;
double latitude, longitude;
String response;
int lastStringLength = response.length();
String link;
const int MPU6050_addr=0x68;
int16_t AccX,AccY,AccZ,Temp,GyroX,GyroY,GyroZ;
#include <IRremote.h>
int RECV_PIN = 4; //REMOTE
IRrecv irrecv(RECV_PIN);
decode_results results;
int Sirene = 6; //BUZZER
int Motor = 7; //MOTOR
/////===================================================================== Inicializacao do sensores =============================================================================================================================
void setup()
{
Serial.begin(9600);
sgsm.begin(9600);
delay (1000);
Wire.begin();
Wire.beginTransmission(MPU6050_addr);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
delay (1000);
pinMode(sensorMag, INPUT); //SENSOR MAGNETICO
pinMode(Sirene, OUTPUT); //Sirene
pinMode(Motor, OUTPUT); //MOTOR
irrecv.enableIRIn();
Serial.println("SISTEMA INICIALIZADO");
}
/////===================================================================== Inicio do Loop =============================================================================================================================
void loop()
{
//GPS();
remote ();
ReceberComando();
}
/////===================================================================== Remote controle =============================================================================================================================
void remote (){
if (irrecv.decode(&results))
{
Serial.println(results.value, HEX);
Serial.println(" ");
if (results.value== 0xFF6897)
{
//while (results.value==0xFF5AA5){
Serial.println("SISTEMA INACTIVO");
digitalWrite(Motor, LOW);
Serial.println(" ");
//Acelerometro();
delay(500);
}
else
{
while (results.value==0xFF10EF)
{
Serial.println("Sistema Armado");
digitalWrite(Motor, HIGH);
delay(1000);
Serial.println(" ");
SensorMagnetico();
delay(1000);
Acelerometro();
delay(1000);
}
}
}
irrecv.resume(); // Receive the next value
delay(1000);
}
void SensorMagnetico()
{
int EstadosensorMag = digitalRead(sensorMag);
if (EstadosensorMag = digitalRead(sensorMag)== HIGH){
Serial.println("A porta N. 1 da sua viatura foi aberta!");
digitalWrite(Sirene, HIGH);
delay(1000);
mensagem2();
delay(1000);
enviolink();
delay (1000);
}
else
Serial.println("Portas Fechadas");
digitalWrite(Sirene, LOW);
delay(100);
//digitalWrite(Motor, HIGH);
}
void Acelerometro(){
Wire.beginTransmission(MPU6050_addr);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_addr,14,true);
AccX=Wire.read()<<8|Wire.read();
AccZ=Wire.read()<<8|Wire.read();
Serial.print("AccX = ");
Serial.print(AccX);
Serial.print(" || AccZ = ");
Serial.println(AccZ);
delay(1000);
if (AccZ > 2000){
digitalWrite(Sirene, HIGH);
delay(2000);
}
else
digitalWrite(Sirene, LOW);
}
/////==================== coordenadas/ GPS=============================
void GPS(){
if(Serial.available()) {
gps.encode(Serial.read());
}
if(gps.location.isUpdated()) {
Serial.print("latitude:");
latitude = gps.location.lat();
Serial.print("longitude:");
longitude = gps.location.lng();
link = "www.google.com/maps/place/" + String(latitude, 6) + "," + String(longitude, 6) ;
Serial.println(link);
}
}
/////========= Receber Comandos de texto + localizacao ======================
void ReceberComando()
{
Serial.begin(9600);
sgsm.begin(9600);
Serial.print("Inicializado o GSM e apagando SMS");
clear_SMS_Memory();
delay(3000);
sgsm.println("AT+CMGF=1");
delay(3000);
sgsm.println("AT+CNMI=2,2,0,0,0");
memset(Buff, '0円', 250);// Initialize the string BuffIndex=5; }
delay (9000);
pinMode(Motor, OUTPUT); // controle do motor
while(1)
{
if(sgsm.available()>0)
{
Buff[BuffIndex] = sgsm.read();
if( (Buff[BuffIndex-2] == 'D') && (Buff[BuffIndex-1] == 'M') && (Buff[BuffIndex] == '1'))// Desativar Motor Agora
{
digitalWrite(Motor, HIGH);
send2("Motor da sua viatura desligado! aguarde pelas coordenadas...");
Serial.println ("Set sgsm Number");
delay(10000);
GPS();
delay(10000);
enviolink();
Serial.println(" ");
}
if( (Buff[BuffIndex-2] == 'A') && (Buff[BuffIndex-1] == 'R') && (Buff[BuffIndex] == 'M'))//Ativar Motor Agora
{
digitalWrite(Motor, LOW);
digitalWrite (Sirene, LOW);
send2("Motor Ativo....A viatura esta segura!, Aguarde a localizacao!");
Serial.println ("Set sgsm Number");
delay(1000);
GPS();
delay(1000);
enviolink();
Serial.println(" ");
}
if( (Buff[BuffIndex-2] == 'L') && (Buff[BuffIndex-1] == 'O') && (Buff[BuffIndex] == 'C'))//Retorna coordenadas
{
send2("Buscado a localizacao actual!");
GPS();
delay(10000);
enviolink();
Serial.println(" ");
delay(10000);
}
/// Pode se acrescentar mais condicoes
BuffIndex++;
if(BuffIndex>250)
{
BuffIndex=5;
}
}
}
}
/////=============== Mensagens de Texto =======
void send2(String SMS)
{
Serial.println ("Sending Message");
sgsm.println("AT+CMGF=1"); //Sets the GSM Module in Text Mode
delay(1000);
Serial.println ("Set sgsm Number");
sgsm.println("AT+CMGS=\"" + number + "\"\r"); //Mobile phone number to send message
delay(1000);
sgsm.println(SMS);
delay(100);
sgsm.println((char)26);// ASCII code of CTRL+Z
delay(1000);
}
void mensagem()// mensagens das variaveis; e inicializacao do carro
{
Serial.println ("Sending Message");
sgsm.println("AT+CMGF=1"); //Sets the GSM Module in Text Mode
delay(1000);
Serial.println ("Set sgsm Number");
sgsm.println("AT+CMGS=\""+ number + "\"\r"); //Mobile phone number to send message
delay(1000);
String SMS = "Sistema de Alarme habilitado"; //sgsm content
sgsm.println(SMS);
delay(100);
sgsm.println((char)26);// ASCII code of CTRL+Z
delay(1000);
}
void mensagem2()// mensagens das variaveis; e inicializacao do carro
{
Serial.println ("Sending Message");
sgsm.println("AT+CMGF=1"); //Sets the GSM Module in Text Mode
delay(1000);
Serial.println ("Set sgsm Number");
sgsm.println("AT+CMGS=\""+ number + "\"\r"); //Mobile phone number to send message
delay(1000);
String SMS = "Alerta de intrução! Verifique a sua viatura."; //sgsm content
sgsm.println(SMS);
delay(100);
sgsm.println((char)26);// ASCII code of CTRL+Z
delay(1000);
}
////========================= Apaga mensagens no cartao ===========
void clear_SMS_Memory()
{
unsigned short i = 0;
for (i = 0; i <= 30; i++)
{
sgsm.print("AT+CMGD=");
sgsm.println(i);
delay(100);
}
while (sgsm.available() > 0) sgsm.read();
}
/////===================== Leitura de Inputs do GSM ==========
void updateSerial()
{
delay(500);
while (Serial.available())
{
sgsm.write(Serial.read());//Forward what Serial received to Software Serial Port
}
while(sgsm.available())
{
Serial.write(sgsm.read());//Forward what Software Serial received to Serial Port
}
}
/////======= localizacao ========================================
void enviolink()
{
sgsm.println("AT+CMGF=1"); //Sets the GSM Module in Text Mode
delay(1000); // Delay of 1000 milli seconds or 1 second
sgsm.println("AT+CMGS=\"+25884xxxxxxx\"\r"); // Replace x with mobile number
delay(1000);
sgsm.println(link);// The SMS text you want to send
delay(100);
sgsm.println((char)26);// ASCII code of CTRL+Z
delay(1000);
}
3 Answers 3
Since you put "simultaneous" in quotes, I'm assuming you realize that one MCU can only do one thing at a time, but cleverly programmed, it can do small pieces of several things faster than you and I can perceive the difference. (I state this for completeness, for the benefit of readers who may not have thought this out yet.)
A couple of techniques will help you here.
One is what I call "maybedo" functions - functions you call frequently, that do or do not do something (depending on conditions such as time or input signals) but they do it quickly and return immediately. See my answer here for more explanation of "maybedo" functions.
Another and very important one is to avoid delay()
calls. Try a timer library such as SimpleTimer. This lets your loop()
function and those it calls, keep short. The SimpleTimer library entry is a "maybedo" for up to 10 timer-driven functions. All you have to do is call mytimers.run()
frequently. Mostly it won't do much, but occasionally it will find one or more timers have expired and will call their associated functions for you. You just have to have set up the timers to call some simple - and again, short - functions to do something. And to be clear, we're talking about software-based timers, not the MCU's hardware timers. The library's work is based on the millis()
function, but it automates that for you.
-
For my apps, I created a class
ArduinoObject
. EachArduinoObject
has asetup()
function and aloop()
function, as well as anactive
boolean flag. My apps manage an array ofArduinoObject
s. If an object's active flag is true, the app's loop calls its loop function on each pass through. If not, it isn't called at all. This makes it very easy to manage a whole bunch of what you call "MaybeDo" tasks dynamically.Duncan C– Duncan C2019年12月20日 00:29:28 +00:00Commented Dec 20, 2019 at 0:29 -
The app uses a fixed-sized C array with enough elements for the max number of
ArduinoObject
s my app needs. If I need to add another task, I add anArduinoObject
to the array. If I want one of the objects to go to sleep, I set itsactive
flag to false. The code that manages the array ofArduinoObject
ignores NULL values, so I can set one of them to NULL if I'm completely done with it. The code that adds a new object searches for the first empty slot in the array. EachArduinoObject
is written to take very little time on each pass through its loop.Duncan C– Duncan C2019年12月20日 00:31:54 +00:00Commented Dec 20, 2019 at 0:31
Without analyzing the complete code, the steps to go are:
- Remove the
delay
function calls. These mostly delay the program in such a way that other parts are not executed in time or 'at the same time'. - Instead use the
millis
command and check again time stamps (ofunsigned long int
type) to reach the delays you need. - Create a state machine. This means in simple form that you use an enumeration (
enum
type) which can have one out of a set of values (like Stopped, Accelerating, Decelerating), for each 'states' you can define in your sketch. - Use these state machines and times to move from one state to another, and while changing state (or during a state) you can perform the actions you need.
-
1You have a minor typo in your answer. The function is
millis()
notmilli
. A newbie might not know that, and might fail to find the function with that typo in it.Duncan C– Duncan C2019年12月19日 22:49:01 +00:00Commented Dec 19, 2019 at 22:49 -
@DuncanC Thanks for the notification, I updated my answer. I also added a reference to the page.Michel Keijzers– Michel Keijzers2019年12月19日 22:56:21 +00:00Commented Dec 19, 2019 at 22:56
As others have said, Arduinos are single-threaded, real mode computers. They only do one thing at a time. However, they do that one thing fast enough that you can make your apps switch between things rapidly enough that they keep multiple tasks running, like a circus clown keeping lots of plates spinning on sticks.
You have to use "roll-your-own" cooperative multitasking, where each time through your app's loop, you look for work to do on each of the tasks you're juggling. You have to make each pass through the loop fast so you don't miss things.
You should avoid the delay()
function entirely if at all possible. The delay()
and delayMicros()
functions bring your app to a complete halt for the entire duration of the delay.
Search on "Arduino blink without delay" and look at the sample app that points to. It shows how to use millis()
to manage timed actions without using delay()
. You should apply that approach to everything you do.