Работа с SIM900

varb
Offline
Зарегистрирован: 19.01.2015


Всем привет!

Прошу сильно не пинать, если плохо искал (я старался)

ПОмогите, пожалуйста новичку

Есть Ардуино Мега и SIM900 shield. пытаюсь получать на ардуину смс-ки, не могу решить проблему

если в программе есть что-то помимо получения данных от gsm шилда, то асть данных теряется

код:

#include <SoftwareSerial.h>
SoftwareSerial  sim900(10, 3);
const int bufsize=256;
byte buffer[bufsize]; 
int count=0;

void setup(void) {
  Serial.begin(9600);
  Serial.println("Hello! Arduino starting ");

  //starting sim900
  sim900.begin(9600);               // the GPRS baud rate  
  delay(500);
  sim900.println("AT+IPR=9600");     // Set the baud rate
  delay(500);
  sim900.begin(9600);               // the GPRS baud rate   
  delay(1000);
  sim900.print("AT\r");
  delay(300);

  Serial.println("Initialized");
}

void GetBufffer()
{
  if (sim900.available())              // if date is comming from softwareserial port ==> data is comming from gprs shield
  {
    while(sim900.available())          // reading data into char array 
    {
      buffer[count++]=sim900.read();     // writing data into array
      if(count == bufsize) {
        Serial.print("##bufsize##");
        break;
      }
    }

      Serial.write(buffer,count);            // if no data transmission ends, write buffer to hardware serial port
      Serial.print("##");
      Serial.print(count);
      Serial.print("##");      
      clearBufferArray();              // call clearBufferArray function to clear the storaged data from the array
    count = 0;
  }
}

void clearBufferArray()              // function to clear buffer array
{
  for (int i=0; i<count;i++)
    { buffer[i]=NULL;}                  // clear all index of array with command NULL
}

String temp ="";
void loop(){
  if (Serial.available()>0){
    byte in = Serial.read();
    if (char(in)=='%') in = byte(char(26));
    if (!('^'==char(in))) {
      temp+=char(in);
    } else {
     Serial.print("command: ");
     Serial.println(temp); 
     sim900.print(temp);
     sim900.print("\r");
     temp = "";
    }
  }
  
  GetBufffer();

}

при таком варианте работает как надо:

AT+IPR=9600

OK
AT

OK
##28##command: at
at

OK##7##
##2##
+CMT:##7## "+79607777777","","15/01/19,12:18:19+12"
Razdva tri chetyre pyat vyshel zayac pogulyat vdrug oho##98##tnik vybegaet prami v zaixhika strelyaet pif paf oi oi oi umira zyac moi la lya ya Razdvatri
##94##
+CMT: "+79607##15##777777","","15/01/19,12:18:25+12"
 chetyre pyat vyshel zayac pogulyat vdrug ohotnik vybegaet prami v zaixhika strelyaet pif paf oi oi oi umiraet zaya##150##c moi lya lya lya
##19##

но если в loop еще что-то добавить (напр. delay(1000)), то выходит так:

Hello! Arduino starting 
Initialized
AT+IPR=9600

OK
AT

OK
##28##
+CMT: "+79607777777","","15/01/19,12:16:21+12"
Razdva tri ch##63##
+CMT: "+79607777777","","15/01/19,12:16:28+12"
 chetyre pyat##63##

 

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

В какое именно место программы вы delay() вставляете?

varb
Offline
Зарегистрирован: 19.01.2015

сразу после GetBufffer();

можно не delay, а другими задачами нагрузить, delay-просто эмуляция занятости (обработки других задач) в этом случае)

axill
Offline
Зарегистрирован: 05.09.2011

можете попробовать использовать библиотеку GSM_Shield

varb
Offline
Зарегистрирован: 19.01.2015

axill пишет:

можете попробовать использовать библиотеку GSM_Shield

А что от этого глобально изменится?

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Для начала уберите clearBufferArray(); из функции GetBufffer();

А еще, я на вашем месте отказался бы от программного порта. На Меге своих аппаратных 4 штуки...

varb
Offline
Зарегистрирован: 19.01.2015

Gippopotam пишет:

Для начала уберите clearBufferArray(); из функции GetBufffer();

А еще, я на вашем месте отказался бы от программного порта. На Меге своих аппаратных 4 штуки...

порт переклчил на аппаратный,  не помогло

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

попробовал - не помогло

 

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

Попробуй мой код, я с ним детям объяснял как работает.

#include <SoftwareSerial.h>
 
SoftwareSerial gprsSerial(7, 8);
 
void setup()
{
    Serial.begin (9600);
    gprsSerial.begin(19200);
    // Настраиваем приём сообщений с других устройств
    // Между командами даём время на их обработку
    gprsSerial.print("AT+CMGF=1\r");
    delay(300);
    gprsSerial.print("AT+IFC=1, 1\r");
    delay(300);
    gprsSerial.print("AT+CPBS=\"SM\"\r");
    delay(300);
    gprsSerial.print("AT+CNMI=1,2,2,1,0\r");
    delay(500);
}
 
String currStr = "";
// Переменная принимает значение True, если текущая строка является сообщением
boolean isStringMessage = false;
 
