не очевидное состояние выхода (NANO)

Prostovova
Offline
Зарегистрирован: 17.10.2017

Оборудование: Ардуинка Нано, GSM модуль SIM800, 3 реле на ключах (кт3102), питание 12V + преобразователь с 12V на 4V (для SIM800). Мощность источника 12V - достаточная.

Реле на выходах 2, 3, 4 . Так вот на D4 в состоянии "1" - напряжение 1,4 V; "0" - 0,1V. (на 2и 3 - 5V и 0,01V  соответственно). От состояния на выводах 2 и 3 не зависит (то есть грешить на нехватку мощности преобразователя видимо не стоит).

Вопрос - никто не сталкивался? Что это может быть: кирдык платы, кривые руки или еще что то.

Причем, что интересно - реле отрабатывает, но информация о состоянии выхода (по digitalRead) считывается как "0"

b707
Offline
Зарегистрирован: 26.05.2017

ставлю на то, что D2 и D3 в скетче описаны как OUTPUT, а про D4 забыли

Prostovova
Offline
Зарегистрирован: 17.10.2017

Да, еще забыл. Если загрузить "блинк" на этот вывод (на этой собранной плате) - все отрабатывает нормально (0,01V и 5V)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Prostovova пишет:

Да, еще забыл....

Вы забыли не только это. Вы также забыли приложить схему, скетч и фото сборки.  А хрустальные шары здесь запрещены :(((

Prostovova
Offline
Зарегистрирован: 17.10.2017

Использован известный (модифицированный под собственные нужды код)

Подключение выходов организовано так:

int pins[3] = {2, 3, 4};

void setup() {
    for (int i = 0; i < 2; i++) {
    pinMode(pins[i], OUTPUT); 

  }  

Prostovova
Offline
Зарегистрирован: 17.10.2017
Весь код выглядит так:
 
Удалил, что бы не засорять галиматьей
Постом ниже коректная вставка
 
b707
Offline
Зарегистрирован: 26.05.2017

Prostovova пишет:

Использован известный (модифицированный под собственные нужды код)

Подключение выходов организовано так:

int pins[3] = {2, 3, 4};

void setup() {
    for (int i = 0; i < 2; i++) {
    pinMode(pins[i], OUTPUT); 

  }  

это круто :) Добавьте вывод в Сериал переменной i и убедитесь, что до третьего по счету пина ваш цикл не доходит :)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Вова, ты до сих пор код вставлять не научилса?  Как эту галиматью читать прикажешь?

Prostovova
Offline
Зарегистрирован: 17.10.2017

Схем простая: ключ на n-p-n транзисторе кт3102 (на всез 3-х выходах одинаково), резистор в базе =6,8к, диод на реле кд522 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, так и есть, прав был b707-  4-ый пин не сконфигурирован.

Только впредь выкладывайте код по правилам форума.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Prostovova пишет:

Схем простая:

Вас никто не спрашивал простая она или сложная. Вас просили её привести. Где?

Впрочем, про 4-ый пин Вам уже писали раньше, сейчас это подтвердилось.

Prostovova
Offline
Зарегистрирован: 17.10.2017

DetSimen пишет:

Вова, ты до сих пор код вставлять не научилса?  Как эту галиматью читать прикажешь?

Да

Всавлял по кнопке "вставить код"

Еще раз попробую:


#include <SoftwareSerial.h>                                   // Библиотека програмной реализации обмена по UART-протоколу
SoftwareSerial SIM800(8, 9);                                  // 8 - RX Arduino (TX SIM800L), 9 - TX Arduino (RX SIM800L)
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 12
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);


int pins[3] = {2, 3, 4};                                      // Пины с подключенными светодиодами

String _response    = "";                                     // Переменная для хранения ответа модуля
long lastUpdate = millis();                                   // Время последнего обновления
long updatePeriod   = 30000;                                  // Проверять каждst 30 сек

String phones = "+7916XXXXXXX, +7916XXXXXXX, +7918xxxxxxx";   // Белый список телефонов

void setup() {
  sensors.begin();                                            // запуск работы с температурными сенсорами
  for (int i = 0; i < 2; i++) {
    pinMode(pins[i], OUTPUT);                                 // Настраиваем пины в OUTPUT
  }
  Serial.begin(9600);                                         // Скорость обмена данными с компьютером
  SIM800.begin(9600);                                         // Скорость обмена данными с модемом
  Serial.println("Start!");

                       // Команды настройки модема при каждом запуске
  Serial.println("первоначальная настройка");
  sendATCommand("AT", true);                                  // Отправили AT для настройки скорости обмена данными
  sendATCommand("AT+CMGDA=\"DEL ALL\"", true);                // Удаляем все SMS, чтобы не забивать память
  sendATCommand("AT+CMGF=1;&W", true);                        // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  sendATCommand("ATE0", true);                                // Отключаем Echo Mode
  //sendATCommand("ATE1", true);                                // или включаем  Echo Mode 
  Serial.println("дальше работа");  
  lastUpdate = millis();                                      // Обнуляем таймер

  sensors.setResolution(9);                                   // устанавливаем точность датчиков Dallas 0,5°С 
}

String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                                           // Переменная для хранения результата
  // Serial.println(cmd);                                         // Дублируем команду в монитор порта
  SIM800.println(cmd);                                         // Отправляем команду модулю
  if (waiting) {                                               // Если необходимо дождаться ответа...
    _resp = waitResponse();                                    // ... ждем, когда будет передан ответ
    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;                                                // ... возвращаем результат. Пусто, если проблема
}

bool hasmsg = false;                                           // Флаг наличия сообщений к удалению
void loop() {
  // печать показаний датчиков в Serial
  // Serial.print("первый "); Serial.print(sensors.getTempCByIndex(0)); Serial.print("  второй "); Serial.print(sensors.getTempCByIndex(1));
  // Serial.print(" третий "); Serial.println(sensors.getTempCByIndex(2));

  if (lastUpdate + updatePeriod < millis() ) {                 // Пора проверить наличие новых сообщений
   Serial.print("первый "); Serial.print(sensors.getTempCByIndex(0)); Serial.print("  второй "); Serial.print(sensors.getTempCByIndex(1));
   Serial.print(" третий "); Serial.println(sensors.getTempCByIndex(2)); 
   Serial.print(digitalRead(2));    Serial.print(digitalRead(3)); Serial.println(digitalRead(4));  
    do {
      _response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений
      if (_response.indexOf("+CMGL: ") > -1) {                 // Если есть хоть одно, получаем его индекс
        int msgIndex = _response.substring(_response.indexOf("+CMGL: ") + 7, _response.indexOf("\"REC UNREAD\"", _response.indexOf("+CMGL: "))).toInt();
        char i = 0;                                            // Объявляем счетчик попыток
        do {
          i++;                                                 // Увеличиваем счетчик
          _response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true);  // Пробуем получить текст SMS по индексу
          _response.trim();                                    // Убираем пробелы в начале/конце
          if (_response.endsWith("OK")) {                      // Если ответ заканчивается на "ОК"
            if (!hasmsg) hasmsg = true;                        // Ставим флаг наличия сообщений для удаления
            sendATCommand("AT+CMGR=" + (String)msgIndex, true); // Делаем сообщение прочитанным
            sendATCommand("\n", true);                         // Перестраховка - вывод новой строки
            parseSMS(_response);                               // Отправляем текст сообщения на обработку
            break;                                             // Выход из do{}
          }
          else {                                               // Если сообщение не заканчивается на OK
            Serial.println ("Error answer");                   // Какая-то ошибка
            sendATCommand("\n", true);                         // Отправляем новую строку и повторяем попытку
          }
        } while (i < 10);
break;
      }
      else {
        lastUpdate = millis();                                 // Обнуляем таймер
        if (hasmsg) {
          sendATCommand("AT+CMGDA=\"DEL READ\"", true);        // Удаляем все прочитанные сообщения
          hasmsg = false;
        }
        break;
      }
    } while (1);
  }
  if (SIM800.available())   {                         // Если модем, что-то отправил...
    _response = waitResponse();                       // Получаем ответ от модема для анализа
    _response.trim();                                 // Убираем лишние пробелы в начале и конце
    Serial.println(_response);                        // Если нужно выводим в монитор порта
    if (_response.indexOf("+CMTI:")>-1) {             // Пришло сообщение об отправке SMS
      lastUpdate = millis() -  updatePeriod;          // Теперь нет необходимости обрабатываеть SMS здесь, достаточно просто
                                                      // сбросить счетчик автопроверки и в следующем цикле все будет обработано
    }             
    if (_response.indexOf("+7916XXXXXXX")>-1)                      // если в ответе присутствует заданный в этой строке номер
    {sendATCommand("ATH", true);setLedState("40","+7916XXXXXXX");} // то отправляем смс с данными о температуре
  }
  if (Serial.available())  {                          // Ожидаем команды по Serial...
    SIM800.write(Serial.read());                      // ...и отправляем полученную команду модему
  };
      sensors.requestTemperatures();                  // снимаем показания датчика температуры
}

void parseSMS(String msg) {                                   // Парсим SMS
  String msgheader  = "";
  String msgbody    = "";
  String msgphone   = "";

  msg = msg.substring(msg.indexOf("+CMGR: "));
  msgheader = msg.substring(0, msg.indexOf("\r"));            // Выдергиваем телефон

  msgbody = msg.substring(msgheader.length() + 2);
  msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK"));  // Выдергиваем текст SMS
  msgbody.trim();

  int firstIndex = msgheader.indexOf("\",\"") + 3;
  int secondIndex = msgheader.indexOf("\",\"", firstIndex);
  msgphone = msgheader.substring(firstIndex, secondIndex);

  Serial.println("Phone sender: " + msgphone);                // Выводим номер телефона
  Serial.println("Message: " + msgbody);                      // Выводим текст SMS

  if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) { // Если телефон в белом списке, то...
    setLedState(msgbody, msgphone);                           // ...выполняем команду
  }
  else {
    Serial.println("Unknown phonenumber");
    }
}

