SIM800L, передача данных в тоновом режиме

Dron
Offline
Зарегистрирован: 17.06.2016

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

Хотел бы поделится со всеми одной своей разработкой. Может данная информация окажется кому-то полезной. На своей даче я реализовал автоматическую систему полива. Реализована она на готовых электроных таймерах. Один таймер включает насос типа "малыш", погруженный в колодец. Вода поступает в бочку. Бочка - 200 литров. Набор воды обычно происходит через день с 21:00 до 21:20. Другой таймер открывает соленойдный клапан, и подогретая окружающей средой вода поступает в систему капельного полива. Открытие клапана происходит ежедневно с 15:00 до 20:30. И все бы хорошо, но система питается от 220VAC. Бывают отключения электричества. Может засориться магистральный фильтр.  И пр... Одним словом, необходимо отслеживать изменения уровня воды в бочке. Было принято решение разработать устройство. Вот оно:Устройство состоит из четырех модулей:

- Arduino Nano;

- GSM-модуль SIM800L;

- блок питания 220VAC/5VDC;

- понижающий DC-регулятор.

Выходное напряжение DC-регулятора установлено на уровне 4.18 вольт. От него запитывается SIM800L. При этом уровне напряжения SIM (по АТ запросу) выдает заряд аккумулятора около 100%. Вообще, от этого регулятора SIM работает очень стабильно. 

Arduino и SIM в любой момент могут быть извлечены из устройства (просто, для удобства)

Хотелось бы отметить, что у Arduino Nano есть один несомненно большой плюс. Это наличие готового USB разъема. Нет необходимоти тащить ноут на дачу. Программу можно корректировать с телефона через ArduinoDroid. Можно отследить ход выполнения программы через Serial (опять же с телефона).

На первых трех аналоговых входах реализован кондуктометрический датчик. К ним и к GND подключаются электроды на разных уровнях в бочке. GND является общим электродом и подключается на самое дно бочки. Электроды на входах А0, А1 и А2 подключаются на нижнем, среднем и верхнем уровнях бочки соответственно. Как всем нам известно, значения на аналоговых входах может меняться от 0 до 1024. Значение более 1020 означает, что данный уровень водой не достигнут. Пороговое значение, при котором уровень считается достигнутым в программе установлен равным 800 (исходя из экспериментов проведенных в ванной). После установки устройства на месте, пороговое значение будет скорректированно для каждого уровня.

И так... Каков функционал данного устройства... При изменении уровня в бочке, оно звонит "хозяину". При этом мы не знаем, увеличился уровень или уменьшился. Да, конечно, можно было бы просто послать SMS-ку, и указать в ней что да как... Но исходящие SMS платны. Я не жадный, но дело принципа. Дача находится в 30-ти километрах от дома. Но это уже другой регион. Соответственно, роуминг. На этом наши сотовые операторы незаслуженно (я так считаю) наживаются. Поэтому, вместо того, чтоб слать SMS-ки, устройство нам будет звонить, а мы будем этот звонок игнорировать. Мы лучше сами позвоним на устройство, переключимся на телефоне на DTMF-приемник и в тоновом режиме примем текущие значения уровней в бочке:

Судя по картинке, бочка пуста (полив прошел успешно).

Симку нужно покупать с посекундным тарифом без каких либо ежемесячных платежей. Тогда ваши расходы на нее будут составлять 0.00 руб в месяц.

Данный способ передачи информации может быть использован и для других целей (показания датчиков и пр.). Так же в тоновом режиме можно удаленно управлять устройствами с телефона.

А так выглядит Serial Monitor, если устройство функционирует нормально:

А вот и программа:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
int ch = 0;
String val = "";  //переменная для приема данных от GSM-модуля
int level_1=0;    //переменная 1-го уровня
int level_2=0;    //переменная 2-го уровня
int level_3=0;    //переменная 3-го уровня

int level_11=0;    //промежуточная переменная 1-го уровня
int level_22=0;    //промежуточная переменная 2-го уровня
int level_33=0;    //промежуточная переменная 3-го уровня

String Level="AT+VTS="; //переменная формирования АТ команд для передачи в  GSM-модуль
String L_1="";
String L_2="";
String L_3="";

unsigned long time;
unsigned long time1=0;