void loop()
{
    if (!gprsSerial.available())
        return;
 
    char currSymb = gprsSerial.read();    
    if ('\r' == currSymb) {
        if (isStringMessage) {
            //если текущая строка - SMS-сообщение,
            //отреагируем на него соответствующим образом
            if (!currStr.compareTo("Lera")) {
                Serial.println ("Hello Lera");
            } else if (!currStr.compareTo("Jula")) {
                Serial.println ("Hello Jula");
            } 
            isStringMessage = false;
        } else {
            if (currStr.startsWith("+CMT")) {
                //если текущая строка начинается с "+CMT",
                //то следующая строка является сообщением
                isStringMessage = true;
            }
        }
        currStr = "";
    } else if ('\n' != currSymb) {
        currStr += String(currSymb);
    }
}

 

varb
Offline
Зарегистрирован: 19.01.2015

что еще примечательно, когда происходит пропажа данных, count всегда равен 63

Artemiy
Offline
Зарегистрирован: 20.10.2014

Простите, такой немного отвлеченный вопрос: а как оно работает, если нет программного включения сим-шилда?

varb
Offline
Зарегистрирован: 19.01.2015

Artemiy пишет:

Простите, такой немного отвлеченный вопрос: а как оно работает, если нет программного включения сим-шилда?


Ручное включение в процессе отладки

varb
Offline
Зарегистрирован: 19.01.2015

накопал, что буфер для serial по умолчанию задан в 64*2 байт, при этом на входящие данные берется 64, поэтому, видимо, происходит пропажа данных после 64 байт (надо пробовать менять это значение в HardwareSerial.cpp)

но тогда возникает другой вопрос:

почему при таком коде 

void setup(void) {
  Serial.begin(9600);
  Serial.println("Hello! Arduino starting ");

  //starting Serial1
  Serial1.begin(9600);               // the GPRS baud rate  
  delay(500);
  Serial1.println("AT+IPR=9600");     // Set the baud rate
  delay(500);
  Serial1.begin(9600);               // the GPRS baud rate   
  delay(1000);
  Serial1.print("AT\r");
  delay(300);

  Serial.println("Initialized");
}

String str="";
int buf =NULL;

void GetBufffer()
{
  boolean mustlisten = true;
  if (Serial1.available())              // if date is comming from softwareserial port ==> data is comming from gprs shield
  {
    while(mustlisten || Serial1.available())          // reading data into char array 
    {
      buf=Serial1.read();
      if (buf==char('\r')) {
        buf=byte('^');
        mustlisten = false;
      } else {
        mustlisten = true;
      }
      if (buf==char('\n')) {
        buf=byte('&');
        mustlisten = false;
      } else {
        mustlisten = true;
      }
     if (!(buf==-1)) {
       Serial.print(char(buf));
     str+=char(buf);
     }
     if (!mustlisten) {
       Serial.print("###");
      Serial.print(str);            // if no data transmission ends, write buffer to hardware serial port     
      Serial.println("$$$");
      str="";
     }
    }
  }
}
void serialEvent1(){
  GetBufffer(); 
}

String temp ="";
void loop(){
  while (Serial.available()>0){
    byte in = Serial.read();
    if (char(in)=='%') in = byte(char(26));
    if (!('^'==char(in))) {
      temp+=char(in);
    } else {
     Serial.print("command: ");
     Serial.println(temp); 
     Serial1.print(temp);
     Serial1.print("\r");
     temp = "";
    }
  }

  Serial.print("delaying...");
  
  delay(7000);
Serial.println("...delayed");

}

если в loop не стоит delay , то посылка от модема приходит полностью, даже если в ней больше 64 байт.

но если оставить delay в Loop, то после 64 байт зацикливается из-за отсутствия конца строки (mustlisten=true)

как delay влияет на буфер сериала?:)

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Никак не влияет. Просто фаза луны.

Снова посоветую - откажитесь от программеного порта.

И еще - если вы не преследуете какую-то конкретную цель (минимальный размер, понты и т.п.) - воспользуйтесь классом String. Все будет просто и очевидно.

varb
Offline
Зарегистрирован: 19.01.2015

Gippopotam пишет:

Никак не влияет. Просто фаза луны.

Снова посоветую - откажитесь от программеного порта.

И еще - если вы не преследуете какую-то конкретную цель (минимальный размер, понты и т.п.) - воспользуйтесь классом String. Все будет просто и очевидно.

в моем последнем комменте код уже с аппаратным портом и с классом String :)

спасибо за советы:)

varb
Offline
Зарегистрирован: 19.01.2015

ingener.solovyev пишет:

Попробуй мой код, я с ним детям объяснял как работает.

#include <SoftwareSerial.h>
 
SoftwareSerial gprsSerial(7, 8);
 
void setup()
{
    Serial.begin (9600);
    gprsSerial.begin(19200);
    // Настраиваем приём сообщений с других устройств
    // Между командами даём время на их обработку
    gprsSerial.print("AT+CMGF=1\r");
    delay(300);
    gprsSerial.print("AT+IFC=1, 1\r");
    delay(300);
    gprsSerial.print("AT+CPBS=\"SM\"\r");
    delay(300);
    gprsSerial.print("AT+CNMI=1,2,2,1,0\r");
    delay(500);
}
 
