Все о SIM800L и все что с ним связано.

kostyamat
Offline
Зарегистрирован: 16.11.2017

alexbmd пишет:

добрый день.

в ДШ упоминается PWRKEY пин. но на выводах сим800 такого нету.  есть варианты как можно программно его выключать /включать ?

на модулях не выведенно, а программно - вот прямо над вашим постом, который я процитировал.

alexbmd
Offline
Зарегистрирован: 15.01.2016

Спасибо, сообщение видел. Там речь про спящий режим. Меня больше интересует полное отключение через power key

nhs
Offline
Зарегистрирован: 28.07.2019

andycat пишет:
Это вы батенька их готовить не умеете. Несколько десятков устройств ездит по стране вообще без проблем. Завтра посторяюсь выложить схему соединения nano и sim800 какую я использую - все отлично работает в любых режимах.

Готовка не обязательно влияет на результат. Пример 6 (шести) модулей - https://www.amazon.de/AZDelivery-⭐⭐⭐⭐⭐-SIM800L-Antenne-Arduino/dp/B07D361WZV/

Из шести три прекрасно запитались от +5в, живут замечательно (хотя скорее всего это просто over-voltage protection в модулях не работает как надо). Два из них запускаются и живут от 3.3v.

Ещё один от 5в моргает два раза при включении и всё (over-voltage protection сработал). От ~4v работает.

Ещё один от 5в моргает уже не два, а три раза при включении (опять over-voltage protection сработал).

Итого: очень большой разброс, каждый модуль сам по себе.

kostyamat
Offline
Зарегистрирован: 16.11.2017

А в чем суть подбора модуля из шести - работает/не работает овервольтаж? Если есть отлично зарекомендовавший себя способ запитать модуль от 5в через обычный кремниевый диод, и получить на нем 4.2-4.4 вольта, от которых он работает всегда, и без сбоев?

nhs
Offline
Зарегистрирован: 28.07.2019

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

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

А если из 20+ модемов, подключённых по даташиту работают 100 % это типа не правильно)))

nhs
Offline
Зарегистрирован: 28.07.2019

andycat пишет:
А если из 20+ модемов, подключённых по даташиту работают 100 % это типа не правильно)))

Это охрененно правильно и Вы везунчик (ну или типа того)

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Это не везение, а правильное подключение и правильный продавец модемов.

nhs
Offline
Зарегистрирован: 28.07.2019

andycat пишет:
Это не везение, а правильное подключение и правильный продавец модемов.

Судя по всему Вы большой специалист по подключению и по выбору продавца. Прямо таки завидую Вам !

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Небольшая библиотека для работы с Sim800L, функционал:

- прием и отправка SMS

- прием входящих звонков и обработка DTMF нажатий

В проекте добавление следующих действий:

- отправка GET запросов и чтение возвращаемой странички HTML

- пакетная прием-передача данных -> общение с MQTT сервером

Скетч из 4х файлов, первый - пример использования с комментариями, остальные - сама библиотека.

Обработка ответов из модема online - в каждом проходе loop, соответственно категорически не рекомендуется сильно задерживать цикл своими обработчиками.

#include <avr/wdt.h>
#include "sim800lib.h"

unsigned long currentMillis; // главный таймер для запуска операций по времени

s800lib s800l; // объект библиотеки Sim800L

#define period_read_sms 120000UL // каждые 2 минуты читаем СМС
unsigned long timer_read_sms;
#define max_size_sender (byte)16
char sender[max_size_sender]; // отправитель
#define max_size_textsms (byte)32
char textsms[max_size_textsms]; // текст СМС, максимум 255, если необходимо больше - переписывать библиотеку
#define period_send_sms 6003537UL // через 100 минут отправляем тестовую СМС
unsigned long timer_send_sms; byte fl_send_sms = 1; // один раз

uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
void get_mcusr(void) \
__attribute__((naked)) \
__attribute__((used)) \
__attribute__((section(".init3")));
void get_mcusr(void)
{
  mcusr_mirror = MCUSR;
  MCUSR = 0;
  wdt_disable();
}

void setup() {
  MCUSR = 0; wdt_disable(); // отключение Watch Dog Timer
  // put your setup code here, to run once:
#ifdef USE_SOFTWARESERIAL
  Serial.begin(115200); // инициализируем аппаратный UART для вывода сообщений
#endif
  s800l.initModem(false); // запуск модема. C использованием GPRS? true/false
  wdt_enable(WDTO_8S); // запуск WDT
}

