Выполнение функций «одновременно»

все Я разрабатываю систему безопасности автомобиля, в основном я уже умею читать и управлять всеми компонентами (GSM, GPS, магнитный датчик, гироскоп, зуммер...), подключенными к микроконтроллеру.

Но тогда функции в основном три основные (в пустом цикле), которые мне нужно работать «одновременно», есть идеи, как я могу это сделать?

Под кодом половина длины, но это все, что мне нужно...

есть некоторые комментарии на португальском языке. прошу прощения за это, но главное в коде заранее спасибо

#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;  //ДАТЧИК МАГНИТНЫЙ

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;   //УДАЛЕННЫЙ
IRrecv irrecv(RECV_PIN);
decode_results results;


int Sirene = 6;     //ЗУММЕР
int Motor = 7;      //МОТОР




/////============================================ ======================== Инициализация датчиков ======================= ================================================== ================================================== ==
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); //ДАТЧИК МАГНИТНЫЙ
pinMode(Sirene, OUTPUT);  //Сирена
pinMode(Motor, OUTPUT);   //МОТОР
irrecv.enableIRIn();
Serial.println("SISTEMA INICIALIZADO");  
}



/////============================================ ======================== Inicio do Loop ======================= ================================================== ================================================== ==
void loop()
{
 //GPS();
 remote ();
 ReceberComando();

 }


/////============================================ ======================== Пульт дистанционного управления ======================== ================================================== ================================================== "="