void setLedState (String result, String phone) {              // функция реагирования на входящие СМС - 3 светодиода и замер температуры
  bool correct = false;                                       // Для оптимизации кода, переменная корректности команды
  String msgToSend = "";
  if (result.length() == 2) {
    int ledIndex = ((String)result[0]).toInt();               // Получаем первую цифру команды - адрес устройства (1-3)
    int ledState = ((String)result[1]).toInt();               // Получаем вторую цифру команды - состояние (0 - выкл, 1 - вкл)
    if (ledIndex >= 1 && ledIndex <= 3 && (ledState == 0 or ledState == 1)) // Если все нормально, шлем смс и исполняем команду
    { 
      msgToSend = "LED:" + (String)ledIndex + " set to " + (ledState == 0 ? "OFF" : "ON"); // Статус исполнения
      digitalWrite(pins[ledIndex - 1], ledState);             // Исполняем команду
      correct = true;                                         // Флаг корректности команды
    }
      
      //путь через Ж:  по входящему звонку с моего  номера имитируем приходящее смс "40" 
      else if (ledIndex == 4) // Если это запрос на температуру ("40" или "41")
      { 
      msgToSend = "Temper 1: "+ (String)sensors.getTempCByIndex(0) + " 2: " + (String)sensors.getTempCByIndex(1) + " 3: " +  (String)sensors.getTempCByIndex(2) + " Relay  1: " +(String)digitalRead(2)  + " 2: " +(String)digitalRead(3)  + " 3: " +(String)digitalRead(4) ; // то формируем строку ответа
      correct = true;                                         // Флаг корректности команды
      } 
     
  }
  if (!correct) {
    msgToSend = "Incorrect command: " + result;               // Статус исполнения
  }
  sendSMS ("+7916XXXXXXX" , msgToSend);                            // ответное СМС
}