void loop() {
  wdt_reset(); // сброс WDT
  //Serial.println("Start"); delay(9000); // test WDT
  currentMillis = millis(); // присвоим таймеру текущее значение МК
  // put your main code here, to run repeatedly:
  if (s800l.workModem()) { // модем в работе, что то или пришло или требует внимания программы/пользователя или ошибка
    if (s800l.getModemReport() == errTimeOut) { // обрабатываем ошибку модема (таймаут по ответу на команду)
      Serial.print("Error timeout on command = "); Serial.println(s800l.getModemCmd(), DEC);
      switch (s800l.getModemActions()) { // выбираем реакцию в зависимости от текущего действия
        case initATmodem: {
            Serial.println("Reset modem."); s800l.resetModem(); s800l.initModem(false); break; // перезапускаем модем
          }
        case delSMS: {
            s800l.clearAction(); break; // продолжаем работать
          }
        case readSMS: {
            s800l.clearAction(); break; // продолжаем работать
          }
        case sendSMS: {
            s800l.clearAction(); break; // продолжаем работать
          }
        case waitDTMF: {
            s800l.clearAction(); break; // продолжаем работать
          }
        default: {};
      }
    } else if  (s800l.getModemReport() == noGPRS)   { // GPRS не поддерживается
      Serial.println("GPRS not supported. Reset modem.");
      s800l.resetModem(); s800l.initModem(false); // перезагружаемся без поддержки GPRS
    } else if (s800l.getModemReport() == oneSMS) { // получили СМС - обрабатываем
      Serial.println(sender);
      Serial.println(textsms);
    } else if (s800l.getModemReport() == keyPressDTMF) { // прилетела нажатая цифра
      Serial.print("Pressed key "); Serial.println(s800l.getKeyDTMF()); // обрабатываем нажатую кнопку
    } else { // смотрим другие ответы

    }
  } else { // модем ничем не занят, можно делать что то свое
    // отправка СМС, чтение СМС, запрос USSD, отправка GET запроса, вывод в монитор порта каких то своих данных и т.д.
    switch (s800l.getModemReport()) { // обрабатываем ответы модема
      case initReady: { // успешно запустили модем
          Serial.println("Ready");
          s800l.deleteAllSMS(); // удалим все СМС при старте
          break;
        }
      case existSMS: { // все СМС прочитаны и обработаны
          s800l.deleteAllSMS(); // удалим все СМС
          break;
        }
      case incomingCall: { // входящий звонок
          // получаем номер звонящего абонента
          Serial.print("Incoming call from "); Serial.println(s800l.getPhoneNumber());
          // анализируем номер и решаем что делать дальше или просто игнорируем звонок
          s800l.waitPressDTMF(); // снимаем трубку и ждем команд DTMF
          break;
        }
      default: { // делаем что то свое
          // --- читаем СМС по таймеру
          if ((currentMillis - timer_read_sms) >= period_read_sms) {
            timer_read_sms = currentMillis; s800l.readAllSMS(sender, max_size_sender, textsms, max_size_textsms);
          }
          // --- отправляем СМС по таймеру
          if (fl_send_sms) {
            if ((currentMillis - timer_send_sms) >= period_send_sms) {
              fl_send_sms = 0; timer_send_sms = currentMillis; s800l.sendSimpleSMS((char *)"7900***8478", (char *)"Proba");
            }
          }
          // --- конец своих действий
        };
    }
  }
  // делаем что то свое, не задерживаем поток, не рекомендуется использовать здесь вывод чего лобо в монитор порта
}

-

//---sim800lib.h---
#include <arduino.h>
#include "sim800cmd.h"

#define USE_SOFTWARESERIAL // используем программный UART для работы с модемом
//#define SHOW_MODEM_RESPONSE // отображать ответы модема (используется только при отладке если есть проблемы)
#ifdef USE_SOFTWARESERIAL
#include <SoftwareSerial.h>
#define GSM_RX (byte)3 // пин RX на модуле подключаем к указаному пину на Ардуино TX
#define GSM_TX (byte)2 // пин TX на модуле подключаем к указаному пину на Ардуино RX
#endif
#define reset_sim800_pin (byte)4 // pin for reset modem // нога сброса модема
#define dtr_sim800_pin (byte)10 // pin DTR for sleep mode // нога DTR модема
#define modem_speed (word)9600 // скорость обмена с модемом
#define max_size_response_buf (byte)16 // размер буфера ответа от модема, должен быть чуть больше максимальной строки поиска, например SEND OK, ERROR, OK и т.д. для стандартных команд
#define max_size_phone_number (byte)16 // размер буфера телефона абонента входящего звонка
#define max_size_cmd_buf (byte)40 // размер буфера команд модема, должен быть чуть больше максимальной строки команды
#define periodWaitInit 15000UL // сколько дать времени модему на регистрацию в сети после включения или сброса
#define periodSimpleResponse 3000UL // время ожидания простой команды
#define periodReadSMS 30000UL // время ожидания чтения СМС
#define periodSendSMS 30000UL // время ожидания отправки СМС
#define periodWaitDTMF 60000UL // время ожидания сигналов DTMF

// в каком действии сейчас находится модем (начало, инициализация, чтение смс, отправка смс и т д
enum modemActions {waitInit/*ожидание после включения Х секунд*/,
                   initATmodem/*отправка на модем настроечных AT команд*/,
                   doNothing/*ничего не делаем - обнуляем после обработки ответа*/,
                   delSMS/*удаляем все СМС*/,
                   readSMS/*читаем все смс*/,
                   sendSMS/*отправка СМС*/,
                   waitDTMF/*ожидание команд при входящем звонке*/
                  };
// ответы обработчика
enum modemReport {noReport/*нет ответа - все хорошо*/,
                  initReady/*Успешная инициализация модема - просто работаем*/,
                  errTimeOut/*за X время нет успешного ответа на команду*/,
                  noGPRS/*на SIM ке или не включен или не поддерживается пакетная передача данных*/,
                  noSMS/*нет SMS*/,
                  existSMS/*все SMS прочитаны*/,
                  oneSMS/*получено одно СМС*/,
                  incomingCall/*входящий звонок*/,
                  keyPressDTMF/*нажата кнопка DTMF*/
                 };

