Дозвон на телефон не идёт

Добрый день.
Делаю сигнализацию открытия двери.
Использованы Ардуино NANO, плата для сотовой связи SIM800L и MP3 TF 16P Player.
По плану работы:

  1. наступает вечернее время - включается освещение перед дверью;
  2. при открытии двери:
    - звучит аудиозапись;
    - включается основное освещение;
    - звонки на два номера;
    - СМС на два номера;
    По отдельности все части системы работают. Пока всё собрано на макетной плате, но SIM800L запитан хорошо, не жалуется.
    Когда собираю все части кода воедино, свет и аудио срабатывают, а звонки не идут.
    Прошу помочь разобраться где конфликтуют части моего кода.
    Спасибо!

Тему форума
Arduino+SIM800L. TinyGSM. Не работает пример
я просмотрел. Там про другое.

String numberCall_1 = "7913"; // Номер абонента №1 для звонка
String numberSMS_1 = "+7913"; // Номер абонента №1 для СМС (отличается только знаком +)
String numberCall_2 = "7913"; // Номер абонента №2 для звонка
String numberSMS_2 = "+7913"; // Номер абонента №2 для СМС (отличается только знаком +)
String textZone_1 = "Otkryta dver!";    // Свое название зоны ,  на латинице.

#include <SoftwareSerial.h>           // Подключаем библиотеку SoftwareSerial
SoftwareSerial mySerial(2, 3);        // RX, TX

void initGSM(void) {
  delay(2000);                            
  mySerial.begin(9600);  // Выставляем скорость общения с GSM-модулем 9600 Бод/сек.  
  mySerial.println("AT"); 
  mySerial.println("AT+CLIP=1");          
  delay(300);
  mySerial.println("AT+CMGF=1");          
  delay(300); 
  mySerial.println("AT+CSCS=\"GSM\"");    
  delay(300); 
  mySerial.println("AT+CNMI=2,2,0,0,0");  
  delay(300); 
  Serial.println("Выставлены параметры GSM");
}

/* Отправка SMS */
void sendSMS(String text, String phone) {
  mySerial.println("AT+CMGS=\"" + phone + "\""); 
  delay(500);
  mySerial.print(text);                         
  delay(500);
  mySerial.print((char)26);       
  delay(2500);  
}
unsigned long timerTemp = 0;  
uint8_t hours = 0;            
uint8_t flagSensor_0 = 0;
uint8_t flagSensor_1 = 0;
bool NochnoeVremya = 1;
bool podsvetNomera = 0;
bool ZvukVkluchen = 0;
bool DverOtkryta = 0;
int FalshivoeVremya = 8;
bool najatie8 = 0;

void setup() {
  Serial.begin(9600);                 // Скорость обмена данными с компьютером
  Serial.println("Start!");
  mySerial.begin(9600);               // Скорость обмена данными с GSM модулем
  initGSM(); 
  pinMode(5, INPUT);              //  вход от концевика открытия двери
  pinMode(6, OUTPUT);             //  ВЫКЛ. аудиозаписи
  digitalWrite(6, HIGH);
  pinMode(7, OUTPUT);             //  ВКЛ. аудиозаписи  
  digitalWrite(7, HIGH);
  pinMode(11, OUTPUT);            //  подсвет коридора при срабатывании
  pinMode(12, OUTPUT);            //  подсвет площадки в ночное время
  pinMode(8, INPUT);              //  кнопка остатка времени до включения ночи.
  timerTemp = millis(); 
}