void setup() {
digitalWrite(A0, 1);  //включаем подтягивающий резистор аналогового входа А0 (уровень 1)
digitalWrite(A1, 1);  //включаем подтягивающий резистор аналогового входа А1 (уровень 2)
digitalWrite(A2, 1);  //включаем подтягивающий резистор аналогового входа А2 (уровень 3)

  if(analogRead(A0)>800) level_1=level_11=0; else level_1=level_11=1; //устанавливаем порог для уровня 1 раным 800
  if(analogRead(A1)>800) level_2=level_22=0; else level_2=level_22=1; //устанавливаем порог для уровня 2 раным 800
  if(analogRead(A2)>800) level_3=level_33=0; else level_3=level_33=1; //устанавливаем порог для уровня 3 раным 800

delay(20000);           //время на инициализацию модуля
Serial.begin(19200);    //открываем COM-порт
mySerial.begin(19200);  //открываем порт GSM-модуля
mySerial.println("AT+CLIP=1");  //включаем АОН
delay(100);
mySerial.println("AT+VTD=4");  //устанавливаем длительность в тоновом режиме равной 0,4сек
delay(100);

mySerial.println("ATD+79ХХХХХХХХХ;");  //звоним на свой номер
delay(16000); 
mySerial.println("ATH0");  //разрываем связь через 16 сек
delay(100);
}

void loop() {

L_1=String(analogRead(A0)); //переводим "цифру" в String 
L_2=String(analogRead(A1)); //переводим "цифру" в String
L_3=String(analogRead(A2)); //переводим "цифру" в String
  
  if (mySerial.available()) {       //если GSM модуль что-то послал нам,
    while (mySerial.available()) {  //сохраняем входную строку в переменную val
      ch = mySerial.read();
      val += char(ch);
      delay(10);
    }
    if (val.indexOf("RING") > -1) {           //если звонок обнаружен, то проверяем номер
      if (val.indexOf("79ХХХХХХХХХ") > -1) {  //если номер звонящего наш
        Serial.println("--- MASTER RING DETECTED ---");
        digitalWrite(13, HIGH);   //включаем светодиод 
        mySerial.println("ATA");  //устанавливаем соединение
        delay(1000);              //задержка для включения DTMF-ресивера на телефоне
        mySerialLevel();          //отправляем значения уровней на DTMF-ресивер 
        mySerial.println("ATH0"); //разрываем связь

        digitalWrite(13, LOW);    //выключаем светодиод 
        }
    } else
      Serial.println(val);  //печатаем в монитор порта пришедшую строку
    val = ""; //обнуляем переменную val
  }
  

time = millis();

if((time-time1)>=5000){   //раз в 5 секунд выводим значения уровней на монитор
  
    Serial.print(L_1);    //выводим на монитор значение уровня 1
    Serial.print("\t");   //табуляция
  
    Serial.print(L_2);    //выводим на монитор значение уровня 2
    Serial.print("\t");   //табуляция
  
    Serial.print(L_3);    //выводим на монитор значение уровня 3
    Serial.print("\t");   //табуляция
  
    SerialLevel();        //выводим на монитор сформированную АТ команду
  
    //Serial.print(time); //выводим на монитор значение времени
  
    Serial.println("");   //перенос строки
                            
    time1=time;                      
  }
  
CheckLevel(); //проверяем значения уровеней
//в случае изменения звоним на свой номер

}



/***функция формирования AT+VTS команды для отслеживания в Serial ***/
void SerialLevel(){
  Level+=char(34);

  Level+=L_1[0];
  Level+=',';
  Level+=L_1[1];
  Level+=',';
  
  if(L_1[2]>47&&L_1[2]<58) {
    Level+=L_1[2];
    Level+=','; 
  }
  if(L_1[3]>47&&L_1[3]<58) {
    Level+=L_1[3];
    Level+=','; 
  }
  Level+='#';
  Level+=',';  
  Level+=L_2[0];
  Level+=',';
  Level+=L_2[1];
  Level+=',';

  if(L_2[2]>47&&L_2[2]<58) {
    Level+=L_2[2];
    Level+=','; 
  } 
  
  if(L_2[3]>47&&L_2[3]<58) {
    Level+=L_2[3];
    Level+=','; 
  } 

  Level+='#';
  Level+=','; 
  Level+=L_3[0];
  Level+=',';
  Level+=L_3[1];  
  if(L_3[2]>47&&L_3[2]<58) {
    Level+=','; 
    Level+=L_3[2];
  } 
  if(L_3[3]>47&&L_3[3]<58) {
    Level+=',';
    Level+=L_3[3];
  } 
  Level+=char(34);
  Serial.print(Level);
  Level="AT+VTS=";
  }