void sendSMS(String phone, String message)
{
  sendATCommand("AT+CMGS=\"" + phone + "\"", true);             // Переходим в режим ввода текстового сообщения
  sendATCommand(message + "\r\n" + (String)((char)26), true);   // После текста отправляем перенос строки и Ctrl+Z
}

b707
Offline
Зарегистрирован: 26.05.2017

Prostovova, у вас странная манера отвечать в ветке - как-то невпопад все время...

Ошибку-то свою поняли? Вопрос закрыт?

Prostovova
Offline
Зарегистрирован: 17.10.2017

Ура!

Заработала!

  for (int i = 0; i < 3; i++) {
  pinMode(pins[i], OUTPUT);}      

Спасибо!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Prostovova пишет:

Ура!

Заработала!

  for (int i = 0; i < 3; i++) {
  pinMode(pins[i], OUTPUT);}      

Спасибо!

существует 99 способов, можно и так, а вообще я бы за такой код отправлял на лесоповал, что показываете? умение пользоваться массивами...в языке это называется косноязычие

for (int i = 0; i <=2; i++) {
pinMode(pins[i], OUTPUT);} 

 

а вот такая рукожопая запись использует памяти поменьше
 

int pins[3] = {2, 3, 4};

void setup() {
  
       pinMode(pins[1], OUTPUT); 
       pinMode(pins[2], OUTPUT); 
       pinMode(pins[3], OUTPUT); 
    }
   