class s800lib
{
  private:
    /* список свойств и методов для использования внутри класса */
    bool _use_gprs; // использовать интернет
    char resp_buf[max_size_response_buf]; // буфер ответов от модема
    char phone_buf[max_size_phone_number]; // буфер телефонного номера
    byte pos_buf; // текущая позиция буфера ответов
    unsigned long modemMillis; // таймер модема - используется один таймер на все команды
    modemActions currentAction; // текущее состояние модема
    modemReport currentReport; // текущий ответ после выхода обработчика
    void clearRespBuf(); // очистка приемного буфера
    byte _current_cmd; // текущая выполняемая команда - команда которую надо запустить - значение 101=выход из пакета команд
    byte _next_cmd; // следующая выполняемая команда
    void sendATcmd(); // отправка команды модему
    bool findResp(char * inStr, byte inByte); // поиск в циклическорм буфере ответа ОК
    char * _sms_sender;
    byte _max_size_sender;
    char * _sms_text;
    byte _max_size_sms_text;
    byte _sms_count, _sms_step, _ring_step;
    bool processSMS(byte inByte); // обработка СМС
    byte _inc_ring; // 1 если пришло RING
    byte _dtmf_press; // 1 если пришло +DTMF:
    char _dtmf_key;
  public:
    /* список методов доступных другим функциям и объектам программы */
    void initModem(bool useGPRS); // начальная инициализация пинов модема, отправка первоначальных команд настройки модема
    void resetModem(); // сброс модема
    bool workModem(); // основная работа с модемом в loop
    modemActions getModemActions(); // возвращает текущую операцию
    modemReport getModemReport(); // возвращает ответ операции
    byte getModemCmd(); // возвращает номер текущей команды модема
    void clearAction(); // сброс текущего действия модема
    void deleteAllSMS(); // удалить все СМС
    void readAllSMS(char * bufSender, byte maxSender, char * bufText, byte maxText); // прочитать все СМС
    void sendSimpleSMS(char * bufSender, char * bufText); // отправка SMS в не PDU фармате
    char * getPhoneNumber(); // получить телефонный номер входящего звонка
    void waitPressDTMF(); // снимаем трубку при звонке и ждем нажатия кнопок
    char getKeyDTMF(); // возвращает нажатую кнопку
  protected:
    /*список средств, доступных при наследовании*/
};

-

//---sim800lib.cpp---
#include "sim800lib.h"

#ifdef USE_SOFTWARESERIAL
SoftwareSerial gsm(GSM_TX, GSM_RX); // установка контактовGSM_TX->RX и GSM_RX->TX для программного порта
#endif

void s800lib::initModem(bool useGPRS) { // начальная инициализация пинов модема, отправка первоначальных команд настройки модема
#ifdef USE_SOFTWARESERIAL
  gsm.begin(modem_speed);
#else
  Serial.begin(modem_speed);
#endif
  pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // гасим встроенный светодиод
  pinMode(reset_sim800_pin, INPUT); digitalWrite(reset_sim800_pin, LOW); // ногу сброса отключаем - рабочий режим
  pinMode(dtr_sim800_pin, OUTPUT); digitalWrite(dtr_sim800_pin, LOW); // normal mode modem // все модули модема включены
  currentAction = waitInit; // ждем как модем зарегестрируется в сети
  _use_gprs = useGPRS; // использование GPRS
  modemMillis = millis(); // обнулим таймер
  _inc_ring = 0; // нет входящего звонка
}

void s800lib::resetModem() { // сброс модема
  pinMode(reset_sim800_pin, OUTPUT);
  delay(115);
  pinMode(reset_sim800_pin, INPUT);
}

void s800lib::clearRespBuf() { // очистка приемного буфера
  memset(resp_buf, 0, max_size_response_buf);
  pos_buf = 0;
}

