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

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

Использую cloudmqtt. При использовании другого сервиса смотрите логи этого сервиса!!!! А то получается что вы применяете косяки Жигули к Мерседесам, ну не маразм ли ? А если на вскидку с большой вероятностью отваливается по time out, если за 30 секунд не было передачи данных - отрубает связь. Для более детального ответа необходимо у модема запрашивать статус интернет сессии и уже по ситуации решать проблему.

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

Картинка из даташита вам в помощь
http://arduino.ru/forum/programmirovanie/snova-mqtt-1?page=1#comment-567999

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

Я тоже естественно подумал на таймаут. Всяко уже  этот вопрос прошевелил. Врядли в этом дело, т.к. от момента подключения до выбрасывания, данные ведь обновляются и я сам шлю запросы, ответы от девайса приходят, поэтому таймаут, даже если как то он коряво и устанавливается на 30 сек, все равно должен сбрасываться на ноль после запросов. А он чётко от момента подключения к брокеру 30 ну +- 3 сек и CLOSED. 

ок , все равно, пасиб за инфу, будем копать. 

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

Проверьте параметры connect packet, возможно ваш брокер некорректно отрабатывает время удержания сессии, в любом случае не видя причину отключения это все угадайка...
И для поддержания сессии люди придумали pingreq pingresp packet

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

del

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

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

Про резистор поняла, уберу (он у меня остался от прямого подключения к Atmega328), а на счёт уровня 2,5 Вольт, минимальное 2,1 максимальное 3,1, не?

По питанию фильтрация есть, как в даташите. на моей схеме не указано

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

Среднее 2.8 вольта, надёжно работает, пока сбоев не было

Update. Вру, среднее 2.6, но мы делаем 2.8.
И всё таки, если зависает, наверняка помехи или БП проседает на доли секунд.

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

Дело было в питании, макетная плата не обеспечивала хорошего контакта.

andycat, какую скорость Hardware serial используете для работы с модемом?

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

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

Dr.Evil
Offline
Зарегистрирован: 06.01.2021

я более того скажу, смысла нет ни малейшего выше 9600 использовать. И везде по возможности стараюсь обходиться этой скоростью, особенно после того как столкнулся с жутко несоответствующим номиналу кварцем на ардуинке. На той 115200 работал с дикими и порой весьма забавными глюками.

Кстати, SoftwareSerial почему-то с SIM800 порой тоже нестабильно работает, по возможности оставьте модуль на аппаратном порту. И да, питание питание и еще раз питание. Конденсатор еще есть смысл на контакты модуля напаять если его там нет, тантал, микрофарад на 1000 хотя бы. Часть глюков отсекает.

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

Спасибо

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

Dr.Evil пишет:

я более того скажу, смысла нет ни малейшего выше 9600 использовать.

А мужики-то и не знают...

Мне вот явно 31250 не хватает: приходится в программе много чего накручивать, чтобы избежать переполнения буфера.

Цитата:

И везде по возможности стараюсь обходиться этой скоростью, особенно после того как столкнулся с жутко несоответствующим номиналу кварцем на ардуинке. На той 115200 работал с дикими и порой весьма забавными глюками.

А к скорости порта то это каким боком? Рассогласование скоростей - относительное, следовательно, на любой скорости будет проявляться в равной степени.

Я тоже с таким сталкивался. Итог: в коде вместо 31250 фигурирует 31500. Но по факту это те же самые 31250, только с поправкой на частоту кварца.

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

andriano, стесняюсь спросить а как зависит скорость и переполнение буфера ? Может быть в алгоритме проблема .

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

Напрямую: буфер переполняется, когда скорость заполнения оказывается выше скорости опустошения. А скорость опустошения - это и есть по сути скорость порта.

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

andriano пишет:

скорость опустошения - это и есть по сути скорость порта.

О_О С какой стороны?

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

Со стороны TX.

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

Мда....оригинальный костыль. Впрочем хозяин-барин.

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

