Баланс GSM модуля
- Войдите на сайт для отправки комментариев
Здравствуйте. Делаю GSM сигнализацию, необходимо знать баланс на сим карте GSM модуля. Хочу сделать так, чтобы по запросу с мобильного (смс) в ответ приходило сообщение о балансе от GSM модуля. Для запроса баланса использую команду ATD*101#. Если набирать команду в Serial monitor, получаю ответ вида:
OK
+CUSD: 0,"65.12 UAH. Tarif - 'Super MTS 3D Nol'. *Bezlimit na 31.12. - 5 grn. pri popolnenii s 25.11. ot 9 grn. Otkaz - *111#"6
Не могу понять, как эти 65.12 запихнуть в переменную. Пробую библиотеку GSMSHIELD.
На этом скетче пробую отладить:
#include "SIM900.h"
#include <SoftwareSerial.h>
//#include "sms.h"
//SMSGSM sms;
//int numdata;
boolean started=false;
//char smsbuffer[160];
//char n[20];
void balance () {
gsm.SimpleWriteln("ATD*101#");
delay(300);
}
void setup()
{
Serial.begin(9600);
Serial.println("GSM Shield testing.");
if (gsm.begin(9600)){
Serial.println("\nstatus=READY");
started=true;
}
else Serial.println("\nstatus=IDLE");
if(started){
balance();
if(gsm.IsStringReceived("+CUSD:")) {
Serial.print("All OK");
} else Serial.print("NO OK");
}
};
void loop()
{
};
Если стоит if(gsm.IsStringReceived("+CUSD:")) { то в сериал мониторе -
GSM Shield testing.
status=READY
NO OK
Если стоит if(gsm.IsStringReceived("OK")) { то в сериал мониторе -
GSM Shield testing.
status=READY
All OK
Я понимаю, что команда ATD*101# возвращает в сериал монитор 2 строки - "ОК" и +CUSD: 0,"65.12 UAH. Tarif - 'Super MTS 3D Nol'. *Bezlimit na 31.12. - 5 grn. pri popolnenii s 25.11. ot 9 grn. Otkaz - *111#"6
Но не знаю как работать со второй строкой. Помогите разобраться.
Неужели никто не знает?
ответ всегда начинается с суммы баланса?
Если да, то это чуть упрощает процесс. В целом идеология такая: выделяем из пришедшего ответа первые 7 символов (один из вариантов), ищем в полученной подстроке точку (определяем номер позиции этой точки), отбрасываем все, что после "позиция точки + 2" (это если нужны копейки), преобразуем в число.
Если набирать команду ATD*101# в Serial monitor, получаю ответ вида:
OK
+CUSD: 0,"65.12 UAH. Tarif - 'Super MTS 3D Nol'. *Bezlimit na 31.12............
Я в принципе смогу поработать со строкой и выделить нужные символы, у меня не получается эту строку записать в строковую переменную.
#include <SoftwareSerial.h> String currStr = ""; boolean isStringMessage = false; SoftwareSerial gprsSerial(50, 51); void balance () { gprsSerial.println("ATD*101#"); //запрос баланса //Serial.println("zapros balansa-1"); delay(5000); } void setup() { Serial.begin(9600); gprsSerial.begin(9600); delay(300); // Настраиваем приём сообщений // Между командами даём время на их обработку gprsSerial.println("AT+CMGF=1"); //устанавливает текстовый режим смс-сообщения delay(300); gprsSerial.println("AT+IFC=1,1"); //устанавливает программный контроль потоком передачи данных delay(300); gprsSerial.print("AT+CPBS=");//открывает доступ к данным телефонной книги gprsSerial.print((char)34); gprsSerial.print("SM"); // SIM-карты gprsSerial.print((char)34); gprsSerial.print((char)13); delay(300); gprsSerial.println("AT+CNMI=1,2,2,1,0");//включает оповещение о новых сообщениях, //новые сообщения приходят в следующем формате: // +CMT: "<номер телефона>", "", "<дата, время>", //а на следующей строчке с первого символа идёт содержимое сообщения delay(500); balance(); //один раз делаю запрос баланса - для отладки } void loop() { if (gprsSerial.available()){ char currSymb = gprsSerial.read(); if ('\r' == currSymb) { if (isStringMessage) { //если текущая строка SMS сообщение, Serial.print(currStr); // печатаем эту строку isStringMessage = false; } else { if (currStr.startsWith("+CUSD")) { //если текущая строка начинается с "+CUSD", //то следующая строка является сообщением isStringMessage = true; } } currStr = ""; } else if ('\n' != currSymb) { currStr += String(currSymb); } } }Вот Serial.print(currStr); // печатаем эту строку - что-то не печатает.... Если бы мне удалось получить эту строку currStr, и проблем бы небыло.
удалить сообщение - глюк в броузере
удалить сообщение - глюк в броузере
удалить сообщение - глюк в броузере
Выкиньте всю логику начиная с 46 строки и просто выводите всё, что получили в Serial. А уж потом будете наворачивать логику, которая не факт, что правильная.
К тому же с таким форматированием текста очень легко ошибиться. Ctrl-T нажимайте прежде чем сюда текст выкладывать. Только не нужно объяснять, просто примите это как совет.
можно ведь зайти на сайте оператора в личный кабинет и глазами посмотреть, сколько осталось, так ведь проще.
или это неспортивно? :)
Не вникая в тонкости с работой gsm модуля ,накидал буквально за 5 минут:
void setup(){ Serial.begin(115200); } void loop(){ char data[]="+CUSD: 0,\"65.12 UAH. Tarif - 'Super MTS 3D Nol'. *Bezlimit na 31.12. - 5 grn. pri popolnenii s 25.11. ot 9 grn. Otkaz - *111#\"6"; char * namedata; strtok(data,"\""); namedata=strtok(NULL," "); float t=atof(namedata); Serial.print("total: "); Serial.println(t); delay(1000); }А..тут как со строками работа ,тогда не подойдет или надо переделывать
На сайте оператора можно, но я планирую сделать приложение на андроид и параметры от сигнализации будут передаваться на смартфон+управление будет со смартфона, и информация о балансе на GSM сигнализации будет передаваться в эту программу.
Проблема не с работой со строками, а в том, что не могу эту строку в строковую переменную загнать. Сейчас анализирую логику начиная с 46 строки, похоже там ошибка...
Опять глюк броузера, можно удалить это сообщение. Сам не знаю как удалить.
Все, решил проблему! Спасибо всем, кто откликнулся!
можно поделиться.
можно поделиться.
тест
Может кому пригодится:
//#include <SoftwareSerial.h> HardwareSerial & gprsSerial = Serial1; String currStr = ""; //SoftwareSerial gprsSerial(50, 51); /* void toSerial() { while(gprsSerial.available()!=0) { Serial.write(gprsSerial.read()); } } */ void balance () { gprsSerial.println("ATD*101#"); //запрос баланса delay(300); Serial.println("zapros balansa"); } void setup() { Serial.begin(9600); gprsSerial.begin(9600); // Настраиваем приём сообщений // Между командами даём время на их обработку gprsSerial.println("AT+CMGF=1"); //устанавливает текстовый режим смс-сообщения delay(300); gprsSerial.println("AT+IFC=1,1"); //устанавливает программный контроль потоком передачи данных delay(300); gprsSerial.print("AT+CPBS=");//открывает доступ к данным телефонной книги gprsSerial.print((char)34); gprsSerial.print("SM"); // SIM-карты gprsSerial.print((char)34); gprsSerial.println(""); // gprsSerial.print((char)13); delay(300); gprsSerial.println("AT+CNMI=1,2,2,1,0");//включает оповещение о новых сообщениях, //новые сообщения приходят в следующем формате: // +CMT: "<номер телефона>", "", "<дата, время>", //а на следующей строчке с первого символа идёт содержимое сообщения delay(300); balance(); } void loop() { // toSerial(); if (gprsSerial.available()){ char currSymb = gprsSerial.read(); if ('\r' == currSymb) { //если символ перевод каретки if (currStr.startsWith("+CUSD: 0,")) { int zzz = currStr.indexOf('UAH'); String balance=currStr.substring(10,zzz-3); //баланс на сим карте Serial.print(balance); } currStr = ""; } else if ('\n' != currSymb) { //если символ НЕ новая строка currStr += String(currSymb); } } }Не подскажите как переделать под такой ответ с модема:
Тоесть как выделить в новую переменную "text sms" ?
Подскажу.
HardwareSerial & gprsSerial = Serial1; String currStr = ""; boolean isStringMessage = false; int flag=1; void setup() { Serial.begin(9600); Serial.println("Begin..."); gprsSerial.begin(9600); } void loop() { if (flag==1){ gprsSerial.println("AT+CMGR=1"); delay(10); flag=0; //один раз запускаем чтение сообщения AT+CMGR=1 } if (gprsSerial.available()){ char currSymb = gprsSerial.read(); if ('\r' == currSymb) { //если символ перевод каретки if (isStringMessage) { Serial.print("currStr= "); Serial.println(currStr); //Вот это и будет текст СМС isStringMessage = false; } else { if (currStr.startsWith("+CMGR")) { isStringMessage = true; } } currStr = ""; } else if ('\n' != currSymb) { //если символ НЕ новая строка currStr += String(currSymb); } } }Всем привет! смотрю код и понять не могу - где происходит инициализация модуля для работы с библиотекой sim900.h? У меня мега2560, GSM модуль зацеплен к порту Serial1. Хочу использовать функции библиотеки Sim900.h, но в примерах инициализируется софтварный сералпорт... а как хардварный использовать и передать его в инициализацию в эту библиотеку?
код библиотеки:
#ifndef __SIM900_H__ #define __SIM900_H__ #include <SoftwareSerial.h> #include <Arduino.h> #define DEFAULT_TIMEOUT 5 //seconds #define DEFAULT_INTERCHAR_TIMEOUT 1500 //miliseconds enum DataType { CMD = 0, DATA = 1, }; void sim900_init(void * uart_device); int sim900_check_readable(); int sim900_wait_readable(int wait_time); void sim900_flush_serial(); void sim900_read_buffer(char* buffer,int count, unsigned int timeout = DEFAULT_TIMEOUT, unsigned int chartimeout = DEFAULT_INTERCHAR_TIMEOUT); void sim900_clean_buffer(char* buffer, int count); void sim900_send_byte(uint8_t data); void sim900_send_char(const char c); void sim900_send_cmd(const char* cmd); void sim900_send_cmd(const __FlashStringHelper* cmd); void sim900_send_cmd_P(const char* cmd); void sim900_send_AT(void); void sim900_send_End_Mark(void); boolean sim900_wait_for_resp(const char* resp, DataType type, unsigned int timeout = DEFAULT_TIMEOUT, unsigned int chartimeout = DEFAULT_INTERCHAR_TIMEOUT); boolean sim900_check_with_cmd(const char* cmd, const char *resp, DataType type, unsigned int timeout = DEFAULT_TIMEOUT, unsigned int chartimeout = DEFAULT_INTERCHAR_TIMEOUT); boolean sim900_check_with_cmd(const __FlashStringHelper* cmd, const char *resp, DataType type, unsigned int timeout = DEFAULT_TIMEOUT, unsigned int chartimeout = DEFAULT_INTERCHAR_TIMEOUT); #endifВроде функций то тут мало, реализовано главное - ожидание ответа в нужном формате... Каким образом цепануть библиотеку правильно в свой код?
Здравствуйте
Подскажите, кто знает, в чем может быть проблема:
Запрос баланса по кодовому слову BAL уходит, ответ в терминале видно в такой форме :
#include <DHT.h> #include <SoftwareSerial.h> #define MASTER "+380957314297" //укажите телефон хозяина SoftwareSerial mySerial(2, 3); // номера дискретных входов-выходов контроллера в качестве RX, TX DHT dht(5, DHT11); int ch = 0; String val = ""; boolean smsOn; boolean statusChanged; String statusText; void setup() { analogReference(INTERNAL); // выбираем внутреннее опорное напряжение 1.1 pinMode(6, OUTPUT); pinMode(8, OUTPUT); pinMode(10, OUTPUT); pinMode(11, OUTPUT); pinMode(12, OUTPUT); pinMode(13, INPUT); // вход массы pinMode(4, INPUT); // вход датчика движения Serial.begin(9600); Serial.println("ROP Progect"); dht.begin(); // DHT11 mySerial.begin(9600); //подключаем порт модема на скорости по умолчанию (можно менять AT-командой) mySerial.println("ATI"); //вывести в терминал иноформацию о модеме delay(100); mySerial.println("AT+CSQ"); //вывести в терминал уровень сигнала (если 99, то связи нет) delay(100); mySerial.println("AT+CLIP=1"); //включаем АОН delay(100); mySerial.println("AT+CMGF=1"); //режим кодировки СМС - обычный (для англ.) delay(100); mySerial.println("AT+CSCS=\"GSM\""); //режим кодировки текста delay(100); mySerial.println("AT+CNMI=2,2"); //отображение смс в терминале сразу после приема (без этого сообщения молча падают в память) delay(5000); } void sms(String text, String phone)//процедура отправки СМС { if (!smsOn) { return; } Serial.println("SMS send started"); mySerial.println("AT+CMGS=\"" + phone + "\""); delay(500); mySerial.print(text); delay(500); mySerial.print((char)26); delay(500); Serial.println("SMS send complete"); delay(2000); } void loop(){ // LOOP statusChanged = true; if (mySerial.available()) { //если есть данные от GSM модуля delay(800); //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана while (mySerial.available()) //сохраняем входную строку в переменную val { ch = mySerial.read(); val += char(ch); delay(100); } Serial.println("myserial" +String (val)); // дублируем сообщение в терминал } if (val.indexOf("BAL") > -1)// блок запрос баланса { mySerial.println ("ATD*101#"); delay(500); Serial.println("zapros balansa"); Serial.println ("val " + String (val)); } else if (val.indexOf("+CUSD:") > -1)// блок ответ баланса { Serial.println("otvet balansa"); Serial.println ("balSms" + String(val)); } val = ""; }в библиотеке
SoftwareSerial.hнадо увеличить объем буфераесли читать СМС с задержкой по 100 мс после КАЖДОГО символа (строка 74) - никакой буфер не поможет. Правильнее было бы выкинуть задержки в строках 69 и 74
SHA_MAN - у вас код написан в худших традициях работы с GSM. Вместо того, чтоб после отсылки команд проверять ответы модема - вы напихали в код задержек. Точнее, даже не вы. а автор скетча. так как вы этот код наверняка не писали сами, а нашли в инете. Этот код устойчиво работать не будет.
Спасибо за ответы. Это действительно мои первые шаги с ардуино и я свои "поделки" из кусочков найденных в сети скетчей пробую создавать. Глубоких знаний катастрофически нехватает, но каждый такой "глюк" заставляет копнуть и разобраться.
Я буду благодарен на направление на путь истинный в организации работы моего модема, ибо вся задумка вертится вокруг работы с смс.
в библиотеке
SoftwareSerial.hнадо увеличить объем буфераБлагодарю!!! Помогло
в библиотеке
SoftwareSerial.hнадо увеличить объем буфераБлагодарю!!! Помогло
задержки все равно лучше выкинуть, по меньшей мере в строке 74.
Увеличкение буфера - это "костыль". Памяти в МК мало и особо большим буфер не сделать. Рано или поздно все равно придет пакет, превышающий размер буфера и снова будет обрезан. А при правильной работе с Сериал можно и со стандартным буфером читать килобайты трафика.
Спасибо. Еще вопросик если можно. Полдня решал как принять всю строку, получилось наконец.
Но теперь понял, что вся она не нужна. А переменная val - в глобальных, и хранить в ней лишнее - память гробить (мне так кажется, по крайней мере).
Как принять в переменную val, допустим, первые 15 символов? Цикл строить или можно проще?
Спасибо!
while (mySerial.available()) //сохраняем входную строку в переменную val { ch = mySerial.read(); val += char(ch); // как тут указать, что только 15 символов нужны из всех? }https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/length/
Ввести переменную, считать каждый входящий байт, после 15 выходить из цикла break
Но это тоже костыль, анадизируйте весь входящий поток, и когда приходят нужные данные сохранять их в буфер и обрабатывать
Мой парсинг баланса из ответа модема в формате UCS2:
void sendbalance(const char* msg) { if (!msg) return; byte _i = 0; char _bal[8] = ""; for (;; _i += 4) { // доходим до первой цифры, символа '-' (отрицательный баланс) или конца строки if (!msg[_i]) return; if (!strncmp(msg+_i, "003", 3) && isdigit(msg[_i+3])) break; if (!strncmp(msg+_i, "002D", 4)) break; } for (;strlen(_bal)+1 < sizeof(_bal); _i += 4) // читаем пока не попадётся НЕцифра, НЕминус и НЕточка if (!strncmp(msg+_i, "002D", 4)) strcat (_bal, "-"); else if (!strncmp(msg+_i, "002E", 4)) strcat (_bal, "."); else if (!strncmp(msg+_i, "003" , 3) && isdigit(msg[_i+3])) strncat(_bal, msg+_i+3, 1); else break; // всё, количество тугриков на балансе в буфере <_bal>, дальше делайте с ним что душе угодно //.............. } //......................................................................... // здесь в буфере <at> у нас считанный ответ модема char* _ptr = NULL; _ptr = strstr(at, "+CUSD:"); if (_ptr) sendbalance(_ptr+11); //...............................................Нормально парсит деньги из ответов операторов большой четвёрки, с другими не пробовал.
Чтание в буфер ответа модема:
.//.............. byte _atlen = 0; while (modem.available()) { char _ch = modem.read(); _delay_us(200); if ( (_atlen+1) < sizeof(at) ) at[_atlen++] = _ch; } at[_atlen] = '\0';"Хвост" не поместившийся в буфер вычитывается "вникуда"
Ребята, помогите разобраться в чём дело.
симка МТС, отправляю в терминал запрос баланса AT+CUSD=1,"*100#" или ATD*100# приходит такой ответ (одинаковый):
#include <SoftwareSerial.h> String currStr = ""; String bal = ""; SoftwareSerial gprsSerial(10,11); void balance () { Serial.println("zapros balansa"); gprsSerial.println(/*"AT+CUSD=1,\"*100#\""*/"ATD*120#"); //запрос баланса } void setup() { Serial.begin(38400); gprsSerial.begin(57600); gprsSerial.println("AT+CMGF=1"); //устанавливает текстовый режим смс-сообщения delay(300); gprsSerial.println("AT+IFC=1,1"); //устанавливает программный контроль потоком передачи данных delay(300); gprsSerial.print("AT+CPBS=");//открывает доступ к данным телефонной книги gprsSerial.print((char)34); gprsSerial.print("SM"); // SIM-карты gprsSerial.print((char)34); gprsSerial.println(""); gprsSerial.print((char)13); delay(300); gprsSerial.println("AT+CMGD=4"); delay(300); gprsSerial.println("AT+CNMI=1,2,2,1,0");//включает оповещение о новых сообщениях, delay(300); balance(); } void loop() { if (gprsSerial.available()){ char currSymb = gprsSerial.read(); if ('\r' == currSymb) { //если символ перевод каретки if (currStr.startsWith("+CUSD:")) { int zzz = currStr.indexOf("\","); String balance=currStr.substring(currStr.indexOf(" \"")+2,zzz); //баланс на сим карте Serial.println(balance); bal += String (balance); // String str = ""+balance; // sms(); // rest (); } currStr = ""; } else if ('\n' != currSymb) { //если символ НЕ новая строка currStr += String(currSymb); } } //Serial.println(bal); } void rest () {gprsSerial.println("AT+CFUN=1,1");} void sms () { char b = balance; gprsSerial.println("AT+CMGS=\"+37544123456\""); delay (1000); gprsSerial.print(bal); gprsSerial.print((char)26); }Симка МТС: ATD*100# - ничего не работает, AT+CUSD=1,"*100#"- работает отлично, стабильно:
Вот тут, http://codius.ru/articles/GSM_%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_SIM800L_%D1%87%D0%B0%D1%81%D1%82%D1%8C_1 отличный цикл статей - "как работать с джиесем", оттуда же можно понять общуюю идеологию обработки ответов модема, и надергать нужные функции для своего проекта, в том числе и не сбойный обработчик баланса.
ATD<запрос> не все операторы поддерживают, пользуйтесь AT+CUSD. В любом случае парсить надо первое вхождение числовых символов в строке, способ на вскус и цвет. Выше приводил пример, но если у Вас текстовый ответ Вам ещё проще.