bool s800lib::workModem() { // основная работа, возвращает true если что то или пришло или ошибка или все ок, false если нечего модему делать
  currentReport = noReport; // сбрасываем ответ при каждом входе
  // обрабатваем каждый байт ответа
  byte br = 0;
#ifdef USE_SOFTWARESERIAL
  if (gsm.available()) br = gsm.read();
#else
  if (Serial.available()) br = Serial.read();
#endif
  if (br) {
    // запись байта в буфер
    resp_buf[pos_buf] = br; // записали
    ++pos_buf; // увеличили счетчик
    if (pos_buf >= max_size_response_buf) pos_buf = 0; // если дошло до максимума - обнуляем
  }
  switch (currentAction) { // отрабатываем все действия раздельно
    case waitInit: {
        if ((millis() - modemMillis) >= periodWaitInit) { // закончили ожидание регистрации модема - запускаем первые команды инициализации
          currentAction = initATmodem; // будем отправлять команды инициализации модема
          _current_cmd = 0; // запускаем нулевую команду
          s800lib::sendATcmd(); // отправить команду модему
        }
        break;
      }
    case initATmodem: {
        // проверяем таймаут
        if ((millis() - modemMillis) >= periodSimpleResponse) {
          currentReport = errTimeOut; return true; // прописываем код ответа и выходим
        }
        if (br) {
#ifdef SHOW_MODEM_RESPONSE
          Serial.write(br);
#endif
          if (_use_gprs) { // проверяем работает ли пакетная передача данных
            if (_current_cmd == 9) { // на нужной команде ищем подстроку
              if (s800lib::findResp((char *)"+CGATT: 0\r\n", br)) {
                currentReport = noGPRS; return true; // прописываем код ответа и выходим
              }
            }
          }
          if (s800lib::findResp((char *)"OK\r\n", br)) {
            if (_next_cmd == 101) { // конец цикла инициализации
              if (_use_gprs) { // продолжить команды настройки GPRS ?
                if (_current_cmd == 8) { // последняя команда инициализации
                  _current_cmd = 9; s800lib::sendATcmd(); // запускаем настройку gprs
                } else {
                  currentReport = initReady; s800lib::clearAction(); return false; // успешно настроили модем. обнулили текущее действие и вышли
                }
              } else {
                currentReport = initReady; s800lib::clearAction(); return false; // успешно настроили модем. обнулили текущее действие и вышли
              }
            } else { // запускаем следующую команду
              _current_cmd = _next_cmd; s800lib::sendATcmd();
            }
          }
        }
        break;
      }
    case waitDTMF: { // ждем нажатия кнопок на телефоне
        // проверяем таймаут
        if ((millis() - modemMillis) >= periodWaitDTMF) {
          currentReport = errTimeOut; return true; // прописываем код ответа и выходим
        }
        if (br) {
#ifdef SHOW_MODEM_RESPONSE
          Serial.write(br);
#endif
          if (s800lib::findResp((char *)"NO CARRIER\r\n", br)) {
            s800lib::clearAction(); return false; // успешно выходим
          }
          if (s800lib::findResp((char *)"+DTMF: ", br)) { // кнопка нажата
            _dtmf_press = 1;
          }
          if (_dtmf_press) {
            if ((isdigit(br)) || (br == '#') || (br == '*')) {
              _dtmf_press = 0; _dtmf_key = br;
              currentReport = keyPressDTMF; return true;
            }
          }
        }
        break;
      }
    case delSMS: { // операция удаления СМС - тупо ждем ОК и выходим
        // проверяем таймаут
        if ((millis() - modemMillis) >= periodSimpleResponse) {
          currentReport = errTimeOut; return true; // прописываем код ответа и выходим
        }
        if (br) {
#ifdef SHOW_MODEM_RESPONSE
          Serial.write(br);
#endif
          if (s800lib::findResp((char *)"OK\r\n", br)) {
            s800lib::clearAction(); return false; // успешно выходим
          }
        }
        break;
      }
    case readSMS: { // операция чтения СМС
        // проверяем таймаут
        if ((millis() - modemMillis) >= periodReadSMS) {
          currentReport = errTimeOut; return true; // прописываем код ответа и выходим
        }
        if (br) {
#ifdef SHOW_MODEM_RESPONSE
          Serial.write(br);
#endif
          if (s800lib::findResp((char *)"OK\r\n", br)) {
            if (_sms_count) currentReport = existSMS; else currentReport = noSMS;
            s800lib::clearAction(); return false; // успешно выходим
          } else {
            if (s800lib::processSMS(br)) { // обрабатываем поток байтов
              currentReport = oneSMS; // СМС закончилась, выходим
            }
          }
        }
        break;
      }
    case sendSMS: { // операция отправки простой СМС
        // проверяем таймаут
        if ((millis() - modemMillis) >= periodSendSMS) {
          currentReport = errTimeOut; return true; // прописываем код ответа и выходим
        }
        if (_sms_step == 0) { // отправляем в модем телефонный номер
#ifdef USE_SOFTWARESERIAL
          gsm.print(_sms_sender); gsm.print("\"\r");
#else
          Serial.print(_sms_sender); Serial.print("\"\r");
#endif
          ++_sms_step; // на следующий шаг
#ifdef SHOW_MODEM_RESPONSE
          Serial.print(_sms_sender); Serial.println("\"");
#endif
        }
        if (br) {
#ifdef SHOW_MODEM_RESPONSE
          Serial.write(br);
#endif
          if (_sms_step == 1) { // ждем приглашения >
            if (br == '>') {
#ifdef USE_SOFTWARESERIAL
              gsm.print(_sms_text); gsm.write(26);
#else
              Serial.print(_sms_text); Serial.write(26);
#endif
              ++_sms_step; // на следующий шаг
#ifdef SHOW_MODEM_RESPONSE
              Serial.println(_sms_text);
#endif
            }
          } else if (_sms_step == 2) { // ждем ОК
            if (s800lib::findResp((char *)"OK\r\n", br)) {
              s800lib::clearAction(); return false; // успешно выходим
            }
          }
        }
        break;
      }
    default: {
#ifdef SHOW_MODEM_RESPONSE
        if (br) Serial.write(br);
#endif
        // ищем какие либо значимые ответы от модема
        if (br) {
          if (s800lib::findResp((char *)"RING\r\n", br)) { // ищем входящий звонок
            _ring_step = 0; _inc_ring = 1; memset(phone_buf, 0, max_size_phone_number);
          }
          if (s800lib::findResp((char *)"NO CARRIER\r\n", br)) _inc_ring = 0; // сбросился звонок
          if (_inc_ring) { // позвонили
            // вытаскиваем телефонный номер
            if ((s800lib::findResp((char *)"+CLIP: \"+", br)) && (!_ring_step)) {
              _ring_step = 1;
            }
            if (_ring_step) {
              if (br == '\"') { // закончился номер
                _ring_step = 0; _inc_ring = 0; currentReport = incomingCall;
              } else if (isdigit(br)) {
                byte phl = strlen(phone_buf);
                if (phl < (max_size_phone_number - 1)) phone_buf[phl] = br;
              }
            }
          }
        }
        return false; // ничего не обрабатывается
      }
  }
  return true;
}