andycat пишет:
Мда....оригинальный костыль. Впрочем хозяин-барин.

Мне самому не нравится. Но еще больше не хочется изменять размер буфера порта.

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

Дык обрабатывайте online каждый приходящий байт в кольцевом буфере и будет всё работать вне зависимости от размера буфера

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

У меня байты не приходят, они задаются музыкантом. Вот уходить не всегда успевают. 

Кстати, у порта и так два кольцевых буфера, зачем еще?

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

Чтоб искать приходящие слова фразы типа Creg и прочее
И кстати у порта не кольцевые буферы насколько я знаю

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

andycat пишет:
И кстати у порта не кольцевые буферы насколько я знаю

Вот это для меня новость.

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

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

Легко, 2 переменных, указатель на последнюю ячейку для записи и количество занятого объема , + соответственно максимальный размер буфера. Ну а дальше тупо логика. Это кольцевой. Ну и поиск подстроки в нем начинать с конца строки.

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

andycat пишет:
Среднее 2.8 вольта, надёжно работает, пока сбоев не было Update. Вру, среднее 2.6, но мы делаем 2.8. И всё таки, если зависает, наверняка помехи или БП проседает на доли секунд.

А как вы делаете 2,8? Используете выход VDDEXT?

 

 

С рождеством!

 

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

Резисторный делитель, точные номиналы сами рассчитайте или после праздников я схему просмотрю

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

andycat пишет:
Легко, 2 переменных, указатель на последнюю ячейку для записи и количество занятого объема , + соответственно максимальный размер буфера. Ну а дальше тупо логика. Это кольцевой.
Так кольцевой или не кольцевой?

В любом случае, интересует вопрос: как организовать FIFO без кольцевого буфера?

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

Не знаю, ни разу не требовался, но наверное как обычно , включить логику и все будет.

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

Так вот как раз по логике - иначе не будет.

Другими словами, если без извращений, то FIFO - это кольцевой буфер.

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

Я вот потихоньку пытаюсь уйти от String, возникли вопросы

#include <SoftwareSerial.h>
SoftwareSerial MODEM(9, 10);
#include <avr/wdt.h>

const char AT_UART[] PROGMEM = "AT";
const char AT_SET[] PROGMEM = "AT+CCALR?";
const char AT_AOH[] PROGMEM = "AT+CLIP=1";
const char AT_UARTotv[] PROGMEM = "AT\r";

const char* const AtCommand[] PROGMEM = {
  AT_UART, AT_SET, AT_AOH, AT_UARTotv,
};


unsigned long Time;
char buffers[50];
byte pos_buf ;
#define MAX_SIZE_RESP_BUF 50



void AtSend(byte nomer) {
  char arrayBuf[20];
  strcpy_P(arrayBuf, (char*)pgm_read_word(&(AtCommand[nomer])));
  MODEM.println(arrayBuf);
}


char AtRead(byte nomer) {
  char arrayBuf[20];
  strcpy_P(arrayBuf, (char*)pgm_read_word(&(AtCommand[nomer])));
  return arrayBuf;
}


void setup() {
  wdt_disable();
  Serial.begin(9600);
  MODEM.begin(9600);
  AtSend(0);
  wdt_enable (WDTO_4S);
}


void loop() {
  while (1) {
    wdt_reset();

    /* if (millis() - Time >= 3000) {
       Time = millis();
       AtSend(1);
      }*/

    if (Serial.available())MODEM.write(Serial.read());

    if (MODEM.available() > 0) {
      delay(50);
      while (MODEM.available()) {
        if (pos_buf < MAX_SIZE_RESP_BUF) {
          byte temp = MODEM.read();
          buffers[pos_buf] = temp;
          pos_buf++;
        } else {
          Serial.println("Bufer perepolnen");
          break;
        }
      }//while

      Serial.print("Polucheno: ");
      Serial.print(pos_buf);
      Serial.print(" Byte");
      Serial.println("");
      //Serial.println(buffers);

      if (strstr (buffers, "AT\r") != NULL && strstr (buffers, "OK") != NULL)
      {
        Serial.println("Uart_OK");
      }


      if (strstr (buffers, "AT+CCALR?") != NULL && strstr (buffers, "+CCALR: 1") != NULL && strstr (buffers, "OK") != NULL)
      {
        Serial.println("Set'_OK");
      }



      while (MODEM.available())MODEM.read();
      for (byte i = 0; i < pos_buf ; i++)buffers[i] = NULL;
      pos_buf  = 0;

    }//if (MODEM.available() > 0) {
  }//while(1){
}//loop

 

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

