GSM сигнализация M590+Arduino

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Это что за циклы такие, больше 30 сек? Для вачдога 8 сек максимум и это никогда не было проблемой. Вставьте в loop вывод millis() в порт и посмотрите. 

 

Kvolk, Вы из контекста слова выдергиваете или не поняли. Я говорю что сперва появляется спрос, потом кто-то реализует устройство, которое удовлетворяет потребностям, но дорогое, а потом китайцы это повторяют и делают максимально дешевым и с разного цвета пуговицами. И если на первом и втором этапе еще есть смысл заморачиваться с самостоятельной реализацией, то на третьему уже не очень. Разве что если хочется. Это я про копеешные бесперебойники на 18650. Да в общем-то и сигналки есть у них готовые, но тут интереснее творческий процесс плюс возможность самому сделать именно так как хочется. Но никто же не будет сам модем паять.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Short Circuit пишет:

а то, что пишут здесь этому отвечает? :) вот поэтому я написал вопрос за 30 сек.. :)

Тут его сложнее нужно прописывать, как - я пока не знаю.

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

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

Short Circuit пишет:

тоесть каждый, весь цикл в программе должен проходить всегда не медленнее чем 8 сек?  а то, что пишут здесь этому отвечает? :) вот поэтому я написал вопрос за 30 сек.. :)

простите, но 8 сек для микроконтроллера - это вечность. Особенно в программе сигнализации.

Сигнализация. у которой цикл занимает больше секунды - это сторож, который спит на работе. За 8 секунд злоумышленник легко откроет дверь, зайдет и закроет за собой - а вы даже не заметите.

Так что проблема-то не в собаке, а в кривом и не оптимальном коде. Даже если вы не станете встраивать в программу вотчдог - код все равно надо кардинально переписывать., так как сигналка, у которой цикл занимает несколько секунд и более - по сути бесполезна.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

 Umka, хороший обзор! спасибо что поделился знаниями ;)

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Стараюсь. Спасибо.

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

b707 пишет:

Так что проблема-то не в собаке, а в кривом и не оптимальном коде. Даже если вы не станете встраивать в программу вотчдог - код все равно надо кардинально переписывать., так как сигналка, у которой цикл занимает несколько секунд и более - по сути бесполезна.

так я о том же:)  

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

pasha413
Offline
Зарегистрирован: 27.11.2016

Интересно сколько времени занимает выполнение моего кода?)

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

pasha413 пишет:
Интересно сколько времени занимает выполнение моего кода?)

вставьте миллис в начале и конце loop да и посмотрите. Только величина эта очень непостоянная. Как только в коде начинается работа с модемом, идут куча задержек и таймаутов. Думаю, при отправке и приеме СМС тормоза максимальны и счет может идти на десятки секунд.

kkzim
kkzim аватар
Offline
Зарегистрирован: 30.08.2017

Привет парни.

Кто пробовал или освоил язык программирования FBD  и программу FLProg

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

pasha413
Offline
Зарегистрирован: 27.11.2016

kkzim, пробовал, но до сигналки не дошел.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

kkzim пишет:

Кто пробовал или освоил язык программирования FBD  и программу FLProg

Вы думаете стоит тратить время на "FLProg", если его разработчики жирным красным шрифтом, буквально на знамени пишут абсолюную ахинею: "Чтобы программировать микроконтроллеры не обязательно знать языки программирования!"? так и хочется добавить, а "чтобы делать операции на сердце не обязательно знать анатомию, физиолгию и иметь навыки кардиохирурга".

Идиотизм там зашкаливает: "Они могут придумать, нарисовать, собрать, отладить и запустить сложнейшие схемы, но If, For, Case, Void и т.п. - это не для них". Похоже, авторы сами не сумели "if" освоить и не понимают, что если у человека есть голова, то уж как-нибудь эту хрень он поймёт, а если нет головы, то никакие "сложнейшие схемы" всё равно никогда не заработают.

vitez
Offline
Зарегистрирован: 04.11.2015

Реализовал несколько проектов с помощью FLProg. В том числе сигналку на дачу. Работала с Sim 900? потом переделал на М590. Собственно сигналка, еще собирает данные с трех датчиков температуры, мониторит расход злектричества,  дисплей hd44780. Полтора года, все отработало отлично. На данном форуме вы получите только негатив относительно данной программы. Тут может быть много слов про правильность кода и бла бла бла. Может правильно. Но проекты созданные в FLPog работают. Хотите научиться работать с FLProg, найдите профильный форум.

vitez
Offline
Зарегистрирован: 04.11.2015

Вот собственно начальный  вариант сигнализации. Там все очень страшно с точки зрения монтажа. ))) Попросили снять видео, я снял. Сейчас все переделал.

https://youtu.be/mmt7hjMBfvE

Я не знаю С++ Все написанно в FLProge

pasha413
Offline
Зарегистрирован: 27.11.2016

неплохо сделано но ценник...6500....

http://gsmgps.narod.ru/example.htm

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

vitez пишет:

 На данном форуме вы получите только негатив относительно данной программы. Тут может быть много слов про правильность кода и бла бла бла. Может правильно. Но проекты созданные в FLPog работают.

Конечно работают. Ведь и на трехколесном велосипеде можно кататься, и даже удобнее - не надо учиться держать равновесие. Только почему-то дети, когда становятся чуть постарше, уже хотят "на взрослом".

Любые подобные системы сильно ограничивают программиста в наборе железа и в написании программы.  Без них программы получаются интереснее и эффективнее. Если конечно, уметь программировать. Это как панельное здание против частного дома. Частный дом может быть уродливым и неудобным, а может быть произведением искусства. А панель - она панель и есть.

Если "я не знаю С++" - это предмет гордости, то разговор бесполезен. Мы живем в разных мирах. Если хочется вообще ни во что не вникать - FLProg, наверно, выход. Хотя лично я не понимаю, в чем радость собирать систему. не понимая. как она работает...  Ведь самое интересное - именно вникнуть.

 

ЗЫ Хотя, конечно, собирать свое в FLProg - это уже явно лучше, чем повторять чужие проекты по готовым схемам и прошивкам...

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

Набросал скетч, в нем оправка смс с несколькими строками.

Так вот ньюанс -  после какого то события  в  смс  отправляется только 1-2 последние строки.

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

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

Может это особенность самой атмеги?

Скетч использует 23090 байт (75%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 621 байт (30%) динамической памяти, оставляя 1427 байт для локальных переменных. Максимум: 2048 байт.
буду благодарен за дельные советы.
kvolk
Offline
Зарегистрирован: 12.06.2017

Short Circuit пишет:

Набросал скетч, в нем оправка смс с несколькими строками.

1) ПАмять оперативная. Есть процедуры или фнкции которые вызывают или передают параметры в другие функции и процдуры, и так дале.

Если вы передаёте из одной функции/процедуры строку типа "Бла-бла-бла" в другую функцию/процедуру, то пока не закончится выполнение всех этих вложенных функций/процедур оперативная память выделенная под эти передаваемые переменные высвобождена не будет, и при передаче строки из функции/процедуры в функцию/процедуру для каждой строки "Бла-бла-бла" будет резервироваться объём памяти. 

2) Увеличить буфер софтваресериал, если вы этого не сделали.

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

2)  а до какого размера увеличить? я не был уверен, что проблема может быть в этом.