void s800lib::sendATcmd() {
  char cmd_buf[max_size_cmd_buf]; // буфер команд
  s800lib::clearRespBuf(); // очищаем приемный буфер
  const char * addrStroki = pgm_read_word_near((int)(at_list_cmd + _current_cmd)); // адрес команды в eeprom
  strcpy_P(cmd_buf, addrStroki); // достать команду
  // отправляем команду в модем
#ifdef USE_SOFTWARESERIAL
  gsm.print(cmd_buf);
#else
  Serial.print(cmd_buf);
#endif
#ifdef SHOW_MODEM_RESPONSE
  Serial.print(cmd_buf);
#endif
  // прописать следующую команду при успешном ответе или по условию операции
  _next_cmd = pgm_read_byte_near(at_move_cmd + _current_cmd);
  modemMillis = millis(); // обнулим таймер
}

bool s800lib::findResp(char * inStr, byte inByte) { // поиск строки в циклическом буфере
  byte slen = strlen(inStr); // длина искомой строки
  if (inByte == inStr[slen - 1]) { // если последний символ совпадает - продолжаем искать всю строку
    byte cfound = 1; // число совпавших символов
    byte abpos = pos_buf; // абсолютная позиция в буфере поиска-1  = последнему символу искомой строки
    if (!abpos) abpos = max_size_response_buf - 1; else --abpos; // ищем с предпоследнего символа
    for ( byte i = 0; i < (slen - 1); ++i) {
      if (inStr[slen - 1 - i] != resp_buf[abpos]) return false;
      if (!abpos) abpos = max_size_response_buf - 1; else --abpos;
    }
  } else {
    return false;
  }
  return true;
}

modemActions s800lib::getModemActions() { // возвращает текущую операцию
  return currentAction;
}
modemReport s800lib::getModemReport() { // возвращает ответ операции
  return currentReport;
}
byte s800lib::getModemCmd() { // возвращает номер текущей команды модема
  return _current_cmd;
}
void s800lib::clearAction() { // сброс текущего действия модема
  s800lib::currentAction = doNothing;
}

void s800lib::deleteAllSMS() { // удалить все СМС
  currentAction = delSMS; _current_cmd = 18; s800lib::sendATcmd();
}

void s800lib::readAllSMS(char * bufSender, byte maxSender, char * bufText, byte maxText) { // прочитать все СМС
  s800lib::_sms_count = 0;
  s800lib::_sms_step = 0;
  s800lib::_sms_sender = bufSender;
  s800lib::_max_size_sender = maxSender;
  s800lib::_sms_text = bufText;
  s800lib::_max_size_sms_text = maxText;
  currentAction = readSMS; _current_cmd = 19; s800lib::sendATcmd();
}

bool s800lib::processSMS(byte inByte) { // обработка СМС
  switch (_sms_step) {
    case 0: {
        if (s800lib::findResp((char *)"CMGL:", inByte)) { // найдено начало СМС
          ++_sms_count; ++_sms_step; // увеличиваем счетчик СМС и переходим на след шаг
          memset(_sms_sender, 0, _max_size_sender); memset(_sms_text, 0, _max_size_sms_text); // чистим буферы
        }
        break;
      }
    case 1: {
        if (s800lib::findResp((char *)",\"", inByte)) ++_sms_step;
        break;
      }
    case 2: {
        if (s800lib::findResp((char *)"\",\"+", inByte)) ++_sms_step; // следующий шаг - номер отправителя
        break;
      }
    case 3: {
        if (s800lib::findResp((char *)"\",\"\",\"", inByte)) { // номер закончился
          ++_sms_step; // следующий шаг
        } else {
          byte lphone = strlen(_sms_sender);
          if ((lphone < (_max_size_sender - 1)) && (isdigit(inByte))) _sms_sender[lphone] = inByte; // записываем в строку отправитель
        }
        break;
      }
    case 4: {
        if (s800lib::findResp((char *)"\"\r\n", inByte)) ++_sms_step; // следующий шаг - текст смс
        break;
      }
    case 5: {
        if (s800lib::findResp((char *)"\r\n", inByte)) { // смс закончилась
          _sms_step = 0; return true; // выход
        } else {
          byte ltext = strlen(_sms_text);
          if (ltext < (_max_size_sms_text - 1)) _sms_text[ltext] = inByte; // записываем в строку
        }
        break;
      }
    default: {}
  }
  return false;
}

void s800lib::sendSimpleSMS(char * bufSender, char * bufText) { // отправка SMS в не PDU фармате
  s800lib::_sms_sender = bufSender;
  s800lib::_sms_text = bufText;
  s800lib::_sms_step = 0;
  currentAction = sendSMS; _current_cmd = 20; s800lib::sendATcmd();
}

char * s800lib::getPhoneNumber() { // получить телефонный номер входящего звонка
  return phone_buf;
}

void s800lib::waitPressDTMF() { // снимаем трубку при звонке и ждем нажатия кнопок
  s800lib::_dtmf_press = 0;
  currentAction = waitDTMF; _current_cmd = 21; s800lib::sendATcmd();
}

char s800lib::getKeyDTMF() { // возвращает нажатую кнопку
  return _dtmf_key;
}

-

//---sim800cmd.h---