Так как ключевое АТ содержится во всех* командах, то условие на 75 строчке выполнялось бы всегда, поэтому я добавила \r


      if (strstr (buffers, "AT\r") != NULL && strstr (buffers, "OK") != NULL)
      {
        Serial.println("Uart_OK");
      }

Почему при замене "АТ\r" на AtRead(3) условие выполняется всегда

      if (strstr (buffers, AtRead(3)) != NULL && strstr (buffers, "OK") != NULL)
      {
        Serial.println("Uart_OK");
      }

т.е. при выполнении AT+CCALR? 

я получу в монитор порта

Polucheno: 29 Byte
Uart_OK
Set'_OK
 
andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Atread возвращает один символ, а не три.

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

andriano, вы пытаетесь найти абстрактное решение к непонятно какой (не описанной)задаче , опишите саму суть и нафига FIFO именно не кольцевой ?

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

andycat пишет:
Atread возвращает один символ, а не три.

Как собрать в строку*?

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

andycat пишет:
andriano, вы пытаетесь найти абстрактное решение к непонятно какой (не описанной)задаче , опишите саму суть и нафига FIFO именно не кольцевой ?

Собственно, речь не о задаче, а о Вашем утверждении:

andycat пишет:
И кстати у порта не кольцевые буферы насколько я знаю

Если не кольцевые, то какие?

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

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

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

Irinka пишет:

andycat пишет:
Atread возвращает один символ, а не три.

Как собрать в строку*?

Тут были примеров масса, с мобильника сложно писать, и я например отказался от progmem для хранения ответов модема, быстродействия не хватает, только отправляемые команды там храню.

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

Цитата:
быстродействия не хватает, только отправляемые команды там храню.

Спасибо. Учту. 

На счёт примеров, как будет время, ткните, пожалуйста, хочу знать.

Dr.Evil
Offline
Зарегистрирован: 06.01.2021

andriano пишет:

А к скорости порта то это каким боком? Рассогласование скоростей - относительное, следовательно, на любой скорости будет проявляться в равной степени.

RS-232 интерфейс асинхронный, тактового провода в нем нет, линии DTR/DSR дуина по умолчанию не имеет поэтому устройство ориентируется только на старт-бит как начало посылки, а после в соответствии с предполагаемым таймингом - принимает остальные биты кодовой посылки. Тайминги же конкретно на кварц завязаны, в итоге на больших скоростях передачи (да, 115200 для 232го это уже много) на левом кварце могут вполне себе пакеты не успевать приниматься/передаваться полностью. К сожалению сейчас не могу проиллюстрировать это скринами с логического анализатора - я тогда когда просек в чем проблема даже сравнивал время передачи пакетов - у меня одна дуинка на которой кварц заявленный как 16 а по факту оказался примерно 15,2 мегагерца - конкретно "тормозила" при связи на 115200 bps - более-менее устойчивая работа начиналась только на 38400.

Dr.Evil
Offline
Зарегистрирован: 06.01.2021

А вообще конечно буфер UART в 64 байта это совсем немного, тут как раз наоборот - большие скорости передачи только усугубляют проблему обработки данных. Если принимается большой объем (больше 64 байт) и нет желания/возможности увеличить буфер - то есть прямой смысл думать про обработку прерываний от UART и ухода от условия Serial.available() - что кстати на софтварном порту вроде как не реализуется, только на аппаратном.

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