1) как после передачи данных  "чистить память" ? может есть специальные приемы?

pasha413
Offline
Зарегистрирован: 27.11.2016

У меня смс с информацией о состоянии системы 135 символов, Скетч занимает 66%, и 36% динамической.
Завтра выложу оптимизированные скетчи с lcd1602 который с кнопками (задержка при постановке на охрану с него), и без шилда.

kvolk
Offline
Зарегистрирован: 12.06.2017

Short Circuit пишет:

2)  а до какого размера увеличить? я не был уверен, что проблема может быть в этом.

1) как после передачи данных  "чистить память" ? может есть специальные приемы?

2) В своём проекте использую значение:

В файл SoftwareSerial.h (C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SoftwareSerial\src\SoftwareSerial.h) необходимо внести изменения

#define _SS_MAX_RX_BUFF 192

1) Вот пример, во время выполнения функций/процедур, эти параметры в памяти будут плодить дубликаты самих себя. То есть, пока не выполнится последняя процедура eepromeditsensor все пременные и строки передаваемые до вызова этой вложенной функции будух храниться в озу. Никаких приёмов нет, всё чистится само после выполнения вложенных функций или процедур.

void blablabla (String val) {
    if ((val.indexOf( F ("editsensor")) > -1)) {
      editsensor(val);
}

void editsensor (String val) {
	...
	...
	eepromeditsensor(SmsEditSensorName, SmsCell.toInt(), SmsHoL);
}

void eepromeditsensor(String EditSensorName, uint8_t SensorNumber, uint8_t LorH ) {
	...
	...
}

И при компиляции вы видите что объём памяи озу занят лишь на 30 процентов, а при выплнении подобного кода память может сожраться в момент, и после этого начинаются глюки и неадекватное поведение программы.

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

kvolk пишет:

И при компиляции вы видите что объём памяи озу занят лишь на 30 процентов, а при выплнении подобного кода память может сожраться в момент, и после этого начинаются глюки и неадекватное поведение программы.

ну да, есть и у меня  подобное, но ведь по другому вроде никак?  

или можно подобный код оптимизировать?

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

kvolk пишет:

 

1) Вот пример, во время выполнения функций/процедур, 

