Управление нагрузкой по звонку Arduino Nano + M590

None
Offline
Зарегистрирован: 15.01.2016

Не могу понять почему не опознаётся номер телефона.

byte gsmOk = 13;    //сеть поймана 
byte bootPin = 4;   //пин включение радиомодуля
byte zvonok = 5;    //индикатор входящего звонка
byte PinPower = 6;  //пин управления нагрузкой
byte NumT = 0;      //номер ячейки массива
byte KolMas = 10;   //количество ячеек массива
char* Tel[10] = {"79999999999", "79999999999", "79999999999", "79999999999", "79999999999",   //массив номеров
"79999999999", "79999999999", "79999999999", "79999999999", "79999999999"};                   //массив номеров

void setup() {
  Serial.begin(9600);
  pinMode(gsmOk, OUTPUT);
  pinMode(bootPin, OUTPUT);
  pinMode(zvonok, OUTPUT);
  pinMode(PinPower, OUTPUT);
  digitalWrite(bootPin, HIGH);
  digitalWrite(gsmOk, LOW);
  digitalWrite(zvonok, LOW);
  digitalWrite(PinPower, LOW);
  delay(2000);
  
  Serial.println("AT");         //пингуем включен ли модем
  Serial.flush();               //ждем ответа
  if (!Serial.find("OK")) {     //если нет ответа
    digitalWrite(bootPin, LOW); //включаем модем
  }
  
  while(1){                                 //ждем подключение модема к сети
    Serial.println("AT+CREG?");             //пингуем наличие сети
    Serial.flush();                         //ждем ответа
    if (Serial.find("+CREG: 0,1")) {        //если сеть зарегестрирована
      Serial.flush();                       //ждем ответа
      digitalWrite(gsmOk, HIGH);            //говорим что сеть есть
      digitalWrite(bootPin, HIGH);          
      break;
    }
  }
}

void loop() {
  
  if(Serial.find("RING")){                  //если нашли RING
    digitalWrite(zvonok, HIGH);             //говорим что есть входящий
    Serial.println("AT+CLIP=1");            //включаем АОН
    while(1){                               //в цикле
      if (Serial.find(Tel[NumT])) {         //ищем номер
        digitalWrite(PinPower, HIGH);       //если нашли включаем нагрузку
        Serial.println("ATH0");             //сбрасываем вызов
        Serial.flush();                     //ждем ответа
        digitalWrite(zvonok, LOW);          //говорим что входящего нет
        Serial.println("AT+CLIP=0");        //отключаем АОН
        Serial.flush();                     //ждем ответа
        break;                              //выходим из цикла
      }
      else {
        Serial.println("AT+CPAS");          //спрашиваем состояние модема
        Serial.flush();                     //ждем ответа
        if (Serial.find("+CPAS: 0")) {      //если звонок в процессе, возвращает +CPAS: 3,если он в "готовности"
          Serial.println("AT+CLIP=0");      //отключаем АОН
          Serial.flush();                   //ждем ответа
          digitalWrite(zvonok, LOW);        //говорим что входящего нет
          break;                            //выходим из цикла
        }
      }
    ++NumT;                                 //ищем в следующей ячейке массива
    if (NumT=KolMas) NumT=0;                //проверяем, чтоб не выйти за пределы массива
    }
  }

  //продолжение кода

}

 

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

А должен? По-моему, так нет. И причин тому много.  Начнём с мелочей, к крупным потом перейдём.

Как Вы понимаете строку 66?

На самом деле она полностью эквивалентна такой:

NumT=0;

Вы этого хотели? Если нет, то поставьте нормальное сравнение.

Но это не самое интересное.

Что Вы делаете в строке 46?

Вы ищете там нулевой номер из Вашего списка. Для это Вы вчитаываете из потока всё, пока либо не встретите нужный номер, либо не наступит таймаут.

Предположим Вам пришёл звонок от первого номера. А Вы в процесс поиска нулевого этот первый благополучно из потока вычитали и выбросили. Даже если Вы почините строку 66 и потом начнёте исакть первый номер - Вы его уже прочитали и выбросили - его уже нет.

При таком подходе Вы в лучшем случае найдёте номер только в том случае, если это нулевой номер из Вашего массива. Никакого другого номера Вы не найдёте никогда. найдёте ли первый - не знаю, я дальше в подробности кода не лез.