Irinka пишет:

На счёт примеров, как будет время, ткните, пожалуйста, хочу знать.

Как-то писал для SIM800L и Arduino рыбу для ответа модема и управлению им по DTMF. String не использовлась. Если интересно, то вот - https://github.com/slacky1965/alarm

Обсуждение на этом форуме было тут - http://arduino.ru/forum/proekty/sim800l-dtmf-upravlenie-golosovoe-menyu

Не претендую на гуру SIM800 и Arduino :))

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

Slacky, огромное спасибо, не знала про воспроизведение файлов!

Попробовала, воспроизводится)))))

А я для такого проекта хотела DFPlayer Mini прикручивать)

 



mySerial.print("AT+CREC=4,\"C:\\User\\"), mySerial.print(1), mySerial.println(".amr\",0,100");

Вы написали что одной командой не работает

  MODEM.println("AT+CREC=4,\"C:\\User\\1.amr\",1,100");

Попробовала, работает.

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

Irinka пишет:

mySerial.print("AT+CREC=4,\"C:\\User\\"), mySerial.print(1), mySerial.println(".amr\",0,100");

Вы написали что одной командой не работает

  MODEM.println("AT+CREC=4,\"C:\\User\\1.amr\",1,100");

Попробовала, работает.

 

Я не помню, что я такое где-то утверждал. У меня все передается одной сторокой

void sim800PlayTrack(_track track) {
  strcpy_P(tmpBuffer, (char*)pgm_read_word(&(msgName[track])));
  sim800WriteCmd(tmpBuffer, 0);
  delay(DEFAULT_DELAY_PLAY_TRACK * 1000);
}

Где track - номер трека, который нужно воспроизвести уже вместе с командой ...

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

Возникла проблемка:

#include <SoftwareSerial.h>
SoftwareSerial MODEM(9, 10);
#include <avr/wdt.h>

const char AT_UART[] PROGMEM = "AT";//Proverka uart                     0
const char AT_SET[] PROGMEM = "AT+CCALR?";//Proverka seti               1
const char AT_AOH[] PROGMEM = "AT+CLIP=1";//"Ustanovlen AON             2
const char AT_TEXTM[] PROGMEM = "AT+CMGF=1";//"Text mode                3
const char AT_DELSMS[]PROGMEM = "AT+CMGDA=\"DEL ALL\"";//Sms udaleny    4
const char AT_SBROS[]PROGMEM = "ATH";//Sbros vy`zova                    5



const char* const AtCommand[] PROGMEM = {
  AT_UART, AT_SET, AT_AOH, AT_TEXTM, AT_DELSMS, AT_SBROS
};



unsigned long Time;
char buffers[50];
byte pos_buf;
#define MAX_SIZE_RESP_BUF 50


void AtSend(byte nomer) {
  char arrayBuf[50];
  strcpy_P(arrayBuf, (char*)pgm_read_word(&(AtCommand[nomer])));
  MODEM.println(arrayBuf);
}


void setup() {
  wdt_disable();
  Serial.begin(9600);
  MODEM.begin(9600);
  AtSend(0);
  wdt_enable (WDTO_4S);
}