void loop(){

  // УСТАНАВЛИВАЕМ СВЯЗЬ МЕЖДУ АРДУИНО И МОДЕМОМ SIM800 на mySerial(2,3)  
  if (mySerial.available())           // Ожидаем прихода данных (ответа) от модема...
      Serial.write(mySerial.read());    // ...и выводим их в Serial
  if (Serial.available())           // Ожидаем команды по Serial...
      mySerial.write(Serial.read());    // ...и отправляем полученную команду модему

  // ОРГАНИЗУЕМ ВКЛ-ВЫКЛ СИСТЕМЫ на ВЕЧЕР-УТРО
  if(millis() - timerTemp >= 3600000) {timerTemp = millis(); hours++;}
  if(hours == 12) { // переключение происходит через 12 часов.
    if (NochnoeVremya==0) {
      NochnoeVremya =1;
      sendSMS(String("The system works normally.OK"), numberSMS_1); 
      delay(10000);                                                          
    }
  }
  if(hours == 24) { // переключение происходит через 12 часов.
    if (NochnoeVremya==1) {
      NochnoeVremya =0;
      hours = 0;                                     
    }
  }
  // установка оставшихся часов ДО ПЕРВОГО НАСТУПЛЕНИЯ НОЧИ допустим, ночь наступает в 20.00, 
  //    сейчас на часах 14.00   значит на кнопку (на ноге D8) нужно нажать 6 раз    
  if (digitalRead(8) == HIGH && najatie8 == 0) {
    najatie8 =1; // кнопка нажата
    if (hours == 0) hours = 12;
  }  
  if (digitalRead(8) == LOW && najatie8 == 1) {
    hours = hours - 1;
    najatie8 =0; // кнопка отпущена
  }

  if(millis()%100000==0){                 // если прошло 100 секунд 
//    Serial.print("Время системы ");                         
//    Serial.println(hours);              // Отправка часа 
    Serial.print("Ночное время ");                           
    Serial.println(NochnoeVremya);         // Знак ночного времени 
//    Serial.print("Подсвет номера ");                        
//    Serial.println(podsvetNomera);        // Знак подсвета номера
    Serial.print("Звук включён ");                         
    Serial.println(ZvukVkluchen);           // Знак включения аудиозаписи
    Serial.print("Дверь открыта ");                         
    Serial.println(DverOtkryta);            // Знак открытия двери
    delay(10);                           
  }   
// ОСНОВНЫЕ СРАБАТЫВАНИЯ СИСТЕМЫ
  // ПОДСВЕЧИВАЕМ ПЛОЩАДКУ
  if (NochnoeVremya == 1 && podsvetNomera == 0) {   
    digitalWrite(12, HIGH);
    delay(10);   
    podsvetNomera = 1; 
    delay(10);   
  }
  //ПОДТВЕРЖДАЕМ ОТКРЫТИЕ ДВЕРИ 
  if (NochnoeVremya == 1) {
    if ( digitalRead(5) == HIGH && DverOtkryta == 0) {
      DverOtkryta = 1;
      delay(10);
    }
  }
  // ВКЛЮЧАЕМ АУДИОЗАПИСЬ И ПОДСВЕЧИВАЕМ КОРИДОР.
  if ( DverOtkryta == 1 && ZvukVkluchen == 0) {
    digitalWrite(7, LOW); 
    delay(300);
    digitalWrite(7, HIGH);
    delay(10);
    digitalWrite(11, HIGH);
    delay(10);
    Serial.println("Нажатие зафиксировано");
    Serial.println("Звук есть"); 
    ZvukVkluchen = 1; 
    delay(10);
  }
  // ГАСИМ ПОДСВЕТ ПЛОЩАДКИ
  if (NochnoeVremya == 0 && podsvetNomera == 1) {   
    digitalWrite(12, LOW);
    podsvetNomera = 0;
    delay(10);      
  }
  //ПОДТВЕРЖДАЕМ ЗАКРЫТИЕ ДВЕРИ 
  if ( digitalRead(5) == LOW && DverOtkryta == 1) {
    DverOtkryta = 0;
  delay(10);   
  }
  // ГАСИМ АУДИОЗАПИСЬ И ПОДСВЕТ КОРИДОРА.
  if ( DverOtkryta == 0 && ZvukVkluchen == 1) {
    digitalWrite(6, LOW); 
    delay(300);
    digitalWrite(6, HIGH); 
    delay(10); 
    digitalWrite(11, LOW);
    delay(10); 
    Serial.println("кнопка отжата 1");
    Serial.println("Тишина 1"); 
    ZvukVkluchen = 0;
    delay(10); 
  }
  // ВЫКЛЮЧАЕМ АУДИОЗАПИСЬ ВТОРЫМ СПОСОБОМ.
  if ( digitalRead(5) == LOW && ZvukVkluchen == 1) {
    digitalWrite(6, LOW);  
    delay(300);
    digitalWrite(6, HIGH); 
    digitalWrite(11, LOW);  
    ZvukVkluchen = 0;
    DverOtkryta = 0;
    Serial.println("Нажатия нет 2");
    Serial.println("Тишина 2");
  }

  // ИНФОРМИРУЕМ О СРАБАТЫВАНИИ ЗВОНКАМИ И СМС
  if( ZvukVkluchen == 1 && flagSensor_0 == 0) {       
    flagSensor_0 = 1; 
    flagSensor_1 = 1;
    Serial.print("ФлагСенсор ");                           
    Serial.println(flagSensor_0);                           
  }
  if(flagSensor_0 == 1) {
    String command;

    command = "ATD+" + numberCall_1 + ";";  
    mySerial.println(command);              
    delay(20000);                           
    mySerial.println("ATH");                
    delay(1000);

    command = "ATD+" + numberCall_2 + ";";  
    mySerial.println(command);              
    delay(20000);                           
    mySerial.println("ATH");                
    delay(1000);

    flagSensor_0 = 2;
    Serial.print("ФлагСенсор ");                            
    Serial.println(flagSensor_0);                                                
  }
  if( digitalRead(5) == LOW && flagSensor_0 == 2) {
    flagSensor_0 = 0;
    flagSensor_1 = 0;
  } 
  if(flagSensor_1 == 1 && flagSensor_0 == 2) {
    sendSMS(textZone_1, numberSMS_1); 
    delay(10000);                     
    sendSMS(textZone_1, numberSMS_2); 
    delay(10000);                     
    flagSensor_1 = 2;             
  } 
}