void blablabla (String val) {
    if ((val.indexOf( F ("editsensor")) > -1)) {
      editsensor(val);
}

void editsensor (String val) {
	...
	...
	eepromeditsensor(SmsEditSensorName, SmsCell.toInt(), SmsHoL);
}

void eepromeditsensor(String EditSensorName, uint8_t SensorNumber, uint8_t LorH ) {
	...
	...
}

Плохой пример, негодный - вас кто учил передавать комплексные типы в функцию по значению? У вас кучу ненужных, и даже вредных, с точки зрения расхода памяти, созданий копий объектов на стеке. Надо так:

void blablabla (const String& val)
void editsensor (const String& val)
​void eepromeditsensor(const String& EditSensorName, uint8_t SensorNumber, uint8_t LorH )
 

и далее по списку.

pasha413
Offline
Зарегистрирован: 27.11.2016

оптимизировал до:

Скетч использует 17738 байт (57%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 708 байт (34%) динамической памяти, оставляя 1340 байт для локальных переменных. Максимум: 2048 байт.

 

// max длинна сообщения в данный момент 135 символов.

#include <EEPROM.h> 
#include <OneWire.h>
#include <RCSwitch.h>
#include <SoftwareSerial.h>
#define Ver F("Alarm  v4.4\n")

OneWire ds(6);                  // датчик температуры подключен к 6 пину, подтяжка 4.7кОм на +.
SoftwareSerial gsm(7, 8);  // модем подключен к 7 и 8 пинам.
RCSwitch mySwitch = RCSwitch(); // беспроводной датчик двери, пин 2.

#define DOOR 4             // пин 4. концевик двери.
#define PIR 5              // пин 5. датчик движения.
#define LED 13             // пин 13. состояние системы.
#define GAS 14             // пин A0. датчик дыма.
#define BUZ 15             // пин A1. сирена.

// DOOR     - если сработал, на входе "+" HIGH.
// DOOR2    - если сработал, на пин 2 сигнал.
// PIR      - если сработал, на входе "+" HIGH.
// GAS      - если сработал, на входе "+" HIGH.
// BUZ      - если "-" LOW, то горит. 
// LED      - если "-" LOW, то горит.

#define on "on"     // вкл
#define off "off"   // выкл

int8_t Guard = 0;          // 1. охрана:                         1 - вкл, 0 - выкл.
int8_t AlarmRING = 1;      // 2. вызов при сработке:             1 - вкл, 0 - выкл.
int8_t SendSMS = 1;        // 3. отправка смс при сработке:      1 - вкл, 0 - выкл.
int8_t DOORon = 1;         // 4. контроль концевика двери:       1 - вкл, 0 - выкл.    
int8_t DOOR2on = 1;        // 4. контроль концевика двери 2:     1 - вкл, 0 - выкл.    
int8_t PIRon = 1;          // 5. контроль датчика движения:      1 - вкл, 0 - выкл.
int8_t GASon = 1;          // 6. контроль датчика дыма:          1 - вкл, 0 - выкл.
int8_t Sirena = 1;         // 7. сирена:                         1 - вкл, 0 - выкл. 

int8_t DOORFlag = 0;       // флаг состояние датчика двери.
int8_t DOOR2Flag = 0;      // флаг состояние датчика двери 2.
int8_t PIRFlag = 0;        // флаг состояние датчика движения.
int8_t GASFlag = 0;        // флаг состояние датчика газа.
int8_t DOORState = LOW;    // Состояние концевика двери.
int8_t PIRState = LOW;     // Состояние датчика движения.
int8_t LEDState = HIGH;    // Состояние светодиода.
int8_t Smoky = LOW;        // Состояние датчика газа.
int8_t Firststart = 1;     // первый старт.
int8_t sendsmscaller = 1;  // разрешение отправки смс.

uint32_t msAT = 0;
#define door2 3258553 // адрес 433 передатчика геркона двери

char Bal[4];               // для временного хранения номера баланса.   
char Phone[12];            // для временного хранения номера телефона.      
byte Adress[5] = {25, 40, 55, 70, 85}; // ячейки для пяти номеров в ЕЕПРОМ.

String val = "";                // переменная для хранения пришедших данных.   
String temp = "";               // температура.
String LastEvent = "";          // полное состояние системы.
String EEPhone = "";            // все номера из EEPROM.
String RingPhone = "";          // номер звонившего.
String AlarmPhone[5];      // номера для постановки/снятии с охраны и отправки смс.

int p = 0;
#define GASThres 400           // предельная концентрация газа
#define interval_alarm 20      // Секунд до отключения "тревожного" пина. 
int previousMillis_alarm = 0;
#define interval_led 1000      // для мигания LED, 1 сек.
int previousMillis_led = 0;
#define interval_door 10       // секунд не смотрим на датчик двери.
int previousMillis_door = 0;
#define interval_door2 10      // секунд не смотрим на датчик двери 2.
int previousMillis_door2 = 0;
#define interval_pir 20        // секунд не смотрим на датчик движения.
int previousMillis_pir = 0;
#define interval_gas 600       // секунд не смотрим на датчик газа. 10минут
int previousMillis_gas = 0;
#define interval_t 1800        // секунд между измерениями температуры. 30минут
int previousMillis_t = 0;

/* EEPROM Data:
  № ячейки - значение:
  0 - если записана не 1, то необходимо затереть eeprom и восстановить стандартную конфигурацию.
  1 - Guard = 0;       // охрана:             0 - выкл.
  2 - AlarmRING = 1;   // звонок:             1 - вкл. 
  3 - SendSMS = 1;     // отправка смс:       1 - вкл.
  4 - DOORon = 1;      // концевик двери:     1 - вкл.
  5 - DOOR2on = 1;     // концевик двери 2:   1 - вкл.
  6 - PIRon = 1;       // датчик движения:    1 - вкл.
  7 - GASon = 1;       // датчик дыма:        1 - вкл.
  8 - Sirena = 1;      // сирена:             1 - вкл.
  10 - Firststars = 1; // первый запуск       1.
  20 - ячейка памяти баланса,
  25, 40, 55, 70, 85 - ячейки памяти телефонов.
  100 - ячейка памяти номера последнего звонившего RingPhone.
*/

void setup() { /// === настройка программы === ///
  Serial.begin(9600); 
  Serial.println(Ver); 
  pinMode(DOOR, INPUT_PULLUP);      // вход датчика двери с подтяжкой на +.
  pinMode(PIR, INPUT);           
  pinMode(GAS, INPUT);           
  pinMode(BUZ, OUTPUT);
  pinMode(LED, OUTPUT);             // светодиод горит во время запуска.
    digitalWrite(BUZ, HIGH);        // сирена выкл.
    digitalWrite(PIR, HIGH);        // игнорируем при включении.
  InitModem();                      // запускаем инициализация модема.
  eepromconfig();
  eepromtext();
  eepromphone();
  mySwitch.enableReceive(0);        // 433 приемник на 2 пине
  Serial.println(LastEvent); 
  Serial.println(EEPhone); 
    digitalWrite(LED, HIGH);        // гасим светодиод состояния сигнализации. 
}  
                                 
void loop() {  /// === основной цикл программы === ///
  AlarmPinOff();    // выключаем сирену, если прошло  время.
  if (Guard == 1) { // если на охране
    Detect();       // проверяем датчики.
    Led();          // моргаем светодиодом.
  }
  TempC();
  if (gsm.available()) {           // если GSM модем что-то послал.
    gsmread();
  } else if (Serial.available()) { // если в мониторе порта что-то ввели
      serialread();
    }
}

void serialread() {  // 
    while (Serial.available()) {
      char ch = Serial.read();  
      val += char(ch);
     if (ch == '\n') {
       sendsmscaller = 0;
  Komand();                        // запускаем консольную программу
       val = "";  
       sendsmscaller = 1;
      } 
    } 
}

void gsmread() {
   while (gsm.available()) {
     char ch = gsm.read();  
     val += char(ch);
     if (ch == '\n') {
       gsmcom();
       val = "";
     } 
   } 
}

void gsmcom() {
    if (val.indexOf(F("+PBREADY")) > -1) InitModem();
    else if (val.indexOf(F("+CLIP")) > -1) {        // если обнаружен вызов.
//  Serial.println(F("Process RING"));                              
      delay(2000);                             // дадим гудок
      gsm.println(F("ATH"));              // сбрасываем вызов.
      if (CheckPhone() == 1) {                 // проверяем номер, если наш.
//  Serial.println(F("Master Ring OK!"));
  MasterRing();                                // меняем состояние охраны
      }// else  Serial.println(F("No Master Ring!"));  
    } else if (val.indexOf(F("+CMT")) > -1) {  // если обнаруженa СМС
//  Serial.println(F("Process CMT"));                            
//  Serial.println(String(F("SMS->")) + val);    // что пришло в смс
        if (CheckPhone() == 1) {               // если СМС от хозяина
//  Serial.println(F("Master SMS OK!"));
  Komand();
        }// else  Serial.println(F("No Master SMS!"));
      } else if(val.indexOf(F("+CUSD:")) > -1) { // если пришел баланс 
        // команда проверки баланса  AT+CUSD=1,#105#,15
        // анализируем строку 
        int p1 = val.indexOf("\"");         // начало строки
        int p2 = val.lastIndexOf("\"");     // конец строки
        val = val.substring(p1+1,p2);
//        Serial.println("");
//        Serial.println(F("Input string:"));    // пишем в порт пришедшую строку
//        Serial.println(val);
        String decodestr;
        Decode7bit(val, decodestr);
//        Serial.println("");
//        Serial.println(F("Decode string:"));   // пишем в порт конвертированную строку
//        Serial.println(decodestr);
sms("SIM " + decodestr + "\n", 0);    // смс на последний звонивший
        gsm.println(F("AT+CUSD=0"));
         } val = ""; 
}

int CheckPhone() { /// === проверка телефона === ///
  if (Firststart == 0) {                        // если не первый старт
    for (int i = 0; i < 5; i++) {
      if (val.indexOf(AlarmPhone[i]) > -1 && val.indexOf(AlarmPhone[i]) != 0) { // если есть вызов, и он наш
        RingPhone = AlarmPhone[i];              // запоминаем его.
        RingPhone.toCharArray(Phone, 12);   
        EEPROM.put(100, Phone);                 // записываем RingPhone в память. 
  Serial.println(String(F("RingPhone ")) + RingPhone);          
        return 1;                               // возвращаем 1 - номер наш!
      } 
    } return 0;                                 // возвращаем 0 - номер не наш!
  } else if (Firststart == 1) {                 // иначе (если первый старт)
// первый звонивший добавляется как основной мастер номер для управления сигнализацией
      if (val.indexOf(F("+CLIP: \"7")) > -1) {
      int ind = val.indexOf(F("+CLIP:"));          // обрезаем номер 
      String num = val.substring(ind + 8, ind + 19); 
      num.toCharArray(Phone, 12);
      EEPROM.put(25, Phone);                    // пишем номер в EEPROM
      EEPROM.put(100, Phone);                   // записываем RingPhone в память. 
      AlarmPhone[0] = Phone;                    // запишем
      RingPhone = Phone;                        // запоминаем его.
      EEPROM.update(10, 0);                     // обновляем Firststart
      Firststart = 0;                           // пишем 0
  Serial.println(String(F("Firststart:")) + Firststart);
sms(String(F("Master0:")) + num + " Ok\n", 0);     // смс на звонивший
//  приходит смс в виде: " Master0:79111234567 Ok "
      }
    } return 1;                               
}

void eepromconfig() { /// === конфигурирование сигнализации === ///
    if (EEPROM.read(0) != 1) {           // если записана не 1
      for (int i = 0 ; i < 512 ; i++) {  // переписываем все ячейки
        EEPROM.write(i, 0);
      }                      // и записываем:
      EEPROM.update(1, 0);   // Guard       охрана выкл.
      EEPROM.update(2, 1);   // AlarmRING   вызов вкл.
      EEPROM.update(3, 1);   // SendSMS     смс вкл.
      EEPROM.update(4, 1);   // DOORon      датчики дверей вкл.
      EEPROM.update(5, 1);   // DOOR2on     датчики дверей вкл.
      EEPROM.update(6, 1);   // PIRon       датчик движения вкл.
      EEPROM.update(7, 1);   // GASon       датчик газа вкл.
      EEPROM.update(8, 1);   // Sirena      сирена вкл.
      EEPROM.update(10, 1);  // Firststart  первый старт!.
      EEPROM.update(20, 0);  // баланс, записываем массив в EEPROM 
      EEPROM.update(0, 1);   // 
  Serial.println(F("EEPROM != 1/ RESET!")); 
    } else if (EEPROM.read(0) == 1) {
      Guard      = EEPROM.read(1);   // Охрана
      AlarmRING  = EEPROM.read(2);   // Вызов
      SendSMS    = EEPROM.read(3);   // Отправка смс
      DOORon     = EEPROM.read(4);   // Датчик двери
      DOOR2on    = EEPROM.read(5);   // Датчик двери
      PIRon      = EEPROM.read(6);   // Датчик движения
      GASon      = EEPROM.read(7);   // Датчик газа/дыма
      Sirena     = EEPROM.read(8);   // сирена
      Firststart = EEPROM.read(10);  //
    }
}

void eepromtext() { /// === состояние системы === ///
   String SIGN = "";         // текущее состояние системы.
   String SIRENA = "";       // аварийная сирена.
   String RING = "";         // текущее состояние вызов.
   String SMS = "";          // текущее состояние смс.
   String Door = "";         // текущее состояние датчика двери.
   String Door2 = "";        // текущее состояние датчика двери.
   String Pir = "";          // текущее состояние датчика движения.
   String Gas = "";          // текущее состояние датчика газа.
   if (Guard == 1) SIGN = F("System on\n"); else SIGN = F("System off\n");
   if (Sirena == 1) SIRENA = F("Sirena on\n"); else SIRENA = F("Sirena off\n");
   if (AlarmRING == 1) RING = F("Ring on\n"); else RING = F("Ring off\n");
   if (SendSMS == 1) SMS = F("SMS on\n"); else SMS = F("SMS off\n");
   if (DOORon == 1) Door = F("Door on\n"); else Door = F("Door off\n");
   if (DOOR2on == 1) Door2 = F("Door2 on\n"); else Door2 = F("Door2 off\n");
   if (PIRon == 1) Pir = F("Pir on\n"); else Pir = F("Pir off\n");
   if (GASon == 1) Gas = F("Gas on\n"); else Gas = F("Gas off\n");
    String System = SIGN + SIRENA + RING + SMS;     // состояние (вкл/выкл) системы.
    String Sensors = Pir + Door + Door2 + Gas;       // состояние (вкл/выкл) датчиков.
    LastEvent = System + Sensors;             // полное состояние системы и датчиков.
}

void eepromphone() { /// === чтение мастер-номеров из EEPROM === ///
    for (int i = 0; i < 5 ; i++) {
      EEPROM.get(Adress[i], Phone);        // считываем мастер-номера 
      AlarmPhone[i] = Phone;
    }
    String numbers = "[0] " + AlarmPhone[0] + "\n[1] " + AlarmPhone[1] + "\n[2] " + AlarmPhone[2] + "\n[3] " + AlarmPhone[3] + "\n[4] " + AlarmPhone[4] + "\n";
    EEPROM.get(100, Phone);                // считываем номер последнего звонившего
    RingPhone = Phone;
    String ring = String(F("Ring ")) + RingPhone + "\n";
    EEPROM.get(20, Bal);                   // считываем номер баланса
    String bal = String(F("Balance *")) + Bal + "#\n"; 
    Firststart = EEPROM.read(10);          // cчитаем первый старт
    String FST;
    if (Firststart == 1) FST = F("Firststart Yes"); else FST = F("Firststart No");
    EEPhone = numbers + ring + bal + FST + "\n";
}

void Detect() { /// === чтение датчиков === ///
  DOORState = digitalRead(DOOR);
  PIRState = digitalRead(PIR);
  Smoky = analogRead(GAS);
  
  if (DOORon == 1) {
    if (DOORState == HIGH && DOORFlag == 0) {
      previousMillis_door = millis();
      DOORFlag = 1;
//  Serial.println(F("Dver' otkrita!"));
  Alarm();                                // 
    }
    else if (DOORState == LOW && DOORFlag == 1) {
      int currentMillis_door = millis();
      if (((currentMillis_door - previousMillis_door) / 1000 > interval_door)) {
        DOORFlag = 0;
      }
    }
  }
  if (DOOR2on == 1) {
    if (mySwitch.available()) {
      unsigned long value = mySwitch.getReceivedValue();
      if (value == door2 && DOOR2Flag == 0) {
        previousMillis_door2 = millis();
        DOOR2Flag = 1;
//  Serial.println(F("Dver' 2 otkrita!"));
  Alarm();                                // 
      }
      mySwitch.resetAvailable();
    }
    int currentMillis_door2 = millis();
    if (((currentMillis_door2 - previousMillis_door2) / 1000 > interval_door2)) {
      DOOR2Flag = 0;
    }
  }
  if (PIRon == 1) {
    if (PIRState == HIGH && PIRFlag == 0) {
      previousMillis_pir = millis();
      PIRFlag = 1;
//  Serial.println(F("Dvizhenie u dveri!"));
  Alarm();                                // 
    }
    else if (PIRState == LOW && PIRFlag == 1) {
      int currentMillis_pir = millis();
      if (((currentMillis_pir - previousMillis_pir) / 1000 > interval_pir)) {
        PIRFlag = 0; 
      }
    }
  }
  if (GASon == 1) {
    if ((Smoky > GASThres) && GASFlag == 0) {
      previousMillis_gas = millis();
      GASFlag = 1;
      delay(100);
//  Serial.println(F("Gas v dome!"));
  Alarm();                                // 
    }
    else if ((Smoky < GASThres) && GASFlag == 1) {
      int currentMillis_gas = millis();
      if (((currentMillis_gas - previousMillis_gas) / 1000 > interval_gas)) {
        GASFlag = 0; 
      }
    }
  }
}

void Alarm() { /// === запускаем сирену и отправку смс === ///
  if (Guard == 1) {
    previousMillis_alarm = millis();
    if (Sirena == 1) digitalWrite(BUZ, LOW);
    Serial.println(F("Alarm!!!"));  
    if (SendSMS == 1) {
        if (DOORFlag == 1) {
sms(F("Dver' otkrita!\n"), 1); // смс на все номера
        }
        else if (DOOR2Flag == 1) {
sms(F("Dver' 2 otkrita!\n"), 1); // смс на все номера
        }
        else if (PIRFlag == 1) {
sms(F("Dvizhenie y dveri!\n"), 1); // смс на все номера
        }
        else if (GASFlag == 1) {
sms(F("Gas v dome!\n"), 1); // смс на все номера
        }
    }
    if (AlarmRING == 1) {
      gsm.println("ATD+" + String(AlarmPhone[0]) + ";"); // звоним первому номеру
    }
  }
}

void AlarmPinOff() { /// === если прошло время, отключаем сирену === ///      
  int currentMillis_alarm = millis();
  if (((currentMillis_alarm - previousMillis_alarm) / 1000 > interval_alarm) || Guard == 0) {
    digitalWrite(BUZ, HIGH);
  } 
}

void MasterRing() { /// === мастер звонков === //
  if (Guard == 1) GuardOff();     // меняем состояние
  else if (Guard == 0) GuardOn(); // меняем состояние
}

void GuardOff() { /// === выключение сигнализации === ///
    Guard = 0;
    EEPROM.update(1, Guard);
sms(String(F("System->off ")) + RingPhone + "\n", 1); // смс на все номера
}

void GuardOn() { /// === включение сигнализации === ///       
    Guard = 1;
    EEPROM.update(1, Guard);
sms(String(F("System->on ")) + RingPhone + "\n", 1); // смс на все номера
}

void Led() { /// === состояние светодиода === ///
  if (Guard == 1) {                   // если на охране
  int currentMillis_led = millis();  // светодиод моргает
  //проверяем не прошел ли нужный интервал, если прошел то
    if (currentMillis_led - previousMillis_led > interval_led) {
      // сохраняем время последнего переключения
      previousMillis_led = currentMillis_led;
      // если светодиод не горит, то зажигаем, и наоборот
      if (LEDState == HIGH) LEDState = LOW;
      else LEDState = HIGH;
      digitalWrite(LED, LEDState);
    }
  } else digitalWrite(LED, HIGH); // иначе гасим его
}

void Komand() { /// === мастер смс === ///
    val.toLowerCase();
  if (RingPhone == AlarmPhone[0] || sendsmscaller == 0) {        // команды выполняются только с 0 мастер номера
    if (val.indexOf(F("reset")) > -1)    { // полный сброс ЕЕПРОМ
sms(F("All System Reset!\n"), 0); // смс на последний номер
      EEPROM.write(0, 0);
  eepromconfig();
  eepromtext();
  eepromphone();
    }
    else if ((p = val.indexOf(F("master"))) > -1)  { // добавление мастер-номера
      master(val.substring(p + 6, p + 7).toInt(), val.substring(p + 8, p + 19));
///// sms типа: " master1:79111234567 " - ячейка + номер
    }
    else if ((p = val.indexOf(F("balance:"))) > -1) { // добавление номера баланса
      balnum(val.substring(p + 8, p + 11));
///// sms типа: " balance:100 " - номер баланса
    } 
    else if ((p = val.indexOf(F("dell:"))) > -1) { // удаление номера из ячейки     
      dellphone(val.substring(p + 5, p + 6).toInt());
///// sms типа: " dell:1 " - удалить номер из ячейки 1
    } 
    else if (val.indexOf(F("phone")) > -1)     { // инфо о номерах системы
  eepromphone();
sms(EEPhone, 0); // смс на последний номер
    }
  }  
  if (val.indexOf(F("info")) > -1) {     // инфо о состоянии системы
  eepromconfig();
  delay(100);
  eepromtext();
sms(LastEvent, 0); // смс на последний номер
  }
  else if (val.indexOf(F("money")) > -1)    {   // запрос баланса
  balance();
  }
  else if (val.indexOf(F("datchiki")) > -1) {
    if (val.indexOf(on) > -1) {       // вкл 
      DOORon = 1;
      DOOR2on = 1;
      PIRon = 1;
      GASon = 1;
      EEPROM.update(4, DOORon);
      EEPROM.update(5, DOOR2on);
      EEPROM.update(6, PIRon);
      EEPROM.update(7, GASon);
sms(String(F("datchiki->on ")) + RingPhone  + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1) {       // выкл 
      DOORon = 0;
      DOOR2on = 0;
      PIRon = 0;
      GASon = 0;
      EEPROM.update(4, DOORon);
      EEPROM.update(5, DOOR2on);
      EEPROM.update(6, PIRon);
      EEPROM.update(7, GASon);
sms(String(F("datchiki->off ")) + RingPhone  + "\n", 1); // смс на все номера
    }
  }
  else if (val.indexOf(F("system")) > -1)  {  // вкл/выкл сигнализацию
    if (val.indexOf(on) > -1)  {    // вкл 
  GuardOn();
    }
    else if (val.indexOf(off) > -1)  {    // вкл
  GuardOff();
    }
  }
  else if (val.indexOf(F("sirena")) > -1) {     // вкл/выкл сирены
    if (val.indexOf(on) > -1) {       // вкл 
      Sirena = 1;
      EEPROM.update(8, Sirena);                   
//  Serial.println(F("Sirena->on"));      
sms(String(F("Sirena->on ")) + RingPhone  + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1) {      // выкл
      Sirena = 0;
      EEPROM.update(8, Sirena);                   
//  Serial.println(F("Sirena->off"));      
sms(String(F("sirena->off ")) + RingPhone  + "\n", 1); // смс на все номера
    }
  }
  else if (val.indexOf(F("ring")) > -1)   { // вкл/выкл вызов при сработке
    if (val.indexOf(on) > -1)   { // вкл 
      AlarmRING = 1;
      EEPROM.update(2, AlarmRING);
sms(String(F("Ring->on ")) + RingPhone  + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1)   { // выкл 
      AlarmRING = 0;
      EEPROM.update(2, AlarmRING);
sms(String(F("Ring->off ")) + RingPhone  + "\n", 1); // смс на все номера
    }
  }
  else if (val.indexOf(F("sms")) > -1)    { // вкл/выкл смс при сработке
    if (val.indexOf(on) > -1)    { // вкл 
      SendSMS = 1;
      EEPROM.update(3, SendSMS);
sms(String(F("SMS->on ")) + RingPhone + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1)    { // выкл
      SendSMS = 0;
      EEPROM.update(3, SendSMS);
sms(String(F("SMS->off ")) + RingPhone + "\n", 1); // смс на все номера
    }
  }
  else if (val.indexOf(F("door")) > -1) {  // вкл/выкл контроль датчика двери
    if (val.indexOf(on) > -1) {  // выкл
      DOORon = 1;
      EEPROM.update(4, DOORon);
sms(String(F("DOOR->on ")) + RingPhone + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1) {  // выкл контроль датчика двери
      DOORon = 0;
      EEPROM.update(4, DOORon);
sms(String(F("DOOR->off ")) + RingPhone + "\n", 1); // смс на все номера
    }
  }
  else if (val.indexOf(F("door2")) > -1) {  // вкл/выкл контроль датчика двери 2
    if (val.indexOf(on) > -1) {  // вкл
      DOOR2on = 1;
      EEPROM.update(5, DOOR2on);
sms(String(F("DOOR2->on ")) + RingPhone + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1) {  // выкл 
      DOOR2on = 0;
      EEPROM.update(5, DOOR2on);
sms(String(F("DOOR2->off ")) + RingPhone + "\n", 1); // смс на все номера
    }
  }
  else if (val.indexOf(F("pir")) > -1) {  // вкл/выкл контрол датчика движения
    if (val.indexOf(on) > -1) {  // вкл
      PIRon = 1;
      EEPROM.update(6, PIRon);
sms(String(F("PIR->on ")) + RingPhone + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1) {  // выкл
      PIRon = 0;
      EEPROM.update(6, PIRon);
sms(String(F("PIR->off ")) + RingPhone + "\n", 1); // смс на все номера
    }
  }
  else if (val.indexOf(F("gas")) > -1) {  // вкл/выкл контроль датчика газа
    if (val.indexOf(on) > -1) {  // вкл 
      GASon = 1;
      EEPROM.update(7, GASon);
sms(String(F("GAS->on ")) + RingPhone + "\n", 1); // смс на все номера
    }
    else if (val.indexOf(off) > -1) {  // выкл 
      GASon = 0;
      EEPROM.update(7, GASon);
sms(String(F("GAS->off ")) + RingPhone + "\n", 1); // смс на все номера
    }
  }
}

void balance() { /// === проверка баланса сим-карты === ///
  EEPROM.get(20, Bal);        // считываем массив символов
  delay(100);
  gsm.println(String(F("AT+CUSD=1,#")) + Bal + "#,15");
//  Serial.println(String(F("Balance#")) + Bal + "#"); 
}

int master (int i, String num) { /// === добавление мастер-номеров === ///
    if (i < 5 && i != 0) {
      num.toCharArray(Phone, 12); // конвертируем
      AlarmPhone[i] = num;        // пишем номер  
      EEPROM.put(Adress[i], Phone);           // записываем массив в EEPROM 
sms(String("Master") + i + ":" + num + " add\n", 0); // смс на 0 номер.
    }// else Serial.println(F("MAX number 4!"));             // 4 номера максимум! 
    // 0 номер можно удалить только через RESET!!!
    return 1;                             
}                              

int dellphone (int i) { /// === удаление мастар-номеров === ///
     if (i < 5 && i != 0) {
sms(String("Master") + i + ":" + AlarmPhone[i] + " dell\n", 0); // смс на 0 номер
       EEPROM.put(Adress[i], 0);
       AlarmPhone[i] = "";   // обнулим номер
  } return 1;                          
}

int balnum (String num) { /// === добавляем номер баланса === ///
    num.toCharArray(Bal, 4);   // конвертируем
    EEPROM.put(20, Bal);           // записываем массив в EEPROM 
sms(String(F("Balance:*")) + num + "# Ok\n", 0); // смс на 0 номер
    return 1;                             
}

void TempC() {      /// === измеряем температуру === ///
  int currentMillis_t = millis();  // 
  if (((currentMillis_t - previousMillis_t) / 1000 > interval_door)) {
    previousMillis_t = currentMillis_t;
    byte data[2];
    ds.reset();
    ds.write(0xCC);
    ds.write(0x44);
    delay(750);
    ds.reset();
    ds.write(0xCC);
    ds.write(0xBE);
    data[0] = ds.read();
    data[1] = ds.read();
    int Temp = (data[1] << 8) + data[0];
    Temp = Temp >> 4;
    temp = String(F("Temp ")) + Temp + "*C";
  }
}

void Decode7bit(String &instr, String &outstr) { /// === декодирование баланса === ///
  byte reminder = 0;
  int bitstate = 7;
  for (unsigned int i = 0; i < instr.length(); i++) {
    byte b = instr[i];
    byte bb = b << (7 - bitstate);
    char c = (bb + reminder) & 0x7F;
    outstr += c;
    reminder = b >> bitstate;
    bitstate--;
    if (bitstate == 0) {
      char c = reminder;
      outstr += c;
      reminder = 0;
      bitstate = 7;
    }
  }
}

void InitModem() { /// === инициализация модема === ///
//  Serial.println(F("Start GSM"));
  gsm.begin(9600);  //Скорость порта для связи Arduino с GSM модулем
  waitConnect();
//  Serial.println(F("GSM connected"));
  waitRegistration();
  delay(1000); 
}

void waitConnect() { /// === запуск модема === ///
  int countok = 0;
  String str; 
  while(countok < 5) {                   //ждём пять ОК  
    uint32_t ms = millis();
    if ((ms - msAT) > 500 || ms < msAT) { // Событие срабатывающее каждые 500 мс 
      msAT = ms;
//      Serial.println(">>AT");
      gsm.println(F("AT"));          // посылаем команду
      str = "";
      delay(100);                      // ждём ответа
      while (gsm.available()) {
        char ch = gsm.read();
        str += ch;
      } 
//      Serial.println("C>");
//      Serial.println(str);
      if (str.indexOf(F("OK")) > -1)
        countok++;
      else
        countok = 0;
    }
  }  
//  Serial.println(F("Turn on AOH:"));
  gsm.println(F("AT+CLIP=1"));  // включить АОН
  delay(200);
//  Serial.println(F("GSM registration"));
  gsm.println(F("AT+CMGF=1"));
  delay(200); 
//  Serial.println(F("Mode GSM:"));
  gsm.println(F("AT+CSCS=\"GSM\""));  // кодировка текста - GSM
  delay(300);
  gsm.println(F("AT+CNMI=2,2,0,0,0"));
  delay(300); 
}

void waitRegistration() { /// === регистрация модема в сети === ///
  bool ok = 0;
  String str;
  while (!ok) {  
    uint32_t ms = millis();
    if ((ms - msAT) > 500 || ms < msAT) { // Событие срабатывающее каждые 500 мс
      msAT = ms;
//      Serial.println(F(">>AT+CREG?"));
      gsm.println(F("AT+CREG?"));      //посылаем команду
      delay(100);                           //Ждём ответа
      str = "";
      while (gsm.available()) {
           char ch = gsm.read();
           str += ch;
      } 
//      Serial.println(F("R>"));
      Serial.println(str);
      if (str.indexOf(F("+CREG:"))>-1)
        ok = 1;
    }
  }  
}

void sms(String text, byte sendnum) { /// === отправка СМС === ///
    String phone = "";
    if (sendsmscaller == 1 && sendnum == 0) {                  // отправка смс на номер звонившего
      phone = RingPhone;
      Serial.println(String(F("SMS send ")) + phone); 
      delay(100);
      gsm.println(String(F("AT+CMGS=\"+")) + phone + "\"");
      delay(100);
      gsm.print(text + temp);
      delay(100);
      gsm.print((char)26);
      delay(2000);
    } 
    else if (sendsmscaller == 1 && sendnum == 1) {                  // отправка смс на все номера
      for (int i = 0; i < 4 ; i++) {        
        phone = AlarmPhone[i];
        if (phone != 0) {
          Serial.println(String(F("SMS send ")) + phone); 
          delay(100);
          gsm.println(String(F("AT+CMGS=\"+")) + phone + "\"");
          delay(100);
          gsm.print(text + temp);
          delay(100);
          gsm.print((char)26);
          delay(4000);
        }
      }
    }
    Serial.println(text + temp + "\n");
}

работает пока без перебоев, сообщения нормально отправляются и принимаются, глюков не заметил.

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

Плохой пример, негодный - вас кто учил передавать комплексные типы в функцию по значению? У вас кучу ненужных, и даже вредных, с точки зрения расхода памяти, созданий копий объектов на стеке. Надо так:

void blablabla (const String& val)
void editsensor (const String& val)
​void eepromeditsensor(const String& EditSensorName, uint8_t SensorNumber, uint8_t LorH )
 

и далее по списку.

Не видя всего кода пытаетесь искать учителей? Как вы думаете есть ли смысл передавать строку из одной функции в другую без дальнейшей модификации этой строки? А если следуя вашему примеру попробовать откомпилить этот код?

String val = "Bla-bla-bla";

void setup() {
  Serial.begin(9600);
  one ();
}

void loop() {
  // put your main code here, to run repeatedly:

}

void one () {
  val += "-one";
  Serial.println(val);
  two (const String & val);
}

void two (const String & val) {
  val += "-two";
  Serial.println(val);
  three (const String & val);
}
void three (const String & val) {
  val += "-three";
  Serial.println(val);
}

Получится?

ЗЫ Что там с комплексными не так? :)

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

kvolk пишет:

DIYMan пишет:

Плохой пример, негодный - вас кто учил передавать комплексные типы в функцию по значению? У вас кучу ненужных, и даже вредных, с точки зрения расхода памяти, созданий копий объектов на стеке. Надо так:

void blablabla (const String& val)
void editsensor (const String& val)
​void eepromeditsensor(const String& EditSensorName, uint8_t SensorNumber, uint8_t LorH )
 

и далее по списку.

Не видя всего кода пытаетесь искать учителей? Как вы думаете есть ли смысл передавать строку из одной функции в другую без дальнейшей модификации этой строки? А если следуя вашему примеру попробовать откомпилить этот код?

String val = "Bla-bla-bla";

void setup() {
  Serial.begin(9600);
  one ();
}

void loop() {
  // put your main code here, to run repeatedly:

}

void one () {
  val += "-one";
  Serial.println(val);
  two (const String & val);
}

void two (const String & val) {
  val += "-two";
  Serial.println(val);
  three (const String & val);
}
void three (const String & val) {
  val += "-three";
  Serial.println(val);
}

Получится?

ЗЫ Что там с комплексными не так? :)

Хинт: модификатор const ставится там, где он нужен, и не ставится - где не нужен. В любом случае - передача по ссылке, а не по значению - хороший тон программирования, стоит это просто запомнить ;)

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

И да - у вас написана чушь: строка 16, строка 22 - так функции не вызываются :) :) :)

З.Ы. "Не видя всего кода пытаетесь искать учителей?" - это вообще о чём?

З.З.Ы. "Что там с комплексными не так? :)" - всё с ними так, как видите - просто лично вы не умеете их готовить, от слова "совсем". 

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

И да - у вас написана чушь: строка 16, строка 22 - так функции не вызываются :) :) :)