void loop() {
  while (1) {
    wdt_reset();

    /*if (millis() - Time >= 3000) {
       Time = millis();
        AtSend(1);
       }*/





    if (Serial.available())MODEM.write(Serial.read());

    if (MODEM.available() > 0) {
      delay(50);
      while (MODEM.available()) {
        if (pos_buf < MAX_SIZE_RESP_BUF) {
          byte temp = MODEM.read();
          buffers[pos_buf] = temp;
          pos_buf++;
        } else {
          Serial.println("Bufer perepolnen");
          break;
        }
      }//while

 for (byte i = 0; i < pos_buf ; i++) {
    if (buffers[i] == '\r')buffers[i] = 'r';
    if (buffers[i] == '\n')buffers[i] = 'n';
  }

      Serial.print("Polucheno: ");
      Serial.print(pos_buf);
      Serial.print(" Byte");
      Serial.println("");
      //Serial.println(buffers);
      for (byte i = 0; i < pos_buf ; i++) {
      Serial.println(buffers[i]);
      }




      if (strstr (buffers, "+CMTI:") != NULL)
      {
        Serial.println("Polucheno SMS");
        AtSend(4);
      }

      if (strstr (buffers, "AT+CMGDA=\"DEL ALL\"") != NULL && strstr (buffers, "OK") != NULL)
      {
        Serial.println("Sms udaleny");
      }

      while (MODEM.available())MODEM.read();
      for (byte i = 0; i < pos_buf ; i++)buffers[i] = NULL;
      pos_buf  = 0;

    }//if (MODEM.available() > 0) {
  }//while(1){
}//loop

 

Если я вручную отправляю +CMTI: то всё ОК, в мониторе порта вижу Polucheno SMS и Sms udaleny

Polucheno: 7 Byte
+
C
M
T
I
:
r
Polucheno SMS
Polucheno: 25 Byte
A
T
+
C
M
G
D
A
=
"
D
E
L
 
A
L
L
"
r
r
n
O
K
r
n
Sms udaleny
если приходит реальное смс, то ответ (эхо и ответ ОК) почему то приходят разными сообщениями, т.е.
не как другие:
AT+CMGDA="DEL ALL"//Эхо
ОК//Ответ
 
 
Polucheno: 17 Byte
r
n
+
C
M
T
I
:
 
"
S
M
"
,
1
r
n
Polucheno SMS
Polucheno: 19 Byte
A
T
+
C
M
G
D
A
=
"
D
E
L
 
A
L
L
"
r
Polucheno: 6 Byte
r
n
O
K
r
n

 

 

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

Соответственно, если вручную отправляю +CMTI:"SM",1 (как приходит с модема), то так же всё  ОК

+CMTI:"SM",1

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

Irinka, все у вас как то не логично. Зачем while внутри loop. Количество команд инициализации модема мало, поставите другой модем - будут проблемы, возьмите для пробы мой список команд из темы про mqtt. Зачем задержка 50мсек. Программа должна работать по строгой логике, инициализация, чтение смс, ответ за звонок и прочее, а у вас сборная солянка. Если хотите совсем универсально - это сложно и сотней строк кода не обоцдетесь.

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

Команд будеn больше, сейчас разбираюсь с логикой работы, используя char

andycat пишет:
Зачем while внутри loop.

Как по другому собрать буфер?

andycat пишет:
Зачем задержка 50мсек

Иначе работает с ошибками, получаю неверные символы

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

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

А чтоб не было ошибок при приеме , даже не пытайтесь а монитор порта выводить все online принимаемое с модема - рано или поздно упретесь в недостаток быстродействия. Соответственно ваша задержка 50 мсек это тупо костыль .

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
    if (MODEM.available() > 0) {
      delay(3);
      while (MODEM.available()) {
        if (pos_buf < MAX_SIZE_RESP_BUF) {
          byte temp = MODEM.read();
          buffers[pos_buf] = temp;
          pos_buf++;
        } else {
          Serial.println("Bufer perepolnen");
          break;
        }
      }//while

При задержке больше 5 всё ок, при меньшей получаю следующее на команду Ат

 
Polucheno: 5 Byte
 
A
T
r
r
 
 
 

 

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

Если в буфере есть байт, вы просто обязаны его вычитать вне зависимости от того есть ли место в вашем буфере! Если используется не кольцевой буфер - читаете до некоего ключевого символа, например номера отправителя СМС. Если делать универсальное решение то как вариант читать до позиции \r\n Но тогда размер буфера минимум 255 нужен. У вас задача какая стоит ? Читать СМС, звонки или что

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

Я использую только звонки.