const char at0cmdAT[] PROGMEM =      "AT\r"; // проверка связи
const char at1cmdDDET[] PROGMEM =    "AT+DDET=1\r"; // включаем режим распознавания DTMF
const char at2cmdATE0[] PROGMEM =    "ATE0\r"; // отключаем возврат команд от модема
const char at3cmdCLIP1[] PROGMEM =   "AT+CLIP=1\r"; // включаем АОН
const char at4cmdATS0[] PROGMEM =    "ATS0=0\r"; // вручную поднимать трубку при входящем звонке
const char at5cmdATV1[] PROGMEM =    "ATV1\r"; // развернутый символьный ответ от модема
const char at6cmdATCMEE2[] PROGMEM = "AT+CMEE=2\r"; // подробный вывод ошибок
const char at7cmdATCMGF1[] PROGMEM = "AT+CMGF=1\r"; // не PDU режим приема и отправки SMS
const char at8cmdCSCLK1[] PROGMEM =  "AT+CSCLK=0\r"; // отключаем режим ухода в сон с помощью пина DTR на модеме

const char at9cmdCGATT[] PROGMEM = "AT+CGATT?\r"; // Проверка доступа к услугам пакетной передачи данных
const char at10cmdSAPBR311[] PROGMEM =  "AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r";
const char at11cmdSAPBR312[] PROGMEM = "AT+SAPBR=3,1,\"APN\",\"internet\"\r";
const char at12cmdSAPBR313[] PROGMEM = "AT+SAPBR=3,1,\"USER\",\"\"\r";
const char at13cmdSAPBR314[] PROGMEM = "AT+SAPBR=3,1,\"PWD\",\"\"\r";

const char at14cmdCIPMODE[] PROGMEM = "AT+CIPMODE=0\r"; // Командный режим передачи данных
const char at15cmdCIPMUX[] PROGMEM =  "AT+CIPMUX=0\r"; // Моносокет
const char at16cmdCIPHEAD[] PROGMEM = "AT+CIPHEAD=1\r"; // Перед блоком данных, принятых от сервера добавлять заголовок формата +IPD,<длина блока данных>
const char at17cmdCIPSRIP[] PROGMEM = "AT+CIPSRIP=0\r"; // При приеме данных не показывать уведомление в виде RECV FROM:<IP адрес отправителя>,<порт>

const char at18cmdDELSMS[] PROGMEM = "AT+CMGDA=\"DEL ALL\"\r"; // удаление всех смс

const char at19cmdREADSMS[] PROGMEM = "AT+CMGL=\"ALL\"\r"; // чтение всех смс

const char at20cmdCMGS[] PROGMEM = "AT+CMGS=\"+"; // begin send sms

const char at21cmdATA[] PROGMEM = "ATA\r"; // hand up

const char * const at_list_cmd[] PROGMEM = { // text command
  at0cmdAT, at1cmdDDET, at2cmdATE0, at3cmdCLIP1, at4cmdATS0, at5cmdATV1, at6cmdATCMEE2, at7cmdATCMGF1, at8cmdCSCLK1, // initATmodem
  at9cmdCGATT, at10cmdSAPBR311, at11cmdSAPBR312, at12cmdSAPBR313, at13cmdSAPBR314, // init http
  at14cmdCIPMODE, at15cmdCIPMUX, at16cmdCIPHEAD, at17cmdCIPSRIP, // init gprs
  at18cmdDELSMS, // del sms
  at19cmdREADSMS, // read sms
  at20cmdCMGS, // send sms
  at21cmdATA // ring dtmf
};

const PROGMEM  uint8_t at_move_cmd[] = { // step after action cmd
  1, 2, 3, 4, 5, 6, 7, 8, 101, // initATmodem
  10, 11, 12, 13, 14, // init http
  15, 16, 17, 101, // init gprs
  101, // del sms
  101, // read sms
  101, // send sms
  101 // ring dtmf
};

-

Скетч использует 6550 байт (21%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 617 байт (30%) динамической памяти, оставляя 1431 байт для локальных переменных. Максимум: 2048 байт.


Ready
7900***8478
Proba long SMS beach hlam1455&)
Incoming call from 7900***8478
Pressed key 1
Pressed key 6
Pressed key *


 

Shama
Offline
Зарегистрирован: 16.03.2020

Приветствую, вопрос такой, у меня таймер прочьтения смс стоит 1 сек ( ну условно) юзаю без библиотек sim800L. скорость подачи 9600 бадов. чисто вопрос программирования... вот залетел в проверку по времени ну типо пора проверять, типа есть смс... парсю его, а там еще свои таймеры стоят (на проверку количество попыток и прочее...) и свои АТ команды. вот как это работает?!!!  он должен каждую строку по коду же прогнать? правильно же понимаю. Но складывается впечатление что если проверять 1 раз в минуту он как бы не цепляет весь код, гдето вылетает и уже к этому не возвращается. А если его каждую сек кормить то иногда проглатывает как надо. Есть ли адекватная причина проверять смс так часто, если мне по сути без разницы 5 минут или 1 минута.   И еще с чем связано что АТ команда не всегда корректно обрабатывается? возможна ли причина в питании ?   И еще влияет ли вывод в монитор порта на АТ команды ? Неподглюкивает ли ардуино типа время на отправку, а следом уже надо проработать АТ команду СРАЗУ СЛЕДОМ. А там чтото на скоростях 9600 отправляю. Ктонить спатыкался на этом ?   И нужно ли использовать специальные библы чтобы этого избежать? 

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