Согласен, скопипастил и не обратил внимания, поправил всё откомпилилось.

DIYMan пишет:

Если вам нужно модифицировать входящий по ссылке объект - не ставьте const, делов-то. Но если стоит const - даже ежу ясно, что этот объект изменять нельзя, и вызывающая сторона будет уверена, что после отработки вызванной функции на вызывающей стороне объект будет в том же состоянии, что и до вызова.

String val = "Bla-bla-bla";

void setup() {
  Serial.begin(9600);
  one ();
}

void loop() {
  // put your main code here, to run repeatedly:

}

void one () {
  val += "-one";
  Serial.println(val);
  two (val);
}

void two (const String & val) {
  val += "-two";
  Serial.println(val);
  three (val);
}
void three (const String & val) {
  val += "-three";
  Serial.println(val);
}

Консоль:

Bla-bla-bla-one
Bla-bla-bla-one-two
Bla-bla-bla-one-two-three

И что с "const и &" что без этого ОЗУ используется одинаково.

Глобальные переменные используют 232 байт (11%) динамической памяти, оставляя 1816 байт для локальных переменных. Максимум: 2048 байт.

 

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

kvolk пишет:

Не видя всего кода пытаетесь искать учителей?

kvolk - и тут снова всплывает вопрос, почему вы скрываете свой код. Глядя на эти примеры - становится понятно.