void loop() {
  // put your main code here, to run repeatedly:

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Prostovova пишет:

Ура!

Заработала!

Самое время подумать, а нахрена там массив int pins[3] = {2, 3, 4}; ? Может, без него?

for (int i = 2; i <= 4; pinMode(i++, OUTPUT));

И всего делов?

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Самое время подумать, а нахрена там массив int pins[3] = {2, 3, 4}; ? Может, без него?

for (int i = 2; i <= 4; pinMode(i++, OUTPUT));

И всего делов?

не, если отвлечься от экономии одной строчки в коде, я бы оставил массив. Пины же могут оказаться не подряд... а вдруг какой-то из них нужно будет изменить?

Нет, явное задание пинов мне больше нравится. Более того, для трех штук я бы и цикл выкинул - просто три раза написал бы pinMode(pin, OUTPUT);

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, я тоже пины храню в массиве... Можно вразнобой накидывать, местами менять, добавлять, убавлять, потом циклом по (sizeof()/sizeof(pins[0]) инитить. 

Мне так больше нравится.

Prostovova
Offline
Зарегистрирован: 17.10.2017

А мне понравился способ. Для меня - не очевидно (я бы то же задал через pinMode). Учитывая дефицит памяти, каждая  сэкономленная строчка - это есть хорошо. Наверняка захочется еще что то сюда прикрутить и с моими навыками точно лучше заранее сэкономить.

Если к началу - штука задумана на дачу. Управление 3-мя нагрузками и измерение температуры в 3-х точках (на улице, в доме и отдельно в санузле). Например полив (это про лето) и 2 нагревателя (это чтобы зимой прогреть домик к приезду)

Есть мысль прикрутить датчик BME280 для измерения давления в бочке и пересчета по нему объема воды в бочке. диапазон изменения глубины от 0 до 1,5 метра, объем соответственно от 0 до 4 м.куб. Пока прорабатываю конструктив (все должно быть предельно герметично). Здесь даже код почти готов - и он потребует каких то ресурсов. Но прежде чем прикручивать его сюда надо все отмакетировать и оттестировать - есть много сомнений.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А если массив ещё и константным сделать, то компилятор его и без нас выбросит :)))

b707
Offline
Зарегистрирован: 26.05.2017

Prostovova пишет:

Учитывая дефицит памяти, каждая  сэкономленная строчка - это есть хорошо. Наверняка захочется еще что то сюда прикрутить и с моими навыками точно лучше заранее сэкономить.

Если к началу - штука задумана на дачу. Управление 3-мя нагрузками и измерение температуры в 3-х точках (на улице, в доме и отдельно в санузле). Например полив (это про лето) и 2 нагревателя (это чтобы зимой прогреть домик к приезду)

все перечисленное примерно требует трети ресурсов Уно :)

Prostovova
Offline
Зарегистрирован: 17.10.2017

А, что подскажут многоуважаемые Гуру?

В коде есть очень неудобочитаемая строка. Как бы ее сделать посимпатичнее и нагляднее?

 msgToSend = "Temper 1: "+ (String)sensors.getTempCByIndex(0) + " 2: " + (String)sensors.getTempCByIndex(1) + " 3: " +  (String)sensors.getTempCByIndex(2) + " Relay  1: " +(String)digitalRead(2)  + " 2: " +(String)digitalRead(3)  + " 3: " +(String)digitalRead(4) ; // то формируем строку ответа

результат от нее такой:

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Prostovova пишет:

А, что подскажут многоуважаемые Гуру?

Подскажут идти и читать Кернигана и Ритчи.

А строку разбить на куски переводом строки там, где кажется красивше.

b707
Offline
Зарегистрирован: 26.05.2017