Вы бы для начала сами сели и подумали, вместо того чтоб валить все в кучу и в одном посте задавать 9 (не поленился посчитать) вопросов.

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

Shama
Offline
Зарегистрирован: 16.03.2020

Да думал попунктно разбить ) но хоть какие нить зацепки получить... 

Сесть я сел, но вот с думалкой беда у меня (

Shama
Offline
Зарегистрирован: 16.03.2020

смс сохраняется в памяти и только после прочтения его удаляю. 

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

Shama пишет:

смс сохраняется в памяти и только после прочтения его удаляю. 

тогда зачем проверять раз в секунду?

А вообще - показывайте код, как читаете СМС, без кода разговаривать не о чем

Shama
Offline
Зарегистрирован: 16.03.2020
 
 

 

Shama
Offline
Зарегистрирован: 16.03.2020

Бывает до парсем смс недоходит дело вообще... 

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

Shama - вставьте код по правилам, это сообщение модераторы скоро удалят

Shama
Offline
Зарегистрирован: 16.03.2020

Я новенький, пойду почитаю правила ) 

Shama
Offline
Зарегистрирован: 16.03.2020

Я извиняюсь, а  где можно правила почитать ? 

Slacky
Slacky аватар
Offline
Зарегистрирован: 16.11.2017

Господа-товарищи :) 

Вопрос собственно не совсем в тему, но про SIM800L. Допустим модуль находится в режиме PPP. Как отследить входящий звонок? Хорошо, если на плате распаян выход ring, тогда все проще - при появлении 0, считаем, что звонок поступил (а оно именно так и работает, проверял), переводим модуль в режим AT команд и дальше работаем. А если такой выход не выведен на плате? Как? По uart полный молчок. Если до режима PPP дать команду ATS0=1, то модуль прекрасно снимет трубку при первом звонке, но ничего не скажет об этом.  Как?

Помогите :))

Спасибо.

vlad072
Offline
Зарегистрирован: 01.08.2017

Попробуйте включить оповещение о состоянии разговорного канала

AT+CLCC=1

 

GrSnake
Offline
Зарегистрирован: 07.07.2019

Доброго времени суток

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

задача стоит включить "звонок" при поступлении входящего вызова и соответственно выключить его если вызов прекратился или была снята трубка.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

GrSnake пишет:

Доброго времени суток

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

задача стоит включить "звонок" при поступлении входящего вызова и соответственно выключить его если вызов прекратился или была снята трубка.

https://img.filipeflop.com/files/download/Datasheet_SIM800L.pdf - раздел 4.6, страница 35.

GrSnake
Offline
Зарегистрирован: 07.07.2019

Спасибо. Из мануала понял что легче программно реализовать обработку поступления информации о входящем вызове чем использовать этот пин.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

GrSnake пишет:

Спасибо. Из мануала понял что легче программно реализовать обработку поступления информации о входящем вызове чем использовать этот пин.

Да и так, и так - не особо сложно, в общем-то. Проблемы засечь длительность импульса - нет, а уже по длительности понимать, что, собственно, произошло. Просто настроить AT-командами выдачу статусов в порт и потом по всяким +CMT: и +RING: понимать, что пришло СМС или входящий звонок - это банально человекопонятней, на то и AT-протокол изначально был заточен (это сейчас из него выросло то, что выросло :)) ).

GrSnake
Offline
Зарегистрирован: 07.07.2019

а зачем собственно возиться с этим пином, если все равно по итогу придется все равно придется программно разбирать "что произошло". Просто слушаем модуль и при поступлении +RING включаем звонок, при подъеме трубки отключаем и ждем следующего вызова. ну там конечно логика процесса будет несколько сложнее но в общем так.

У меня задача достаточно проста - попросили сделать телефон для приколов. старый советский с дисковым номеронабирателем, но чтоб звонил... + бонусом небольшой дисплейчик  к нему прикрутить чтоб видеть набираемый номер. Всю обвязку сделал, осталось собственно модуль sim800l раскурить.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

GrSnake пишет:

Всю обвязку сделал, осталось собственно модуль sim800l раскурить.

Эх, мне б щас вернуться в те времена, когда всё виделось так просто ;) Осталось-то - всего SIM800L раскурить, и всё. Конечно, если опираться на примеры из сети - курить там нехрен, банальный блокирующий код, и то - о коррекции ошибок авторы примеров, как правило, и не слышали.

А вот если асинхронщина - вот это адъ. У меня ушло примерно полтора года на постепенное допиливание конечного автомата, и это при условии, что он, честно говоря - и не претендует (даже близко) на полноту охвата возможностей общения с SIM800L, да и вообще - коряв и некрасив.

Это я к тому, что я до сих пор не могу сказать, что раскурил SIM800L ;)

GrSnake
Offline
Зарегистрирован: 07.07.2019

Да. именно опираясь на примеры из сети я и действую. Да я понимаю что получится коряво и кровь будет течь из глаз ручьями))) но я не унываю и надеюсь заставить это чудо работать. Может (или даже скорее всего) я где-то крупно ошибаюсь. но пока задача видится достаточно простой. набрать номер - отправить его в модуль для осуществления вызова. и соответственно получить от него информацию о входящем вызове и ответить на него. всю остальную информацию тупо обрубаем. во всяком случае на данном этапе. если интерес не угаснет, можно будет продолжить эксперементы. Для меня это не более чем хобби. взлетит - хорошо, не взлетит - значит не судьба. Свой первый проект "для души" а именно наливатор из старого струйника и платы ардуино я делал наощупь имея только небольшие и давно забытые навыки программирования на delphi и к моему удивлению все получилось. часы на ГРИ получились уже вполне на уровне, но там уже разводка платы с атмегой 328 и еще много всего интересного было...