Хинт2 - если вы хотите экономить память - не используйте String. Вообще. использование String в большом проекте на ардуино - можно считать маркером плохого программиста.

kvolk
Offline
Зарегистрирован: 12.06.2017

b707 пишет:

kvolk - и тут снова всплывает вопрос, почему вы скрываете свой код. Глядя на эти примеры - становится понятно.

Я уже объяснял почему. Этот пример кода был выдернут из февральской прошивки, проблема с памятью в то время остро не стояла, сейчас это выглядит немного иначе. Расставлю точки, многоуважаемый b707, я тут не пытаюсь доказать всем что мой код идеальный, а всё что вы тут делаете - это неправильно. Каждый кодит как может, в силу своих знаний и способностей.

Смотрите в чём дело, товарищ Short Circuit в этом посте сообщил, что у него есть проблема и попросил совета, так как я уже "имел дело" с этой проблемой в своём проекте, я сообщил причину и привёл пример из старого "говнокода", чтобы это было наглядно. Товарищ DIYMan в своём посте показал более эффективную реализацию. Что-то не увидел я вашей активновности в поиске причин и методов устранения этого бага, но личную оценку всему происходящему вы просто обязаны были оставить в свойм посте.

У вас есть своё мнение, но если, например, класс String придумали и он существует в среде программирования, то значит в некоторых случаях его использование вполне оправдано, и если для вас это "маркер плохого программиста" - чтож, пусть будет так.

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