String currStr = "";
// Переменная принимает значение True, если текущая строка является сообщением
boolean isStringMessage = false;
 
void loop()
{
    if (!gprsSerial.available())
        return;
 
    char currSymb = gprsSerial.read();    
    if ('\r' == currSymb) {
        if (isStringMessage) {
            //если текущая строка - SMS-сообщение,
            //отреагируем на него соответствующим образом
            if (!currStr.compareTo("Lera")) {
                Serial.println ("Hello Lera");
            } else if (!currStr.compareTo("Jula")) {
                Serial.println ("Hello Jula");
            } 
            isStringMessage = false;
        } else {
            if (currStr.startsWith("+CMT")) {
                //если текущая строка начинается с "+CMT",
                //то следующая строка является сообщением
                isStringMessage = true;
            }
        }
        currStr = "";
    } else if ('\n' != currSymb) {
        currStr += String(currSymb);
    }
}

 

этот код работает, т.к. ответ модема при таких коротких смсках меньше 64 байт + других задач в коде нет, МК только и делает, что слушает порт (при таком раскладе и у меня все работало)

varb
Offline
Зарегистрирован: 19.01.2015

как и ожидалось, проблема решилась при увеличении буфера.

до каких значений его можно увеличить без опасений?:) 256*2 не много?:)

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

varb пишет:

как и ожидалось, проблема решилась при увеличении буфера.

до каких значений его можно увеличить без опасений?:) 256*2 не много?:)

Так буфер, или String?

 

varb
Offline
Зарегистрирован: 19.01.2015

Gippopotam пишет:

Так буфер, или String?

SERIAL_BUFFER_SIZE

Andrey_151
Offline
Зарегистрирован: 17.01.2015

А как и где именно вы его увеличили? Схожая проблема...кажется....

varb
Offline
Зарегистрирован: 19.01.2015

Andrey_151 пишет:

А как и где именно вы его увеличили? Схожая проблема...кажется....

\arduino\arduino\hardware\arduino\cores\arduino - hardwareserial.cpp

да, надо куда-то в фак такие сведения выложить бы - каждый второй при использовании gsm должен сталкиваться с такой проблемой

Andrey_151
Offline
Зарегистрирован: 17.01.2015

Сори...не увидел постом выше что менять надо в HardwareSerial.cpp А для SoftwareSerial есть ли такое значение?

varb
Offline
Зарегистрирован: 19.01.2015

не вдавался в подробности насчет SoftwareSerial, переткнул порты на HardwareSerial до того

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

Подниму темку. Вопрос назрел.

Какой максимальной длинны может быть одно сообщение, отправляемое с SIM900? Один пакет в 64 байта? Если так, то каким образом отправить SMS  в стандартные 160 символов?

varb
Offline
Зарегистрирован: 19.01.2015

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

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

Дайте наглядный пример кода, для отправки в одно СМС 2 блока по 64 символа.

varb
Offline
Зарегистрирован: 19.01.2015
  Sim900Serial.println("AT + CMGS = \"***********\"");//The target phone number
  delay(100);
  Sim900Serial.println("hello");//the content of the message
  delay(100);
  Sim900Serial.println((char)26);//the ASCII code of the ctrl+z is 26
  delay(100);
  Sim900Serial.println();
ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

varb пишет:

  Sim900Serial.println("AT + CMGS = \"***********\"");//The target phone number
  delay(100);
  Sim900Serial.println("hello");//the content of the message
  delay(100);
  Sim900Serial.println((char)26);//the ASCII code of the ctrl+z is 26
  delay(100);
  Sim900Serial.println();

Этим способом я передам в строке 3 только 64 символа, а как передать 160?

varb
Offline
Зарегистрирован: 19.01.2015

Можно 3ю строку повторить несколько раз

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

varb пишет:
Можно 3ю строку повторить несколько раз

А если я хочу передать 320 или 480 символов сообщение? Так же просто повторять строку до необходимого количества знаков?

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

varb пишет:
Можно 3ю строку повторить несколько раз

void sendSMS ()
{
  gprsSerial.println("AT + CMGS = \"" + nomer1 + "\"");
  delay(300);
  gprsSerial.println(writeSMS1);
  delay(300);
  gprsSerial.println(writeSMS2);
  delay(300);
  gprsSerial.println(writeSMS3);
  delay(300);
  gprsSerial.println((char)26); // Отправляем Ctrl+Z, конец сообщения
  delay(300);
  gprsSerial.print("AT+CMGDA=\"DEL ALL"); //удаляем все принятые сообщения
  delay(300);
  gprsSerial.flush();
  writeSMS1 = "";
  writeSMS2 = "";
  writeSMS3 = "";
}

Приходит только содержание первого writeSMS1, равное ровно 64 символам. writeSMS2 должно содержать 21 символ, а writeSMS3 вообще пустое.

Что не так?

varb
Offline
Зарегистрирован: 19.01.2015

А какие это 64 и 21 символы?

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

Разобрался, проблему устранил.