строку переписать на нормальном человеческом языке - как сам код, так и результат вывода...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Ну, я тоже пины храню в массиве... Можно вразнобой накидывать, местами менять, добавлять, убавлять, потом циклом по (sizeof()/sizeof(pins[0]) инитить. 

Мне так больше нравится.


Это конечно красиво, когда  код сам формирует "программный код", для устройств с "неограниченными ресурсами",  но мне кажется для микроконтроллеров программировать надо так, чтобы расходовать ресурсы минимально, к примеру можно задать алгоритм расчета константы и использовать его, а можно просто вычислить константу и пользоваться оной, так вот второе - правильно, первое - нет!

sadman41
Offline
Зарегистрирован: 19.10.2016

Так я по-всякому делаю - бывает, что давлю из последних сил байты из МК , меняя switch() на if().

Но не думаю, что стоит всегда экономить на спичках и устраивать hardcode party, когда остается еще 50% прогмема и при этом можно сделать легкое увеличение количества обрабатываемых входных каналов (к примеру) добавлением одной цифири в массив с пинами.

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Так я по-всякому делаю - бывает, что давлю из последних сил байты из МК , меняя switch() на if().

Но не думаю, что стоит всегда экономить на спичках и устраивать hardcode party, когда остается еще 50% прогмема и при этом можно сделать легкое увеличение количества обрабатываемых входных каналов (к примеру) добавлением одной цифири в массив с пинами.

я заинтересовался микроконтроллерами после устройств с жёсткой логикой, привычка на всём экономить, для меня 1 килобайт ассемлерного кода это просто колоссально много (по функционалу)

а хардкорд - это к Юре Панчулу, он тексты парсит чистой логикой и никаких микропроцессоров, триггера и логика )))

sadman41
Offline
Зарегистрирован: 19.10.2016

Некоторые африканские племена до сих пор зерна на каменных жерновах перетирают, не строят никакие заводы с мозговыносящей логистикой и двадцатью бухгалтерами в штате ;)  Хорошо это или плохо - who knows... Наверное, если на Замлю упадет метеорит, то мы со своими заводами вымрем, а они еще лет пятьсот будут крутить жернова.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Некоторые африканские племена до сих пор зерна на каменных жерновах перетирают, не строят никакие заводы с мозговыносящей логистикой и двадцатью бухгалтерами в штате ;)  Хорошо это или плохо - who knows... Наверное, если на Замлю упадет метеорит, то мы со своими заводами вымрем, а они еще лет пятьсот будут крутить жернова.


у нас заводов нет, за исключением пожалуй дервейса

Prostovova
Offline
Зарегистрирован: 17.10.2017

Я прошу прощения, возможно это уже не аппаратный вопрос.

Кде то какой то косяк. Эта вся штука не работает как просили без подключения к компу. То есть, когда плата подключена к компу и отурыт монитор порта - все работает (звоню - отбивает вызов и шлет СМС). Автономно - без подключения к кмпьютеру - вызов проходит, отбоя и ответной смс нет

Код тот же.

/*
 * что умеет:
 * по входящим СМС с номеров xxxxxxx и xxxxxxx
 * управляет 3-мя реле
 * смс соответственно 10 20 30 - выключить, 11 21 31 - включить
 * измеряет температуру 3-мя датчиками "Dallas" на одной шине
 * информацию передает СМС-кой в ответ на вызов с указанных номеров или СМС "40" с них же
 * 
 */

#include <SoftwareSerial.h>                                   // Библиотека програмной реализации обмена по UART-протоколу
SoftwareSerial SIM800(8, 9);                                  // 8 - RX Arduino (TX SIM800L), 9 - TX Arduino (RX SIM800L)
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 12
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);


int pins[3] = {2, 3, 4};                                      // Пины с подключенными светодиодами

String _response    = "";                                     // Переменная для хранения ответа модуля
long lastUpdate = millis();                                   // Время последнего обновления
long updatePeriod   = 30000;                                  // Проверять каждst 30 сек

String phones = "+7916xxxxxxx, +7916xxxxxxx, +7918xxxxxxx";   // Белый список телефонов

void setup() {
  sensors.begin();                                            // запуск работы с температурными сенсорами
  for (int i = 0; i < 3; i++) {
    pinMode(pins[i], OUTPUT);                                 // Настраиваем пины в OUTPUT
  }
  Serial.begin(9600);                                         // Скорость обмена данными с компьютером
  SIM800.begin(9600);                                         // Скорость обмена данными с модемом
  Serial.println("Start!");

                       // Команды настройки модема при каждом запуске
  Serial.println("первоначальная настройка");
  sendATCommand("AT", true);                                  // Отправили AT для настройки скорости обмена данными
  sendATCommand("AT+CMGDA=\"DEL ALL\"", true);                // Удаляем все SMS, чтобы не забивать память
  sendATCommand("AT+CMGF=1;&W", true);                        // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  sendATCommand("ATE0", true);                                // Отключаем Echo Mode
  //sendATCommand("ATE1", true);                                // или включаем  Echo Mode 
  Serial.println("дальше работа");  
  lastUpdate = millis();                                      // Обнуляем таймер

  sensors.setResolution(9);                                   // устанавливаем точность датчиков Dallas 0,5°С 
}