/***функция формирования AT+VTS команды для GSM-модуля ***/
void mySerialLevel(){
  Level+=char(34);

  Level+=L_1[0];
  Level+=',';
  Level+=L_1[1];
  Level+=',';
  
  if(L_1[2]>47&&L_1[2]<58) {
    Level+=L_1[2];
    Level+=','; 
  }
  if(L_1[3]>47&&L_1[3]<58) {
    Level+=L_1[3];
    Level+=','; 
  }
  Level+='#';
  Level+=',';  
  Level+=L_2[0];
  Level+=',';
  Level+=L_2[1];
  Level+=',';

  if(L_2[2]>47&&L_2[2]<58) {
    Level+=L_2[2];
    Level+=','; 
  } 
  
  if(L_2[3]>47&&L_2[3]<58) {
    Level+=L_2[3];
    Level+=','; 
  } 

  Level+='#';
  Level+=','; 
  Level+=L_3[0];
  Level+=',';
  Level+=L_3[1];  
  if(L_3[2]>47&&L_3[2]<58) {
    Level+=','; 
    Level+=L_3[2];
  } 
  if(L_3[3]>47&&L_3[3]<58) {
    Level+=',';
    Level+=L_3[3];
  } 
  Level+=char(34);
  mySerial.println(Level);
  delay(15000);
  //while (1) {if(mySerial.available())break;};
  Level="AT+VTS=";
  }

 /*** функция проверки изменения уровней ***/
 void CheckLevel(){
  if(analogRead(A0)>800) level_1=0; else level_1=1; //проверяем изменение уровня 1
  if(analogRead(A1)>800) level_2=0; else level_2=1; //проверяем изменение уровня 2
  if(analogRead(A2)>800) level_3=0; else level_3=1; //проверяем изменение уровня 3
  if(level_1!=level_11||level_2!=level_22||level_3!=level_33){  // если один из уровней изменился

    mySerial.println("ATD+79ХХХХХХХХХ;");  //звоним на свой номер
    delay(16000); 
    mySerial.println("ATH0");  //разрываем связь через 16 сек
    delay(60000);     //делаем задержку на "дребезг зеркала воды"
    level_11=level_1; //запоминаем текущее значение уровня 1 в промежуточной переменной
    level_22=level_2; //запоминаем текущее значение уровня 2 в промежуточной переменной
    level_33=level_3; //запоминаем текущее значение уровня 3 в промежуточной переменной

  };

}

 

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

какая полная команда  AT+VTS дается ?

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

так будет проще вникнуть.

Dron
Offline
Зарегистрирован: 17.06.2016

Для того, что бы на экране телефона получить это

 

команда должна выглядеть так: AT+VTS="1,0,2,3,#,1,0,2,3,#1,0,2,3"

 

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

кстати, а подскажите, в последнем примере генерится дтмф, но там еще  вроде есть коанды генерации коротких звуковых тоновых  сигналов - не дтмф.. не пробовали генерить? а принимать другим сим800 ??

Dron
Offline
Зарегистрирован: 17.06.2016

В данном приборе SIM800 как раз и передает короткие тоновые сигналы. Вопрос терминологии... 

DTMF Decoder
Функция декодирования DTMF-тонов (Dual-Tone Multi-Frequency)
применяется для удаленного управления GSM-устройством — напри-
мер, для запуска двигателя автомобиля с мобильного телефона при
установлении голосового соединения. Обычно декодирование тонов
реализуется при помощи внешнего кодека, подключаемого к анало-
говому выходу GSM-модуля, однако встроенная в SIM900 функция
DTMF Decoder избавляет от необходимости устанавливать в схему
дорогостоящий дополнительный элемент.
Работа этой функции регулируется при помощи простой AT-
команды:
AT+DDET=1 // Включить функцию DTMF декодирования
OK
ATDXXXXXXXXXXX; // Установить голосовое соединение
OK
+DTMF:2 // Удаленная сторона жмет на клавиши мобильного телефона
+DTMF:8
+DTMF:8
+DTMF:4
+DTMF:5
+DTMF:2
NO CARRIER // Голосовое соединение завершено
 
Прием/передача между двумя SIM не проблема. Для этого надо включить вышеописанную функцию декодирования. В моем устройстве (ПОКА) прием не предусмотрен. 
Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

там кроме дтмф есть и другое.. ладно. наверное вы не в курсе.

Dron
Offline
Зарегистрирован: 17.06.2016

Заинтриговал. Что другое? Каков принцип работы? Поищу в мануале (знать бы что искать)...

Dron
Offline
Зарегистрирован: 17.06.2016

Принцип работы моего устройства подобен тому, когда звонишь в какую-нить контору, а тебе в ответ: "Здрасте, если вам нужно то-то, то жми 1. Если другое, то жми 2. Иначе - 3. Может все-таки об одном и том же говорим?

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