хз появится ли звонок, но очень много делеев, надо избавляться

Спасибо за ответ.
Те delay(10), которые в строках 120 и 134 применил в коде, потому что в учебнике нашёл это:

// выполнить короткую задержку, чтобы дать возможность 
// следующим цифрам достичь буфера 
delay(5); 

Без задержек SIM800 вообще не реагировал на изменение переменной, а с ними начал работать.
Поэтому везде, где меняю переменную или посылаю её в Serial навтыкал коротких задержек.
Все длинные задержки не мои, они взяты из чужого, применённого мною исходного кода.
От каких именно, считаете, нужно избавляться?

все delay(10)
и например в строке 186 зачем ждать

а коой буфер в строке 120?
там не нужна задержка.

Убрал все задержки(10).
Убрал все сообщения для монитора порта, кроме первого “Старт”.

Заработало!

Спасибо Вам за участие! Доброго дня.

Это все, в теории правильно, но применимо для HardwareSerial.
SoftwareSerial не слушает в фоне и, пока МК висит в делее после write(), он пропускает начало ответа модема.

Спасибо!
Я ориентировался на следующее утверждение:

Большинство активности платы останавливается функцией delay(). Тем не менее работа прерываний не останавливается, продолжается запись последовательно (serial) передаваемых данных на RX порту, ШИМ сигнал (analogWrite) продолжает генерироваться на портах.

Выходит, если бы “повесил” общение с модемом на ноги 0 и1, то проблема бы даже не возникла?

В принципе - да, но заливать скетч стало бы проблематичней на порядок. Соответственно и отлаживать - тоже.

Вот это, кстати, тоже так себе приемчик.
“Blink без delay” читайте.

1 лайк

Опять же спасибо Вам!
Обязательно гляну.
Доброго дня!

чтобы убрать вот такие ненужные задержки

    sendSMS(textZone_1, numberSMS_1); 
    delay(10000);

делайте так
тогда задержка будет ровно столько сколько необходимо и не больше

String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                            // Переменная для хранения результата
  Serial.println(cmd);                          // Дублируем команду в монитор порта
  SIM800.println(cmd);                          // Отправляем команду модулю
  if (waiting) {                                // Если необходимо дождаться ответа...
    _resp = waitResponse();                     // ... ждем, когда будет передан ответ
    // Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
    if (_resp.startsWith(cmd)) {  // Убираем из ответа дублирующуюся команду
      _resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
    }
    Serial.println(_resp);                      // Дублируем ответ в монитор порта
  }
  return _resp;                                 // Возвращаем результат. Пусто, если проблема
}

String waitResponse() {                         // Функция ожидания ответа и возврата полученного результата
  String _resp = "";                            // Переменная для хранения результата
  long _timeout = millis() + 10000;             // Переменная для отслеживания таймаута (10 секунд)
  while (!SIM800.available() && millis() < _timeout)  {}; // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (SIM800.available()) {                     // Если есть, что считывать...
    _resp = SIM800.readString();                // ... считываем и запоминаем
  }
  else {                                        // Если пришел таймаут, то...
    Serial.println("Timeout...");               // ... оповещаем об этом и...
  }
  return _resp;                                 // ... возвращаем результат. Пусто, если проблема
}

Знаешь почему так делать нельзя?

ЗЫ: И логическое И тут не нужно, нужно логическое ИЛИ.

вы правы какаято странная фигня и почему там не unsigned хотябы)

почему или?
смысл то тогда от этой всей конструкции?

Полностью согласен с Вами - это отличная статья, в Вашей ссылке на Codius.
По ней я разбирался с работой GSM модуля, ну да всего сразу не охватишь.
Включение модуля и установки в него взял как раз отсюда!
С организацией передачи данных буду разбираться дальше.
Главное - направление поиска понятно.
Ещё раз спасибо и всего Вам доброго!

Наверное потому, что при достижении максимального значения millis(), оно станет равным 0 не достигнув millis()+10000.
Тогда, в случае отсутствия ответа от модуля SIM, код не выйдет на строку else до тех пор, пока снова не попадёт на строку long _timout =…
Так?

Нет.
При переполнении long вообще отрицательным станет. А вообще есть у нас тут:
Великое переполнение millis(), рекомендую ознакомиться.

там unsigned long должен быть, и тогда, если я правильно понимаю, чуть менее чем раз в 50 дней на 10 секунд он не будет ждать ответа при любом раскладе.

Действительно, запамятовал, что у long есть отрицательная часть значений!