String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                                           // Переменная для хранения результата
                                     // Serial.println(cmd);   // Дублируем команду в монитор порта
  SIM800.println(cmd);                                         // Отправляем команду модулю
  if (waiting) {                                               // Если необходимо дождаться ответа...
    _resp = waitResponse();                                    // ... ждем, когда будет передан ответ
    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;                                                // ... возвращаем результат. Пусто, если проблема
}

bool hasmsg = false;                                           // Флаг наличия сообщений к удалению
void loop() {
  // печать показаний датчиков в Serial
  // Serial.print("первый "); Serial.print(sensors.getTempCByIndex(0)); Serial.print("  второй "); Serial.print(sensors.getTempCByIndex(1));
  // Serial.print(" третий "); Serial.println(sensors.getTempCByIndex(2));

  if (lastUpdate + updatePeriod < millis() ) {                 // Пора проверить наличие новых сообщений
   Serial.print("первый "); Serial.print(sensors.getTempCByIndex(0)); Serial.print("  второй "); Serial.print(sensors.getTempCByIndex(1));
   Serial.print(" третий "); Serial.println(sensors.getTempCByIndex(2)); 
   Serial.print(digitalRead(2));    Serial.print(digitalRead(3)); Serial.println(digitalRead(4));  
    do {
      _response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);// Отправляем запрос чтения непрочитанных сообщений
      if (_response.indexOf("+CMGL: ") > -1) {                 // Если есть хоть одно, получаем его индекс
        int msgIndex = _response.substring(_response.indexOf("+CMGL: ") + 7, _response.indexOf("\"REC UNREAD\"", _response.indexOf("+CMGL: "))).toInt();
        char i = 0;                                            // Объявляем счетчик попыток
        do {
          i++;                                                 // Увеличиваем счетчик
          _response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true);  // Пробуем получить текст SMS по индексу
          _response.trim();                                    // Убираем пробелы в начале/конце
          if (_response.endsWith("OK")) {                      // Если ответ заканчивается на "ОК"
            if (!hasmsg) hasmsg = true;                        // Ставим флаг наличия сообщений для удаления
            sendATCommand("AT+CMGR=" + (String)msgIndex, true); // Делаем сообщение прочитанным
            sendATCommand("\n", true);                         // Перестраховка - вывод новой строки
            parseSMS(_response);                               // Отправляем текст сообщения на обработку
            break;                                             // Выход из do{}
          }
          else {                                               // Если сообщение не заканчивается на OK
            Serial.println ("Error answer");                   // Какая-то ошибка
            sendATCommand("\n", true);                         // Отправляем новую строку и повторяем попытку
          }
        } while (i < 10);
break;
      }
      else {
        lastUpdate = millis();                                 // Обнуляем таймер
        if (hasmsg) {
          sendATCommand("AT+CMGDA=\"DEL READ\"", true);        // Удаляем все прочитанные сообщения
          hasmsg = false;
        }
        break;
      }
    } while (1);
  }
  if (SIM800.available())   {                         // Если модем, что-то отправил...
    _response = waitResponse();                       // Получаем ответ от модема для анализа
    _response.trim();                                 // Убираем лишние пробелы в начале и конце
    Serial.println(_response);                        // Если нужно выводим в монитор порта
    if (_response.indexOf("+CMTI:")>-1) {             // Пришло сообщение об отправке SMS
      lastUpdate = millis() -  updatePeriod;          // Теперь нет необходимости обрабатываеть SMS здесь, достаточно просто
                                                      // сбросить счетчик автопроверки и в следующем цикле все будет обработано
    }             
    if (_response.indexOf("+7916xxxxxxx")>-1)                      // если в ответе присутствует заданный в этой строке номер
    {sendATCommand("ATH", true);setLedState("40","+7916xxxxxxx");} // то отправляем смс с данными о температуре
  }
  if (Serial.available())  {                          // Ожидаем команды по Serial...
    SIM800.write(Serial.read());                      // ...и отправляем полученную команду модему
  };
      sensors.requestTemperatures();                  // снимаем показания датчика температуры
}