Почитайте описание 1.09

Встречал, что гсм модуль может передавать "АДЕМКО" протокол, и достаточно быстро.

ДТМФ - медленный, вам удавалось дтмф передавать несколько цифр в секунду, например 5-7цифр или более?

у меня чтото не получилось, 1-2 цифры и все..

Dron
Offline
Зарегистрирован: 17.06.2016

Не могу найти 1.09. У меня есть только 1.01. Если можно ссылку, плиз...

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

он на официальном сайте симкома есть. 1.01 - очень старый.

Dron
Offline
Зарегистрирован: 17.06.2016

Нашел. По поводу скорости... Мне удавалось передавать 4-5 цифры/сек, но иногда бывали искажения. Пришлось увеличить длительность (строка 35).

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

насколько понял - при передаче абоненту сотовой связи, дтмф генерит последняя БС оператора связи.

а вот АДЕМКО можно передать бе участия БС станций, быстрее.

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

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

Dron
Offline
Зарегистрирован: 17.06.2016

Даже нужно. В поисковике искал так: SIM800_Series_AT_Command_Manual_V1.09

Если найдете в мануале про "адемко", скажите номер страницы, плиз...

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

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

Dron
Offline
Зарегистрирован: 17.06.2016

Можно ссылку на анонс?

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

сейчас не найду.

Dron
Offline
Зарегистрирован: 17.06.2016

На стр.154 нашел "AT+CLDTMF Local DTMF Tone Generation". Может это?.. Поддерживается только SIMCOM.

Dron
Offline
Зарегистрирован: 17.06.2016
Note
Local DTMF tone can be played in call, play mode is controlled by AT+DTAM.
Получается местное (со стороны SIM800) проигрывание тонов во время звонка.
Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

это помоему в динамик играет..

legionercheg
legionercheg аватар
Offline
Зарегистрирован: 03.06.2015

Dron, можно ли с вами как то связаться по имейл или вк/вайбер? А то есть куча вопросов по SIM80L ver.2.0, а задать некому...

Dron
Offline
Зарегистрирован: 17.06.2016

legionercheg, пишите сюда nosikovandrey@mail.ru. Правда, опыт у меня не велик, но чем смогу, помогу... А какие-то вопросы можно обсудить и на форуме.

 

legionercheg
legionercheg аватар
Offline
Зарегистрирован: 03.06.2015

Отправил письмо.

legionercheg
legionercheg аватар
Offline
Зарегистрирован: 03.06.2015

Dron, письмо отправил, но ответа от вас не получил. Вы мне правильный адрес указали?

Dron
Offline
Зарегистрирован: 17.06.2016

Тем, кто пробует повторить устройство... Уменьшил порог срабатывания с 800 на 400. А то слишком чувствительность большая получилась.  Срабатывает и от утренней росы (в четвертом часу утра), и от дождя. Аналоговые входы все живы. Думаю, ничего с ними не случится.

fps
Offline
Зарегистрирован: 19.09.2016

А не пробовал ли кто-нибудь здесь включать SIM800L в режиме передачи данных, как обычный проводной dial-up модем?

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

Пробую, но ATD без ; в конце сразу выдает ERROR.

Куда копать?

 

 

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

fps пишет:

А не пробовал ли кто-нибудь здесь включать SIM800L в режиме передачи данных, как обычный проводной dial-up модем?

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

Пробую, но ATD без ; в конце сразу выдает ERROR.

Куда копать?

 
 
 

 

 

сначала у оператора поинтересуйся - поддерживает он услугу CSD передачи данных или нет. а уже потом и копать можно.

Logik
Offline
Зарегистрирован: 05.08.2014

///сначала у оператора поинтересуйся - поддерживает он услугу CSD передачи данных или нет. а уже потом и копать можно.

Ага. Была както тема, хотели ЧМ сигнал по GSM передать. Тон передается первые пару секунд, а затем исчезает. Ох и надолбались пацаны с этим! Два дня искали чего сигнал пропадает. Оказалось оператор не поддерживает.

Lazyua
Offline
Зарегистрирован: 11.11.2017

Заинтересовала ваша статья. Хочу реализовать почти такую-же идею измерения уровня, только используя ультразвуковой датчик и СМС. Необходимо по входящему звонку на GSM модуль заставить Arduino отбиться, произвести замер уровня воды в емкости и ответить по СМС на звонивший номер.

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

Ввиду того что запрашивать уровень воды необходимо 1 раз в час, отсылка СМС выльется в копеечку, поэтому переделываю программу под GPRS.