Вот собственно и всё.

None
Offline
Зарегистрирован: 15.01.2016

ЕвгенийП пишет:

Как Вы понимаете строку 66?

На самом деле она полностью эквивалентна такой:

NumT=0;

Вы этого хотели? Если нет, то поставьте нормальное сравнение.

Млин, это уже после полдня мучений такие косяки.

 

Так что же получается, функция Serial.find() после прочтения очищает приёмник сериал?

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

None пишет:

Так что же получается, функция Serial.find() после прочтения очищает приёмник сериал?

Сериал - это поток. Вот представьте себе, что данные сериала идут к Вам на ленте типа телеграфной. Функция find тянет ленту и читает данные в поисках того, что она ищет. Прочитанные куски ленты она при этом выбрасывает. find не отматывает поток назад, если ничего не нашла. Прочитанный кусок потока пропадает.

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

None
Offline
Зарегистрирован: 15.01.2016

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

Я думал, что поток данных записывается во временную память, а эта функция ищет там.

None
Offline
Зарегистрирован: 15.01.2016

УРЯ!!!!! ПОЛУЧИЛОСЬ!!! РАБОТАЕТ!!! Теперь буду разбираться с СМС, и можно ли будет добавлять и убирать номера по СМС, если не получится, подумываю сделать мастер-номер, после звонка которого можно будет убирать/добавлять номер.

byte gsmOk = 13;    //сеть поймана
byte bootPin = 4;   //включение радиомодуля
byte zvonok = 5;    //индикатор входящего звонка
byte PinPower = 6;  //пин управления нагрузкой
byte NumT = 0;      //номер ячейки массива
byte KolMas = 10;   //количество ячеек массива
char* Tel[] = {"79999999999", "79999999999", "79999999999", "79999999999", "79999999999",   //массив номеров
"79999999999", "79999999999", "79999999999", "79999999999", "79999999999"};                 //массив номеров
char Temp[12] = ""; //массив на один символ больше из-за проблемы с нулем в конце строки при команде readBytes

void setup() {
  Serial.begin(9600);
  pinMode(gsmOk, OUTPUT);
  pinMode(bootPin, OUTPUT);
  pinMode(zvonok, OUTPUT);
  pinMode(PinPower, OUTPUT);
  digitalWrite(bootPin, HIGH);
  digitalWrite(gsmOk, LOW);
  digitalWrite(zvonok, LOW);
  digitalWrite(PinPower, LOW);
  delay(2000);
 
  Serial.println("AT");         //пингуем включен ли модем
  Serial.flush();               //ждем ответа
  if (!Serial.find("OK")) {     //если нет ответа
    digitalWrite(bootPin, LOW); //включаем модем
  }
 
  while(1){                                 //ждем подключение модема к сети
    Serial.println("AT+CREG?");             //пингуем наличие сети
    Serial.flush();                         //ждем ответа
    if (Serial.find("+CREG: 0,1")) {        //если сеть зарегестрирована
      digitalWrite(gsmOk, HIGH);            //говорим что сеть есть
      digitalWrite(bootPin, HIGH);          
      break;
    }
  }
}

void loop() {
 
  if(Serial.find("RING")){                  //если нашли RING
    digitalWrite(zvonok, HIGH);             //говорим что есть входящий
    Serial.println("AT+CLIP=1");            //включаем АОН
    while(1){                               //в цикле ищем номер телефона
      if (Serial.find("+CLIP: \"")) {       //если нашли
        Serial.readBytes(Temp, 11);         //записываем его во временную переменную
        delay(200);
        Serial.println("ATH0");             //сбрасываем вызов
        delay(200);
        Serial.println("AT+CLIP=0");        //отключаем АОН
        delay(200);
        digitalWrite(zvonok, LOW);          //говорим что входящих нет
        
        while (NumT <= KolMas) {            //ищем телефон в массиве
          if (strstr(Tel[NumT], Temp)) {    //если находим
            Temp[0] = 0;                    //очистить переменную Temp
            deistvie();                     //выполняем действие
            NumT=0;                         //сбрасываем счетчик
            break;                          //выходим из цикла
          }
          else {
            NumT++;                         //перебираем массив
            if (NumT == KolMas) {           //защита от переборов дальше массива
              Temp[0] = 0;                  //очистить переменную Temp
              NumT = 0;                     //защита от переборов дальше массива
              break;                        //выходим из цикла
            }
          }
        }
        break;
      }
      else {
        Serial.println("AT+CPAS");          //спрашиваем состояние модема   
        if (Serial.find("+CPAS: 0")) {      //если звонка нет
          Serial.println("AT+CLIP=0");      //отключаем АОН
          digitalWrite(zvonok, LOW);        //говорим что входящих нет
          break;                            //выходим из цикла
        }
      }
    }
  }
  //продолжение кода
}