void remote (){
 if (irrecv.decode(&results))
{
Serial.println(results.value, HEX);
Serial.println("  ");
if (results.value== 0xFF6897)
{
//пока (результаты.значение==0xFF5AA5){
Serial.println("SISTEMA INACTIVO");
digitalWrite(Motor, LOW);
Serial.println("  ");
//Аселометро();
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(); // Получаем следующее значение
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);
}

/////=================== координаты/ 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);// Инициализировать строку BuffIndex=5; }
delay (9000);

pinMode(Motor, OUTPUT); // управление двигателем

while(1)
{          
 if(sgsm.available()>0)
 {              
  Buff[BuffIndex] = sgsm.read();                        
  if( (Buff[BuffIndex-2] == 'D') && (Buff[BuffIndex-1] == 'M') && (Buff[BuffIndex] == '1'))// Отключить двигатель сейчас
  {                    
  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'))// Активировать двигатель сейчас
  {                    
  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'))// Координаты возврата
  {  
  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");    // Устанавливает модуль GSM в текстовый режим
 delay(1000);
 Serial.println ("Set sgsm Number");
 sgsm.println("AT+CMGS=\"" + number + "\"\r"); //Номер мобильного телефона для отправки сообщения
 delay(1000);
 sgsm.println(SMS);
 delay(100);
 sgsm.println((char)26);// ASCII-код CTRL+Z
 delay(1000);
 }


void mensagem()// mensagens das variaveis; e inicializacao do carro
{
 Serial.println ("Sending Message");
 sgsm.println("AT+CMGF=1");    // Устанавливает модуль GSM в текстовый режим
 delay(1000);
 Serial.println ("Set sgsm Number");
 sgsm.println("AT+CMGS=\""+ number + "\"\r"); //Номер мобильного телефона для отправки сообщения
 delay(1000);
 String SMS = "Sistema de Alarme habilitado";   //sgsm-контент
 sgsm.println(SMS);
 delay(100);
 sgsm.println((char)26);// ASCII-код CTRL+Z
 delay(1000);
}


void mensagem2()// mensagens das variaveis; e inicializacao do carro
{
 Serial.println ("Sending Message");
 sgsm.println("AT+CMGF=1");    // Устанавливает модуль GSM в текстовый режим
 delay(1000);
 Serial.println ("Set sgsm Number");
 sgsm.println("AT+CMGS=\""+ number + "\"\r"); //Номер мобильного телефона для отправки сообщения
 delay(1000);
 String SMS = "Alerta de intrução! Verifique a sua viatura.";   //sgsm-контент
 sgsm.println(SMS);
 delay(100);
 sgsm.println((char)26);// ASCII-код 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());//Пересылаем полученный Serial на программный последовательный порт
 }
 while(sgsm.available())
 {
 Serial.write(sgsm.read());//Перенаправить то, что Software Serial получил на последовательный порт
 }
}


/////======= localizacao ==================================== ===
void enviolink()
{
  sgsm.println("AT+CMGF=1");    // Устанавливает модуль GSM в текстовый режим
  delay(1000);  // Задержка 1000 миллисекунд или 1 секунда
  sgsm.println("AT+CMGS=\"+25884xxxxxxx\"\r"); // Заменить x на номер мобильного телефона
  delay(1000);
  sgsm.println(link);// Текст SMS, который вы хотите отправить
  delay(100);
  sgsm.println((char)26);// ASCII-код CTRL+Z
  delay(1000);  
}

, 👍0


3 ответа


1

Не анализируя весь код, необходимо выполнить следующие шаги:

  • Удалите вызовы функции delay. В основном они задерживают программу таким образом, что другие части не выполняются вовремя или «одновременно».
  • Вместо этого используйте команду millis и проверьте снова метки времени (типа unsigned long int), чтобы достичь необходимых задержек.
  • Создайте конечный автомат. В простой форме это означает, что вы используете перечисление (тип enum), которое может иметь одно из набора значений (например, Stopped, Accelerating, Decelerating) для каждого «состояния», которое вы можете определить в своем скетче.
  • Используйте эти конечные автоматы и время для перехода из одного состояния в другое, и при изменении состояния (или во время состояния) вы можете выполнять необходимые действия.
,

У вас небольшая опечатка в ответе. Это функция millis(), а не milli. Новичок может этого не знать и может не найти функцию с такой опечаткой., @Duncan C

@DuncanC Спасибо за уведомление, я обновил свой ответ. Я также добавил ссылку на страницу., @Michel Keijzers


4

Поскольку вы взяли слово «одновременно» в кавычки, я предполагаю, что вы понимаете, что один микроконтроллер может делать только одну вещь за раз, но умело запрограммированный, он может делать небольшие части из нескольких вещей быстрее, чем мы с вами можем воспринимать разница. (Я указываю это для полноты, для читателей, которые, возможно, еще не додумались до этого.)

В этом вам помогут несколько приемов.

Одна из них — это то, что я называю функциями «может быть», — функции, которые вы вызываете часто, которые что-то делают или не делают (в зависимости от таких условий, как время или входные сигналы), но они делают это быстро и немедленно возвращаются. См. мой ответ здесь для более подробного объяснения функций "maybedo".

Еще один очень важный момент — избегать вызовов delay(). Попробуйте библиотеку таймеров, например SimpleTimer. Это позволяет вашей функции loop() и тем, которые она вызывает, быть короткими. Запись библиотеки SimpleTimer является «возможной» для 10 функций, управляемых таймером. Все, что вам нужно сделать, это часто вызывать mytimers.run(). В большинстве случаев он мало что делает, но иногда обнаруживает, что один или несколько таймеров истекли, и вызывает для вас связанные с ними функции. Вам просто нужно настроить таймеры для вызова некоторых простых — и опять же, коротких — функций, чтобы что-то сделать. И чтобы было ясно, мы говорим о программных таймерах, а не об аппаратных таймерах микроконтроллера. Работа библиотеки основана на функции millis(), но она автоматизирует ее за вас.

,

Для своих приложений я создал класс ArduinoObject. Каждый ArduinoObject имеет функцию setup() и функцию loop(), а также логический флаг active. Мои приложения управляют массивом ArduinoObject. Если активный флаг объекта имеет значение true, цикл приложения вызывает функцию цикла при каждом проходе. Если нет, то вообще не вызывается. Это позволяет очень легко динамически управлять целой кучей задач, которые вы называете «MaybeDo»., @Duncan C

Приложение использует массив C фиксированного размера с достаточным количеством элементов для максимального количества объектов ArduinoObject, необходимых моему приложению. Если мне нужно добавить еще одну задачу, я добавляю в массив ArduinoObject. Если я хочу, чтобы один из объектов заснул, я устанавливаю его активный флаг в false. Код, который управляет массивом ArduinoObject, игнорирует значения NULL, поэтому я могу установить одно из них в значение NULL, если я полностью с этим покончил. Код, который добавляет новый объект, ищет первый пустой слот в массиве. Каждый ArduinoObject написан таким образом, чтобы каждый проход по его циклу занимал очень мало времени., @Duncan C

Интересная структура задачи - спасибо!, @JRobert


0

Как уже говорили другие, Arduino — это однопоточные компьютеры реального режима. Они делают только одно дело за раз. Тем не менее, они делают это достаточно быстро, чтобы вы могли заставить свои приложения переключаться между задачами достаточно быстро, чтобы они могли выполнять несколько задач, как цирковой клоун, который заставляет множество тарелок вращаться на палочках.

Вы должны использовать совместную многозадачность по принципу "самостоятельно", когда каждый раз в цикле вашего приложения вы ищете работу для каждой из задач, которые вы выполняете. Вы должны сделать каждый проход по циклу быстрым, чтобы ничего не пропустить.

По возможности следует полностью избегать использования функции delay(). Функции delay() и delayMicros() полностью останавливают ваше приложение на все время задержки.

Выполните поиск «Arduino, мигающий без задержки» и посмотрите на образец приложения, на который указывает. Он показывает, как использовать millis() для управления синхронизированными действиями без использования delay(). Вы должны применять этот подход ко всему, что вы делаете.

,