void parseSMS(String msg) {                                   // Парсим SMS
  String msgheader  = "";
  String msgbody    = "";
  String msgphone   = "";

  msg = msg.substring(msg.indexOf("+CMGR: "));
  msgheader = msg.substring(0, msg.indexOf("\r"));            // Выдергиваем телефон

  msgbody = msg.substring(msgheader.length() + 2);
  msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK"));  // Выдергиваем текст SMS
  msgbody.trim();

  int firstIndex = msgheader.indexOf("\",\"") + 3;
  int secondIndex = msgheader.indexOf("\",\"", firstIndex);
  msgphone = msgheader.substring(firstIndex, secondIndex);

  Serial.println("Phone sender: " + msgphone);                // Выводим номер телефона
  Serial.println("Message: " + msgbody);                      // Выводим текст SMS

  if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) { // Если телефон в белом списке, то...
    setLedState(msgbody, msgphone);                           // ...выполняем команду
  }
  else {
    Serial.println("Unknown phonenumber");
    }
}

void setLedState (String result, String phone) {              // функция реагирования на входящие СМС - 3 светодиода и замер температуры
  bool correct = false;                                       // Для оптимизации кода, переменная корректности команды
  String msgToSend = "";
  if (result.length() == 2) {
    int ledIndex = ((String)result[0]).toInt();               // Получаем первую цифру команды - адрес устройства (1-3)
    int ledState = ((String)result[1]).toInt();               // Получаем вторую цифру команды - состояние (0 - выкл, 1 - вкл)
    if (ledIndex >= 1 && ledIndex <= 3 && (ledState == 0 or ledState == 1)) // Если все нормально, шлем смс и исполняем команду
    { 
      msgToSend = "LED:" + (String)ledIndex + " set to " + (ledState == 0 ? "OFF" : "ON"); // Статус исполнения
      digitalWrite(pins[ledIndex - 1], ledState);             // Исполняем команду
      correct = true;                                         // Флаг корректности команды
    }
      
      //путь через Ж:  по входящему звонку с моего  номера имитируем приходящее смс "40" 
      else if (ledIndex == 4) // Если это запрос на температуру ("40" или "41")
      { 
        msgToSend =                                           // то формируем строку ответа
        "Temper 1="  +(String)sensors.getTempCByIndex(0) +
        "; 2="        +(String)sensors.getTempCByIndex(1) + 
        "; 3="        +(String)sensors.getTempCByIndex(2) + 
        " Relay  1=" +(String)digitalRead(2)  + 
        "; 2="        +(String)digitalRead(3)  + 
        "; 3="        +(String)digitalRead(4) ;                // и заканчиваем формировать строку ответа
      correct = true;                                         // Флаг корректности команды
      } 
     
  }
  if (!correct) {
    msgToSend = "Incorrect command: " + result;               // Статус исполнения
  }
  sendSMS ("+7916xxxxxxx" , msgToSend);                            // ответное СМС
}


void sendSMS(String phone, String message)
{
  sendATCommand("AT+CMGS=\"" + phone + "\"", true);             // Переходим в режим ввода текстового сообщения
  sendATCommand(message + "\r\n" + (String)((char)26), true);   // После текста отправляем перенос строки и Ctrl+Z
}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Prostovova пишет:

Я прошу прощения, возможно это уже не аппаратный вопрос.

Кде то какой то косяк. Эта вся штука не работает как просили без подключения к компу. То есть, когда плата подключена к компу и отурыт монитор порта - все работает (звоню - отбивает вызов и шлет СМС). Автономно - без подключения к кмпьютеру - вызов проходит, отбоя и ответной смс нет

Код тот же.

А как работает, если подключить к компу, но не открывать монитор порта?

Prostovova
Offline
Зарегистрирован: 17.10.2017

Нормально работает - как просили...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Тогда, вероятнее всего, проблема с питанием.

Prostovova
Offline
Зарегистрирован: 17.10.2017

Фиг знает

Закомментировал всё, что связано с выводом в порт, все Serial.print, включая:

128   if (Serial.available())  {                          // Ожидаем команды по Serial...
129     SIM800.write(Serial.read());                      // ...и отправляем полученную команду модему
130   };

Вроде заработала.

Хотя наверно только это то и стоило....

Проверил. Так и есть. Закомметировал только эти строки и всё заработало.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ещё бы! Если без байта пришедшего из сериала Вы ни хрена не отправляете!:)