void deistvie() {
  digitalWrite(PinPower, !digitalRead(PinPower));
}

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

Значит приходит что-то не так, как ожидаете (не так как Вы с консоли подсовываете). Мега есть? Чтобы второй сериал бы? Или может через софт-сериал это включить, а хард для монитора порта использовать?

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

None
Offline
Зарегистрирован: 15.01.2016

Проблема была в том, что команду strstr(), я взял из "кривого" источника, а там было сказано, что сначала указывается искомое, а потом уже строка в которой ищет. Сейчас нашел на этом форуме похожую проблему. После замены их местами все заработало.

В сериал, когда отлаживал с ПК, отсылалось что он принял, какую строку сохранил и с чем сравнивал а так-же номер ячейки массива, все сходилось. И все всегда работало.

Это мой второй проект, если не считать мигание лампочками и дерганьем реле. Поэтому приходится тыкаться как слепому котёнку и тратить день на поиск решения и адаптацию под задачу. Изначально это было https://www.youtube.com/watch?v=2ENbWDzX4IQ

ЕвгенийП, спасибо за потраченое на меня время.

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

Не за что, с Победой!

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Кстати если не хватает сириалов на уне можно прикрутить lcd 16×02 ну или 20×04 экран и выводить на него то что получает унка, тогда будет видно все как в сириал. Я так делал когда моделировал передачу по сириал между двумя унами (до физического устройства дело пока не дошло...)

None
Offline
Зарегистрирован: 15.01.2016

Можно, но с экранами у меня туго, то одно придуривается, то другое.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Мк это холст, как на нем нарисуешь так он и будет работать)

None
Offline
Зарегистрирован: 15.01.2016

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

Сейчас опять голова квадратная, с этим ЕЕПРОМ, как я понял туда можно писать только адресно и только по одной ячейке. Вот думаю как мой массив туда писать и считывать без нагромождений, а то память контроллера не резиновая. Думаю через недельку будет подобие кода.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

А что сложного, у вас переменные заданной длинны length 11 символов, сделайте функцию eepromWriteNumber () которой будете передавать ячейку cell и ссылку на массив array, в функции перебирайте i от length*cell до length*(cell+1) и пишете туда ваши чары. Читаем наоборот

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

None пишет:

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

Да, так и писать

int massiv[300];
...
// Пишем
EEPROM.put(0, massiv);
...
// Читаем
EEPROM.get(0, massiv);

Это не работает только в самых древних версиях IDE (там старая библиотека EEPROM). В мало-мальски современных - нет проблем.

None
Offline
Зарегистрирован: 15.01.2016

Завтра попробую на чистой ардуинке.

Я правильно понял, что для записи скажем второй ячейки массива надо будет просто отправить её на (11*2=22) 23 ячейку и функция просто запишет её в следующие 23-33 ячейки?

EEPROM.put(22, Tel[2]);

И считать её можно будет так же?

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

PS: у меня только нано и промини для уже отлаженных проектов, еще парочка на тини85, забыл как они называются.

PPS: сегодня приехал олед экран на I2C, с ними, вроде, попроще. Да и пинов мало используют.

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

put пишет с указанного адреса то, что Вы её дадите. Весь массив, так весь, один элемент, так один элемент. Главное, чтобы на втором аргументе нормально sizeof отрабатывал, чтобы она знала сколько байтов писать.

Если писать по одному байту, то можно ещё проще - в нотации массива:

byte b;
...
// пишем b по адресу addr
EEPROM[addr] = b;
...
// читаем b из адреса addr
b = EEPROM[addr];