Хинт: модификатор const ставится там, где он нужен, и не ставится - где не нужен. В любом случае - передача по ссылке, а не по значению - хороший тон программирования, стоит это просто запомнить ;)

Почему этот код занимает меньше (именно) флэш памяти

String val = "Bla-bla-bla";

void setup() {
  Serial.begin(9600);
  one ();
}

void loop() {
  // put your main code here, to run repeatedly:

}

void one () {
  val += "-one";
  Serial.println(val);
  two (val);
}

void two (const String & val) {
  val += "-two";
  Serial.println(val);
  three (val);
}
void three (const String & val) {
  val += "-three";
  Serial.println(val);
}

//Скетч использует 3076 байт (10%) памяти устройства. Всего доступно 30720 байт.
//Глобальные переменные используют 232 байт (11%) динамической памяти, оставляя 1816 байт для локальных переменных. Максимум: 2048 байт.

чем этот

String val = "Bla-bla-bla";

void setup() {
  Serial.begin(9600);
  one ();
}

void loop() {
  // put your main code here, to run repeatedly:

}

void one () {
  val += "-one";
  Serial.println(val);
  two (val);
}

void two (String val) {
  val += "-two";
  Serial.println(val);
  three (val);
}
void three (String val) {
  val += "-three";
  Serial.println(val);
}