Извиняюсь за оффтоп)))

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

GrSnake пишет:

и к моему удивлению все получилось. 

Не питай иллюзий - это тебя так завлекают :)) Туризм и эмиграция - разные вещи :)))

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

GrSnake , вы главное себе аксиому поставьте в голове "совсем не использовать delay и всегда проверять ответы от модема", и все будет красиво и хорошо :)

GrSnake
Offline
Зарегистрирован: 07.07.2019

andycat пишет:

GrSnake , вы главное себе аксиому поставьте в голове "совсем не использовать delay и всегда проверять ответы от модема", и все будет красиво и хорошо :)

 

про проверять ответы это понятно. а вот как без delay -  Вы меня заинтриговали. Как я понял в некоторых местах паузу между отправкой команд делать все равно надо.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

GrSnake пишет:

про проверять ответы это понятно. а вот как без delay -  Вы меня заинтриговали. Как я понял в некоторых местах паузу между отправкой команд делать все равно надо.

вы всю ветку эту прочитали? и вообще все примеры из сети смотрели?

вот выше например

http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...

примеры с сайта codius.ru не плохи, учиться на них хорошо.

 

GrSnake
Offline
Зарегистрирован: 07.07.2019

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

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

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Здравствуйте. С НОВЫМ ГОДОМ.

Подключила SIM800L к RX TX ардуино, а отладку делаю по SoftwareSerial (подключила UART конвертер)

SIM800 команды не понимает, данные не приходят.

Для проверки подключила конвертер к SIM800, данные отправляются и читаются.

Подключила конвертер к RX TX ардуино - данные отправляются и читаются*

Что не так? (не хватает пинов ардуино, хочу использовать RX TX)

#include <SoftwareSerial.h>
SoftwareSerial CONVERTER(10,9);

void setup() {
  Serial.begin(19200);
  CONVERTER.begin(19200);
}

void loop() {
  if (CONVERTER.available()) Serial.write(CONVERTER.read());
    
  if (Serial.available()) CONVERTER.write(Serial.read());
}

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

В скетче проблем не видно, проверяйте подключение, пины, уровни сигналов, ограничительные резисторы, пробуйте поменять местами rx tx. Скорость 9600 поставить. Чудес не бывает.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Это уже всё перепробовала. Из-за питания ардуины через юсб может быть такая проблема?

 

Alfizik
Alfizik аватар
Offline
Зарегистрирован: 16.12.2020

Не может, а будет точно. Питайте правильно

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Уже, но безрезультатно, сообщения такого плана  CONVERTER.println ("123");

конвертер получает, а с модуля ничего.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
#include <SoftwareSerial.h>
SoftwareSerial CONVERTER(10,9);

void setup() {
  Serial.begin(19200);
  CONVERTER.begin(19200);
CONVERTER.println ("123");
}

void loop() {
  if (CONVERTER.available()) Serial.write(CONVERTER.read());
    
  if (Serial.available()) CONVERTER.write(Serial.read());
}

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Ну....нечему там ломаться, у меня работает, но я на 2 и 3 пинах лог вывожу, разницы быть не должно. Обновите software serial библиотеку, вдруг ошибка, попробовать на других ножках, тестером проверить все соединения, питание модема отдельное 4 вольта, если включить модем после МК, при регистрации в сети в логе должны быть сообщения из модема и скорость 9600 строго при включении, потом увеличивать будете после отладки

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Дело в том, что на ардуино есть два резистора на RX TX, и у меня на модуле один на 1 кОм и делитель из двух по 10кОм, поэтому и неработало. 

Модуль стал отвечать на АТ, но при этом перезагружается, странно.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Мощности БП не хватает

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

10 Ампер БП (DPS5020)

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Совсем не показатель, подключать осциллограф, смотреть что на шине питания.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

andycat пишет:
Совсем не показатель, подключать осциллограф, смотреть что на шине питания.

При работе по софтсериал, всё норм. А на счёт осциллографа ещё нету, первый раз заказала, не пришел, деньги вернули, надо заказать ещё раз)

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Подключите согласно даташита и забудете о проблема с питанием и помехами

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Так подключено:

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Не правильно, на модеме уровень сигнала 2.8 в ,а у вас 2.5. фильтрации питания нет вообще,на tx резистор зачем. И т д .....
Все плохо, откройте даташит

MaksVV
Offline
Зарегистрирован: 06.08.2015

Задам здесь вопрос к Andycat, как человеку глубоко разобравшемуся в вопросе. Ты используешь брокер clusterfly.ru ?  Если да, есть ли у тебя проблемы с этим брокером?  После НГ у меня перестало работать SIM800L  MQTT на этом брокере. До НГ неделями онлайн нормальный был на том же скетче и железе.  Написал в техподдержку  - говорят ничего не изменилось на сервере.

Причём не совсем не работает. Происходит так: подключается, работает  (как PUB, так и SUB) ровно 30 секунд и выбрасывает с сервера. SIM800 при этом пишет CLOSED. Может подскажешь как выяснить причину выбрасывания?  CloudMQTT при этом нормально работает.