При этом, если склероз мне не изменяет, и put, и массив сделаны аккуратно. Они сначала читают, сравнивают и пишут только если новое значение отличается от того, что там итак есть - чтобы лишний раз не изнашивать EEPROM

None
Offline
Зарегистрирован: 15.01.2016

Износ ЕЕПРОМ моей игрушке не грозит, ну забью я туда телефона три-четыре, и все, пусть работает, может когда телефон сменю - поменяю один. А от чтения память не помрет. А может наиграюсь и разберу. Стачала задачу решить хочу.

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

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

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

None пишет:

почему в википедии ардуино не указаны все эти фишки

Если Вы про работу с EEPROM, так всё, что Вам сегодня говорил, написано на сайте производителя Ардуино - https://www.arduino.cc/en/Reference/EEPROM

None
Offline
Зарегистрирован: 15.01.2016

Англицкий... У нас в деревне есть только учитель немецкого, англицкий только в гугле.

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

None пишет:

англицкий только в гугле.

Достаточно. Иногда тексты смешные получаются, но если цель понять, а не постебаться, то понять можно.

Я с гуглом даташиты на китайском читаю. Серьёзно.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

ЕвгенийП пишет:

Это не работает только в самых древних версиях IDE (там старая библиотека EEPROM). В мало-мальски современных - нет проблем.


Простите что внес смуту. Не знал что массивы так писать можно, посоветовал так как делал сам

None
Offline
Зарегистрирован: 15.01.2016

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

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

None пишет:

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

Вас жестоко обманули. Плюньте этому "не помню кому" в рожу. Это в паскале около 30 конструкций, а в системе команд AtMega328 - 131 команда! Это только система команд, а есть еще пара десятков директив самого ассемблера.

None
Offline
Зарегистрирован: 15.01.2016

Далеко плевать придется, это было лет шестнадцать назад.

None
Offline
Зарегистрирован: 15.01.2016

При прошивке ардуино ЕЕПРОМ очищается?

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

None пишет:

При прошивке ардуино ЕЕПРОМ очищается?

Зависит от фьзов. В стандартном IDE'шном "записать загрузчик" фьюз установлен так, чтобы очищалось. Но это несложно поменять.

None
Offline
Зарегистрирован: 15.01.2016

Не буду пока ардуинку ломать, программатор еще не пришел, запишу с сетап.

А не, я про кнопку "Загрузка".

Уже не надо, проверил, нет, не перезаписывает. Класс! Можно задать заранее все данные.

msng
Offline
Зарегистрирован: 07.06.2012

нет

None
Offline
Зарегистрирован: 15.01.2016

Не пойму что я делаю не так. Вроде же читает нормально и сохраняет в массив нормально, почему массив потом пустой? Я опять какую-то фишку не нашел? И откуда эти пробелы берутся?

#include <EEPROM.h>

byte NumT = 0;      //номер ячейки массива
char TelE[10] = "";  //номер из ЕЕПРОМ
char TelZero[10] = "0000000000";  //для обнуления номера
byte Adress[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; //занимаем сотню ячеек для десяти номеров
char* Tel[] = {"", "", "", "", "", "", "", "", "", ""}; //массив номеров
byte NumA = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
/*  for (byte i=0; i<10; i++) {
    EEPROM.write(Adress[NumA]+i, Tel1[i]);
  }
*/
}

void loop() {
  // put your main code here, to run repeatedly:
  while (1) {
    for (byte i=0; i<10; i++) {
      TelE[i] = EEPROM.read(Adress[NumA]+i);
    }
    Tel[NumA] = TelE;
    Serial.print(TelE);
    Serial.print("-");
    Serial.println(Tel[NumA]);
    NumA++;
    if (NumA == 10) {
      NumA = 0;
      break;
    }
    delay(100);
  }
  Serial.println();
  for (byte a=0; a<10; a++) {
    Serial.println(Tel[a]);
  }
  delay(2000);
}

Пойду поем, а то уже руки трясутся.

Да и поработать надо, всё-таки мне за работу деньги платят :) .

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

None пишет:

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

Только читайте внимательно, водя пальцем по коду, если надо возвращайтесь и разбирайтесь несколько раз.

Вот смотрите, в строках 22-24 Вы читаете некие данне в массив TelE. Далее в строке 25 вы пытаетесь сохранить прочитанный массив в элементе NumA. массива Tel.