//Скетч использует 3172 байт (10%) памяти устройства. Всего доступно 30720 байт.
//Глобальные переменные используют 232 байт (11%) динамической памяти, оставляя 1816 байт для локальных переменных. Максимум: 2048 байт.

 и почему нет выигрыша в памяти ОЗУ?

DIYMan пишет:

Если вам нужно модифицировать входящий по ссылке объект - не ставьте const, делов-то.

Меняет и там и там, но это правильно, я так понимаю.:)

Bla-bla-bla-one
Bla-bla-bla-one-two
Bla-bla-bla-one-two-three
DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

kvolk пишет:

 

И что с "const и &" что без этого ОЗУ используется одинаково.

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

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

kvolk пишет:

 

И что с "const и &" что без этого ОЗУ используется одинаково.

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

То есть если я "не понимаю"  "как работает вызов функции, что происходит со стеком", то автоматически попадаю в группу безграмотных? :) Глубоко копаете, здесь большая часть сообщества не то что "не знает что происходит со стеком", а даже слова такого не знает. 

А по существу вы можете прокоментировать "почему этот код занимает меньше (именно) флэш памяти?". 

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

kvolk пишет:

То есть если я "не понимаю"  "как работает вызов функции, что происходит со стеком", то автоматически попадаю в группу безграмотных?

Именно так. Это то же самое, что брать в руки скальпель без знания анатомии - хирург выйдет так себе. А уж если он этим ещё и бравирует - вообще бяда.

kvolk пишет:

А по существу вы можете прокоментировать "почему этот код занимает меньше (именно) флэш памяти?". 

Потому что в первом случае объект тупо не копируется на стек, что я вам и пытаюсь донести. Меньше команд - меньше размер скетча. Вопросы?

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