Правильно? Так вот, на самом деле Вы ничего не схраняете. строка 25

Tel[NumA] = TelE;

не копирует массив TelE в массив Tel[NumA]. Она илшь записывает в Tel[NumA] указатель на нулевой элемент TelE .

Потом в строка 26-28 Вы печатаете то, что получилось и всё должно печататься прилично, т.к. Вы по сути печатаете данные с одного и того же адреса.

Но при следующем прохождении цикла  (когда NumA уже равно 1), вы в тот же самый TelE. читаете новые данные. Но ведь в в Tel[0] сидит указатель на этот самый TelE !!! Т.е. при втором проходе (при  NumA равном 1) Вы первым делом затираете NumA[0]. Затем Вы снова присваиваете Tel[NumA] (то бишь Tel[1]) указатель всё на тот же самый TelE. И снова в строках  26-28 всё печатается прилично.

Когда, наконец у Вас закончится цикл (к строке 36), у Вас все до единой  Tel[NumA] (с нулевой по 9-ую) содержат один и тот же указатель на нулевой элемент массива TelE, а в нём находится последний прочитанный номер.

Вот его Вы 10 раз и печатаете в строках 37-39.

None
Offline
Зарегистрирован: 15.01.2016

То есть, получается что все записывается в нулевую ячейку массива?

Ну по сути получается, что счетчик NumA++; делает не:

Tel[0] - Tel[9], а что-то вроде Tel[0, 0] - Tel[0, 9]?

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

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

Я пробовал считывать из ЕЕПРОМ в переменную, а потом в этой переменной искать, но контроллер тупо зависает, поэтому и решил пройти по проторенной дорожке с массивом.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Только в вашем случае Tel [0][0]

None
Offline
Зарегистрирован: 15.01.2016

Значит запись должна выглядеть типа:

    for (byte a=0; i<10; a++) {
      Tel[NumA][a] = TelE[a];
    }

Нет, мусор на выходе.

У меня ощущение, что этот двумерный массив только отдавать может, информации, как в него записывать я найти не могу.

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

Ну, у Вас как описан Tel?

 char* Tel[]

Вы понимаете эту запись? Это массив указателей на char.

Т.е. Tel[n] у Вас - это указатель на char. Тип у него char *

Вы этот массив проинициализировали

char* Tel[] = {""""""""""""""""""""};

Значит, каждый из 10 элементов массива указывает на пустую строку - "", т.е. на символ '\0'.

Записать туда какую-то другу строку ненулевой длины нельзя, т.к. там не выделено под это место. Записать-то Вы можете, но запишется поверх других переменных и затрёт их.

Если Вам надо хранить там 10-тизначные номера, то любо иницилиазяируйте строкой нужной длины, например 

char* Tel[] = {"0123456789""0123456789""0123456789", ... и т.д.

Либо объявите его двухмерным массивом

char Tel[10][11];

В любом из этих случаев, Вы сможете там что-нибудь сохранять, но не так, как Вы это делали

Tel[NumA] = TelE

а вот так

strcpy(Tel[NumA], TelE);

Только имейте в виду, что strcpy не проверяет помещается ли копируемая строка в принимающую и если не помещатеся, то будет писать дальше, затирая другие переменные. Т.е. TelE не должна быть длинее 10 символов и это на Вашей совести - никто тут Вас не страхует.

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

None пишет:

Значит запись должна выглядеть типа:

    for (byte a=0; i<10; a++) {
      Tel[NumA][a] = TelE[a];
    }

Там же память ни хрена не выделена! Но, я уже Вам написал подробно.

None
Offline
Зарегистрирован: 15.01.2016

ДОБИЛ!!!

#include <EEPROM.h>

byte gsmOk = 13;    //сеть поймана
byte bootPin = 4;   //включение радиомодуля
byte zvonok = 18;   //индикатор входящего звонка
byte PinPower = 17; //пин управления нагрузкой

byte NumT = 0;      //номер ячейки массива
byte KolMas = 10;   //количество ячеек массива
byte Adress[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; //занимаем сотню ячеек для десяти номеров

char Temp[11] = ""; //массив на один символ больше из-за проблемы с нулем в конце строки при команде readBytes
char TelE[11] = ""; //номер из ЕЕПРОМ
char TelZero[10] = "0000000000";  //для обнуления номера

void setup() {
  Serial.begin(9600);
  pinMode(gsmOk, OUTPUT);
  pinMode(bootPin, OUTPUT);
  pinMode(zvonok, OUTPUT);
  pinMode(PinPower, OUTPUT);
  digitalWrite(bootPin, HIGH);
  digitalWrite(gsmOk, LOW);
  digitalWrite(zvonok, LOW);
  digitalWrite(PinPower, LOW);
  delay(2000);

  Serial.println("AT");         //пингуем включен ли модем
  Serial.flush();               //ждем ответа
  if (!Serial.find("OK")) {     //если нет ответа
    digitalWrite(bootPin, LOW); //включаем модем
  }
 
  while(1){                                 //ждем подключение модема к сети
    Serial.println("AT+CREG?");             //пингуем наличие сети
    Serial.flush();                         //ждем ответа
    if (Serial.find("+CREG: 0,1")) {        //если сеть зарегестрирована
      digitalWrite(gsmOk, HIGH);            //говорим что сеть есть
      digitalWrite(bootPin, HIGH);          
      break;
    }
  }
}

void loop() {

  if(Serial.find("RING")){                  //если нашли RING
    digitalWrite(zvonok, HIGH);             //говорим что есть входящий
    Serial.println("AT+CLIP=1");            //включаем АОН
    while(1){                               //в цикле ищем номер телефона
      if (Serial.find("+CLIP: \"7")) {      //если нашли
        Serial.readBytes(Temp, 10);         //записываем его во временную переменную
        Serial.flush();                     //ждем ответа
        Serial.println("ATH0");             //сбрасываем вызов
        Serial.flush();                     //ждем ответа
        Serial.println("AT+CLIP=0");        //отключаем АОН
        Serial.flush();                     //ждем ответа
        digitalWrite(zvonok, LOW);          //говорим что входящих нет
        
        while (NumT <= KolMas) {            //ищем телефон в массиве

          for (byte i=0; i<10; i++) {
            TelE[i] = EEPROM.read(Adress[NumT]+i);  //считываем побайтово номер телефона
          }                                         //во временную переменную

          if (strstr(Temp, TelE)) {         //если находим
            Temp[0] = 0;                    //очистить переменную Temp
            TelE[0] = 0;                    //очистить переменную TelE
            deistvie();                     //выполняем действие
            NumT=0;                         //сбрасываем счетчик
            break;                          //выходим из цикла
          }
          else {
            NumT++;                         //перебираем массив
            if (NumT == KolMas) {           //защита от переборов дальше массива
              Temp[0] = 0;                  //очистить переменную Temp
              TelE[0] = 0;                  //очистить переменную TelE
              NumT = 0;                     //защита от переборов дальше массива
              break;                        //выходим из цикла
            }
          }
        }
        break;
      }
      else {
        Serial.println("AT+CPAS");          //спрашиваем состояние модема   
        if (Serial.find("+CPAS: 0")) {      //если звонка нет
          Serial.println("AT+CLIP=0");      //отключаем АОН
          digitalWrite(zvonok, LOW);        //говорим что входящих нет
          break;                            //выходим из цикла
        }
      }
    }
  }
  //продолжение кода
}

void deistvie() {
  digitalWrite(PinPower, !digitalRead(PinPower));
}

Моя идея сразу считывать с ЕЕПРОМ и тут же сравнивать с входящим, разбилась об этот дурацкий ноль в конце массива. Надо было массив char TelE[11] = ""; всего-лишь увеличить на один байт. Если будет впритык получается, что в TelE всегда имеется входящий номер(номер из еепром и без пробела номер из темпа) 90033322229003332222, а не 9003332222 9003332223, значит всегда срабатывает.

None
Offline
Зарегистрирован: 15.01.2016

ЕвгенийП пишет:

None пишет:

Значит запись должна выглядеть типа:

    for (byte a=0; i<10; a++) {
      Tel[NumA][a] = TelE[a];
    }

Там же память ни хрена не выделена! Но, я уже Вам написал подробно.

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

Завтра буду танцевать с кнопками.

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

Так в конце строки всегда символ '\0'. Он является признаком конца строки. В моём прошлом посте, когда нужно было 10 строк по 10 символов, я объявлял

char Tel[10][11];

Вы этого не знали?

Не понял комментария в строке

byte Adress[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; //занимаем сотню ячеек для десяти номеров

О какой сотне ячеек речь?

Впрочем, добил, так добил. Поздравляю!

 

None
Offline
Зарегистрирован: 15.01.2016

ЕвгенийП пишет:

Не понял комментария в строке

byte Adress[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; //занимаем сотню ячеек для десяти номеров

О какой сотне ячеек речь?

Впрочем, добил, так добил. Поздравляю!

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

Получается 0-9 10-19 20-29 --- 90-99 номера ячеек в еепром.

Это, конечно, не экономично, но мне так проще. Я же говорю, что пока чувствую себя обезьяной с автоматом. Мне паяльник и полуготовое решение от производителя как-то ближе.

Ага, нашел выше сообщение, как-то пропустил его.

ЕвгенийП пишет:

strcpy(Tel[NumA], TelE);

Я так понимаю переводится как СтрокаКопировать? Тоже нигде не нашел. Надо будет поиграться.

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

None пишет:

Я так понимаю переводится как СтрокаКопировать? Тоже нигде не нашел. Надо будет поиграться.

Ничего себе! А где искали? Если в гугле набрать strcpy ....

А вообще, полный список С-шной библиотеки AVR есть ... Вы не поверите ... на сайте производителя AVR-ок - http://www.atmel.com/webdoc/AVRLibcReferenceManual/ch20.html

None
Offline
Зарегистрирован: 15.01.2016

ЕвгенийП пишет:

Ничего себе! А где искали? Если в гугле набрать strcpy ....

Для этого нужно знать что набирать, я искал по теме char* и добавление строк в массив и т.п..

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

None пишет:

Для этого нужно знать что набирать,

Ну, теперь Вы знаете, где лежит описание ВСЕХ функций. Там описания краткие, но если будут непонятки, смело набирайте имя функции в гугле и найдёте много информации - это стандартные функции, они на каждом заборе описаны.

None
Offline
Зарегистрирован: 15.01.2016

Работает! Работает! (пританцовывая)

Номера добавляются и убираются! Я добавил комментариев, вроде понятно что куда и откуда.

Остальное дело механики, а это уже мой основной хлеб, так что ничего сложного.

#include <EEPROM.h>

byte gsmOk = 13;    //сеть поймана
byte bootPin = 4;   //включение радиомодуля
byte zvonok = 18;   //индикатор входящего звонка
byte PinPower = 17; //пин управления нагрузкой
byte PinAddDel = 5; //пин кнопки

byte NumT = 0;      //номер ячейки массива
byte KolMas = 10;   //количество ячеек массива
byte Adress[10] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}; //занимаем сотню ячеек для десяти номеров

char Temp[11] = ""; //массив на один символ больше из-за проблемы с нулем в конце строки при команде readBytes
char TelE[11] = ""; //номер из ЕЕПРОМ
char TelZero[11] = "0000000000";  //для обнуления номера

void setup() {
  Serial.begin(9600);
  pinMode(gsmOk, OUTPUT);
  pinMode(bootPin, OUTPUT);
  pinMode(zvonok, OUTPUT);
  pinMode(PinPower, OUTPUT);
  pinMode(PinAddDel, INPUT);
  digitalWrite(bootPin, HIGH);
  digitalWrite(gsmOk, LOW);
  digitalWrite(zvonok, LOW);
  digitalWrite(PinPower, LOW);
  delay(2000);

  Serial.println("AT");         //пингуем включен ли модем
  Serial.flush();               //ждем ответа
  if (!Serial.find("OK")) {     //если нет ответа
    digitalWrite(bootPin, LOW); //включаем модем
  }
 
  while(1){                                 //ждем подключение модема к сети
    Serial.println("AT+CREG?");             //пингуем наличие сети
    Serial.flush();                         //ждем ответа
    if (Serial.find("+CREG: 0,1")) {        //если сеть зарегестрирована
      digitalWrite(gsmOk, HIGH);            //говорим что сеть есть
      digitalWrite(bootPin, HIGH);          
      break;
    }
  }
}

void loop() {

  if(Serial.find("RING")){                  //если нашли RING
    digitalWrite(zvonok, HIGH);             //говорим что есть входящий
    Serial.println("AT+CLIP=1");            //включаем АОН
    while(1){                               //в цикле ищем номер телефона
      if (Serial.find("+CLIP: \"7")) {      //если нашли АОН
        Serial.readBytes(Temp, 10);         //записываем телефон во временную переменную
        Serial.flush();                     //ждем ответа
        Serial.println("ATH0");             //сбрасываем вызов
        Serial.flush();                     //ждем ответа
        Serial.println("AT+CLIP=0");        //отключаем АОН
        Serial.flush();                     //ждем ответа
        digitalWrite(zvonok, LOW);          //говорим что входящих нет
        
        while (NumT <= KolMas) {            //ищем телефон в массиве

          for (byte i=0; i<10; i++) {
            TelE[i] = EEPROM.read(Adress[NumT]+i);  //считываем побайтово номер телефона
          }                                         //во временную переменную

          if (strstr(TelE, Temp)) {         //если находим
            
            if (digitalRead(PinAddDel) == HIGH) {  //если кнопка зажата
              
              for (byte i=0; i<10; i++) {   //очищаем телефон в ЕЕПРОМ
                EEPROM.write(Adress[NumT]+i, TelZero[i]);
              }
              
              NumT=0;                       //сбрасываем счетчик
              break;                        //выходим из цикла
            }
            
            else {                          //если кнопка не зажата
              Temp[0] = 0;                  //очистить переменную Temp
              TelE[0] = 0;                  //очистить переменную TelE
              deistvie();                   //выполняем действие
              NumT=0;                       //сбрасываем счетчик
              break;                        //выходим из цикла
            }
          }
          
          else {                            //если не находим телефон
            NumT++;                         //переходим к следующему телефону
            //пока не дойдем до конца списков номеров
            if (NumT == KolMas) {           //дошли до конца списков номеров
              NumT = 0;                     //сбрасываем счетчик
              
              if (digitalRead(PinAddDel) == HIGH) {  //если кнопка зажата
                while (NumT < KolMas) {       //начинаем искать пустую ячейку
                  if (strstr(TelE, TelZero)) {//если находим
                    for (byte i=0; i<10; i++) {   //записываем телефон в ЕЕПРОМ
                      EEPROM.write(Adress[NumT]+i, Temp[i]);
                    }
                    break;                    //выходим из цикла
                  }
                  else {                      //если не находим
                    NumT++;                   //следующий номер
                  }
                }
              }

              NumT = 0;                     //сбрасываем счетчик
              Temp[0] = 0;                  //очистить переменную Temp
              TelE[0] = 0;                  //очистить переменную TelE
              break;                        //выходим из цикла
            }                               //конец "дошли до конца списков номеров"
            
          }                                 //конец "если не находим телефон"
        }                                   //конец цикла поиска
      }                                     //конец "если нашли АОН"
      else {                                //если не нашли АОН
        Serial.println("AT+CPAS");          //спрашиваем состояние модема   
        if (Serial.find("+CPAS: 0")) {      //если звонка нет
          Serial.println("AT+CLIP=0");      //отключаем АОН
          digitalWrite(zvonok, LOW);        //говорим что входящих нет
          break;                            //выходим из цикла
        }                                   //конец "если звонка нет"
      }                                     //конец "если не нашли АОН"
    }                                       //конец цикла поиска номера
  }                                         //конец "если нашли RING"
  //продолжение кода
}

void deistvie() {
  digitalWrite(PinPower, !digitalRead(PinPower));
  
}
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

С Победой!

None
Offline
Зарегистрирован: 15.01.2016

Ну прошел почти месяц, работает стабильно, нареканий нет.

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

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

Спасибо, пригодился ваш скетч для доработки сигнализации. Ато мучался с массивами, незнал как использовать несколько номеров.

None
Offline
Зарегистрирован: 15.01.2016

Значит не зря потел :)

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

вопрос по ЕЕПРОМ: по вашему коду у меня почему-то сохраняется в ЕЕПРОМ последние 8 цифр номера. в чем может быть проблема?

None
Offline
Зарегистрирован: 15.01.2016

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

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

да, переделал немного. и убрал кнопку. никак не могу осилить сохранение и проверку номеров в еепром