Потому что в первом случае объект тупо не копируется на стек, что я вам и пытаюсь донести. Меньше команд - менше размер скетча. Вопросы?

Разве это не касается только оперативной памяти?

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

вопрос - как чистить принудительно память или стек?

kvolk
Offline
Зарегистрирован: 12.06.2017

Short Circuit пишет:

вопрос - как чистить принудительно память или стек?

Никак. http://robocraft.ru/blog/arduino/531.html

http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-pa...

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

kvolk пишет:

DIYMan пишет:

Потому что в первом случае объект тупо не копируется на стек, что я вам и пытаюсь донести. Меньше команд - менше размер скетча. Вопросы?

Разве это не касается только оперативной памяти?

Вопрос: МК как-то нужно уметь копировать объект на стек? Как он это делает? В хрустальный шар смотрит или таки выполняет набор команд, которые входят в состав прошивки и размещаются во флеше?

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

Вопрос: МК как-то нужно уметь копировать объект на стек? Как он это делает? В хрустальный шар смотрит или таки выполняет набор команд, которые входят в состав прошивки и размещаются во флеше?

Да, спасибо, этот момент был мной упущен.

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

kvolk пишет:

Да, спасибо, этот момент был мной упущен.

Вот, курить можно, чтобы понять, чем отличаются вызовы функции с передачей объекта по значению и по ссылке:

int freeRam() 
{
    extern int __heap_start, *__brkval;
    int v;
    return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);    
}

int byReferenceCall(const String& val)
{
  int ramFree = freeRam();
  Serial.print(F("By reference call with string: "));
  Serial.println(val);
  Serial.print(F("Free RAM inside func: "));
  Serial.println(ramFree);
  

  return ramFree;
}

int byValueCall(String val)
{
  int ramFree = freeRam();
  Serial.print(F("By value call with string: "));
  Serial.println(val);
  Serial.print(F("Free RAM inside func: "));
  Serial.println(ramFree);

  return ramFree;
}

void setup() 
{
  Serial.begin(57600);

  String test = F("1234567890");

  int ramFree = freeRam();
  Serial.print(F("Free ram here: "));
  Serial.println(ramFree);

  ramFree = freeRam();
  int ramFreeTester = byReferenceCall(test);

  Serial.print(F("By reference call result (freeRam, diff): "));
  Serial.print(ramFreeTester);
  Serial.print(F(", "));
  Serial.println(ramFree - ramFreeTester);


  ramFree = freeRam();
  ramFreeTester = byValueCall(test);

  Serial.print(F("By value call result (freeRam, diff): "));
  Serial.print(ramFreeTester);
  Serial.print(F(", "));
  Serial.println(ramFree - ramFreeTester);  
  

}

void loop() 
{
  // put your main code here, to run repeatedly:

}

У меня вывело (комплировал под мегу):

Free ram here: 7938
By reference call with string: 1234567890
Free RAM inside func: 7931
By reference call result (freeRam, diff): 7931, 7
By value call with string: 1234567890
Free RAM inside func: 7918
By value call result (freeRam, diff): 7918, 20

Как видно, передача по значению - насилует оперативку.

З.Ы. Для атомарных типов данных - без разницы, как передавать, по значению или по ссылке. Для сложных типов данных - разница есть, как видно на тестовом скетче. String - это класс, следовательно...

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

Меньше команд - меньше размер скетча. Вопросы?

Например, если есть несколько функций, в которые по ходу выполнения программы передаётся строка, тогда для экономии флэш памяти можно прописать указатель на какую нибудь одну строку?

...
void a (const String & val, int x) 
void b (const String & val, byte s) 
void c (const String & val, uint8_t ds) 
void d (const String & val, uint8_t ccc)
...
DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

kvolk пишет:

DIYMan пишет:

Меньше команд - меньше размер скетча. Вопросы?

Например, если есть несколько функций, в которые по ходу выполнения программы передаётся строка, тогда для экономии флэш памяти можно прописать указатель на какую нибудь одну строку?

...
void a (const String & val, int x) 
void b (const String & val, byte s) 
void c (const String & val, uint8_t ds) 
void d (const String & val, uint8_t ccc)
...

Именно так, только в приведённых объявлениях не указатель - а ссылка, указатель - это оператор *, т.е., передача по указателю - это:

void a (String* val, int x) 
void b (String* val, byte s) 
void c (String* val, uint8_t ds) 
void d (String* val, uint8_t ccc)

При этом тоже передаваться будет только указатель, а не копироваться всё нутро объекта типа String. 

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

З.Ы. Вы мой скетч-то запустите, и гляньте - есть разница в используемой оперативке или нет? И попробуйте ответить на простой вопрос: что будет, если свободной оперативки всего 15 байт осталось - какая функция из пары byValueCall/byReferenceCall отработает, а какая - сведёт ардуину с ума вследствие заезжания кучи в область данных?

kvolk
Offline
Зарегистрирован: 12.06.2017

DIYMan пишет:

При этом тоже передаваться будет только указатель, а не копироваться всё нутро объекта типа String. 

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

З.Ы. Вы мой скетч-то запустите, и гляньте - есть разница в используемой оперативке или нет? И попробуйте ответить на простой вопрос: что будет, если свободной оперативки всего 15 байт осталось - какая функция отработает, а какая - сведёт ардуину с ума вследствие заезжания кучи в область данных?

Спасибо.

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

А почему никто тоновый набор не использует для команд? 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

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

pasha413
Offline
Зарегистрирован: 27.11.2016

Umka пишет:

А почему никто тоновый набор не использует для команд? 


Это же надо команды все помнить. А так отправил сообщение "info" и вот тебе весь список команд и заодно текущее состояние.
System on
Sirena on
Ring off
SMS on
Pir on
Door on
Door2 on
Gas on
Temp 15*C

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Ну, тем же макаром и тоновые команды захелпить. Зато есть тарифы халявые у большинства операторов и любимые номера. А СМС как правило денег стоят. И обратка платная. 

pasha413
Offline
Зарегистрирован: 27.11.2016

У меня тариф безлимит, на сигналке без абонентской платы, и пакет смс подключен.
Ну на данный момент думаю как на GPRS перейти, не могу найти примеров использования MQTT с GPRS, и приложение на андроид.

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Не взлетит скорее всего. Скорость для MQTT не подходящая и задержки. Тут лучше на ESP8266 делать имхо. И мозгов больше и вифи и уровни 3,3В. Приложения MQTT на Андроид использую несколько. Могу подсказать что знаю.

pasha413
Offline
Зарегистрирован: 27.11.2016

Umka пишет:

Могу подсказать что знаю.


Буду признателен за примеры, очень интересно esp + gsm.
На почту pasha413@mail.ru

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

если не трудно поделитесь с нами тоже, интересно и за темой слежу....

Umka что вы имели в виду когда сказали что у esp8266 мозгов больше?

с gsm модулем 3.3в согласовать легко, а весь остальной обвес как согласовывать?

Umka
Umka аватар
Offline
Зарегистрирован: 19.10.2012

Мозгов больше, пинов меньше. UART там тот же самый и команды те же для GSM модуля. Ну плюс WEB-интерфейс еще не сложно прикрутить и mqtt руление. Либы есть, поддержка в Arduino IDE есть, поддержка практически всех датчиков тоже есть. Вот только 1 АЦП не радует.