Проект Охранная GSM система. Нужна помощь

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Добрый день коллеги! Пишу свой проектик по охранной системе. Вроде все написал, спаял, начал тестировать. Проект должен работать на Iskra Mini, когда заливаю на Mega, то все работает норм. Все команды принимает и обрабатыват. Шилда на чипе - Sim900, залил в нее прошиву "1137B08SIM900M64_ST_DTMF_JD_MMS" для работы с DTMF сигналами. Заливаю на Mini и получаю полный хаос... то не поднимает трубку, то поднимает трубку не от первого абонента, а от второго, то dtmf сигналы распознавать не хочет. Вообщем сложно дать полную оценку. Привожу полный свой код программы. Может я где-то не вижу косяк в коде... бывает такое что глаз замыливается и в упор не видишь... А может дело в аппаратной части, если не в программной. Вообщем вот:

#include <EEPROM.h>
#define DEFAULT_TIMEOUT          2   //seconds
#define DEFAULT_INTERCHAR_TIMEOUT 500   //miliseconds

const int pwr_st = 10; // состяние питания от сети, если плюс - то есть
const int dt_plus = 8; // постоянный плюс на датчик
const int dt_m = 9; // контакт датчика, если плюс - то замкнут геркон
const int gprs_pw = 3; // контакт питания шилды

byte Signal = 0; //запись уровня сигнала в глобальную
bool StatusArm = false;
bool DialUp = false;
bool IncomRead = false; // если фалс то разрешено читать буф с SerEvent
char inputString[100];
bool stringComplete = false;
bool SendSmsSt=false;
bool SendSmsA=false;
bool DoorOpen=false;
int newStatePw=0; // состояние питания из памяти
bool GPRSOnline=false;
char SigGMS[5];

unsigned pauseT3 = 5000; // пауза опроса питания
unsigned long timeT3 = millis();

const char* Tel[] = {"89xxxxxxxx1", "89xxxxxxxx2", "89xxxxxxxx3", "89xxxxxxxx4", "89xxxxxxxx5"};
char Tel1[13] = "+79xxxxxxxx1";
char Tel2[13] = "+79xxxxxxxx2";
char Tel3[13] = "+79xxxxxxxx3";
char Tel4[13] = "+79xxxxxxxx4";
char Tel5[13] = "+79xxxxxxxx5";

int numtel = 0;
int lastcomm = 1;

enum DataType {
  CMD     = 0,
  DATA    = 1,
};

unsigned pauseAT = 15000; // пауза dpp2
unsigned long timeAT = millis();

void EEPROMWriteInt(int p_address, int p_value)
{
  byte lowByte = ((p_value >> 0) & 0xFF);
  byte highByte = ((p_value >> 8) & 0xFF);

  EEPROM.write(p_address, lowByte);
  EEPROM.write(p_address + 1, highByte);
}
unsigned int EEPROMReadInt(int p_address)
{
  byte lowByte = EEPROM.read(p_address);
  byte highByte = EEPROM.read(p_address + 1);

  return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}



void PowerSw() {
  digitalWrite(13, HIGH);
  digitalWrite(gprs_pw, LOW);
  delay(1000);
  digitalWrite(gprs_pw, HIGH);
  delay(2000);
  digitalWrite(gprs_pw, LOW);
  delay(3000);
  digitalWrite(13, LOW);
}



boolean sim900_wait_for_resp(const char* resp, DataType type, unsigned int timeout = DEFAULT_TIMEOUT, unsigned int chartimeout = DEFAULT_INTERCHAR_TIMEOUT)
{
  
  int len = strlen(resp);
  int sum = 0;
  unsigned long timerStart, prevChar;    //prevChar is the time when the previous Char has been read.
  timerStart = millis();
  prevChar = 0;
  while (1) {
    if (Serial.available()) {
      char c = Serial.read();
      prevChar = millis();
      sum = (c == resp[sum]) ? sum + 1 : 0;
      if (sum == len) {
       
        break;
      }
    }
    if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
           return false;
    }
    //If interchar Timeout => return FALSE. So we can return sooner from this function.
    if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
      
      return false;
    }

  }
  //If is a CMD, we will finish to read buffer.
  if (type == CMD) sim900_flush_serial();
  
  return true;
}

boolean sim900_check_with_cmd(const char* cmd, const char *resp, DataType type, unsigned int timeout = DEFAULT_TIMEOUT, unsigned int chartimeout = DEFAULT_INTERCHAR_TIMEOUT)
{
  if (strlen(cmd) > 0) {
    Serial.write(cmd);
  }
  return sim900_wait_for_resp(resp, type, timeout, chartimeout);
}
void sim900_flush_serial() {
  
  while (Serial.available()) {
    char c = Serial.read();
  }
}

void sim900_send_cmd(const char* cmd)
{
  if (strlen(cmd) > 0) {
    Serial.write(cmd);
  }

}
void sim900_clean_buffer(char *buffer, int count)
{
  for (int i = 0; i < count; i++) {
    buffer[i] = '\0';
  }
}

void simInitAT() {  
  sim900_check_with_cmd("AT+CMGF=1\r\n", "OK", CMD);
  sim900_check_with_cmd("AT+CLIP=1\r\n", "OK", CMD);
  sim900_check_with_cmd("AT+IFC=1,1\r\n", "OK", CMD);
  sim900_check_with_cmd("AT+CNMI=1,2,2,1,0\r\n", "OK", CMD);
  sim900_check_with_cmd("AT+VTD=1\r\n", "OK", CMD);
  sim900_check_with_cmd("AT+DDET=1\r\n", "OK", CMD);
}

void sim900_read_buffer(char *buffer, int count, unsigned int timeout = DEFAULT_TIMEOUT, unsigned int chartimeout = DEFAULT_INTERCHAR_TIMEOUT) // принимает буфер, размер этого буфера. Пишет в него и возвращает
{
   if (StatusArm == true) {
    if (digitalRead(dt_m) == LOW) {
      DoorOpen=true;
    }
   }
  int i = 0;
  unsigned long timerStart, prevChar, TimeZap;
  timerStart = millis();
  TimeZap= millis();
  prevChar = 0;
  while (1) {
    while (Serial.available()) {
      char c = Serial.read();
      prevChar = millis();
      buffer[i++] = c;
      if (i >= count) {
        
        break;
      }
    }
     if (i >= count)break;

    if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
     
      break;
    }
    //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
    if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
     
      break;
    }
    if ((unsigned long) (millis() - TimeZap) > 100) {
       if (StatusArm == true) {
         if (digitalRead(dt_m) == LOW) {
           DoorOpen=true;
        }
      }
     TimeZap=millis();
    }
  }
}



bool ifcallNow(void)
{
  return sim900_check_with_cmd("", "RING\r\n", CMD);
}


char ByteToChar(byte byteSt, byte num)
{
 const byte offset = 48;
  if (num==1) return char(offset+byteSt/10);
  if (num==2) return char(offset+byteSt-byteSt/10*10); 
}


byte CheckSignal() {
 byte result = 99;  
 if (IncomRead == false) { // Если мы не отправляем смс то можно читать параметры сигнала
  char gprsBuffer[21];
  sim900_clean_buffer(gprsBuffer, 21);
  char *s;
  sim900_send_cmd("AT+CSQ\r\n");
  sim900_read_buffer(gprsBuffer, 21, 5);
  if (NULL != ( s = strstr(gprsBuffer, "+CSQ: "))) {
    result = atoi(s + 6);   
    sim900_wait_for_resp("OK\r\n", CMD);
  }
  return result;
 }
 return result;
}



bool sendSMS(char *number, char *data)
{
  // Set message mode to ASCII  
  sim900_send_cmd("AT+CMGS=\"");
  sim900_send_cmd(number);

  if(!sim900_check_with_cmd("\"\r\n",">",CMD)) {
      return false;
  }
  delay(1000);
  sim900_send_cmd(data);
  delay(500);
  Serial.println((char)26);
  return true;
}
    
bool sms_text(char *txt) {
 IncomRead = true; // Указываем что работает отправка смс
  digitalWrite(13, HIGH);
  
  sim900_send_cmd("AT+CMGS=\"");
  sim900_send_cmd(Tel1);
  if(!sim900_check_with_cmd("\"\r\n",">",CMD)) {
    IncomRead = false;
      return false;
  }
  delay(1000);
  sim900_send_cmd(txt);
  delay(300);
  Serial.println((char)26);
  delay(200);
  delay(10000);
  sim900_send_cmd("AT+CMGS=\"");
  sim900_send_cmd(Tel2);
  if(!sim900_check_with_cmd("\"\r\n",">",CMD)) {
    IncomRead = false;
      return false;
  }
  delay(1000);
  sim900_send_cmd(txt);
  delay(300);
  Serial.println((char)26);
  delay(200);
  digitalWrite(13, LOW);
  IncomRead = false; // Отпрвка смс окончена
  timeAT = millis();
}

void setup() {
  delay(3000);
  pinMode(13, OUTPUT); // светодиод
  pinMode(gprs_pw, OUTPUT); // power_sw gprs
  pinMode(pwr_st, INPUT); // состояние питания от сети
  pinMode(dt_plus, OUTPUT); // power_sw gprs
  pinMode(dt_m, INPUT); // читаем эту ногу - если разрыв то тревога. Т.е нет +
  digitalWrite(dt_plus, HIGH); // подать сигнал на датчик
  DialUp = false;
  Serial.begin(19200);
  if (EEPROMReadInt(1) < 2) {
    StatusArm = EEPROMReadInt(1); // состояние охраны в 1 адресе
  }
  sim900_clean_buffer(inputString, 99);
  
  bool SimOk = sim900_check_with_cmd("AT\r\n", "OK", CMD);

  if (SimOk == false) {
    PowerSw();
  }
  simInitAT();

}


void loop() {

  // put your main code here, to run repeatedly:
  if (millis() - timeAT >= pauseAT) {
   if ((DialUp == false) && (IncomRead==false)) {
    bool SimOk = sim900_check_with_cmd("AT\r\n", "OK", CMD);
    GPRSOnline=SimOk;
    if (SimOk == false) {            
      PowerSw();
      simInitAT();
    }
    Signal = CheckSignal();
    SigGMS[0]=ByteToChar(Signal,1);
    SigGMS[1]=ByteToChar(Signal,2);
    }
    timeAT = millis();
  }

 sim900_read_buffer(inputString, 99); //получаем все сообщения от сим


  int len = strlen(inputString);

  if (inputString[0] != '\0') {    
    stringComplete = true;
  }

  if (stringComplete) {
    
    if (NULL != (strstr(inputString, "+CLIP:"))) {
    
      numtel = 0;
      if (NULL != (strstr(inputString, Tel1))) {
        numtel = 1;
      }
      if (NULL != (strstr(inputString, Tel2))) {
        numtel = 2;
      }
      if (NULL != (strstr(inputString, Tel3))) {
        numtel = 3;
      }
      if (NULL != (strstr(inputString, Tel4))) {
        numtel = 4;
      }
      if (NULL != (strstr(inputString, Tel5))) {
        numtel = 5;
      }

      if (numtel > 0) {      
        sim900_check_with_cmd("ATA\r\n", "OK\r\n", CMD);
        DialUp = true;
        delay(2000);
        if (StatusArm == true) {
          Serial.println("AT+VTS=\"1,9\""); // тоновый сигнал
        } else {
          Serial.println("AT+VTS=\"5,5,5\""); // тоновый сигнал
        }

      }

    }

    if (NULL != (strstr(inputString, "+DTMF:0"))) { // запускаем систему    
      sim900_check_with_cmd("AT+VTS=\"0\"\r\n","OK\r\n", CMD);
      sim900_check_with_cmd("AT+VTS=\"1,9\"\r\n","OK\r\n", CMD);
      StatusArm = false;
      lastcomm = numtel-1;
      EEPROMWriteInt(1, 0);
      delay(1000);
      sim900_check_with_cmd("ATH0\r\n","OK\r\n", CMD);
      DialUp = false;
      DoorOpen=false;
      timeAT = millis();
    }
  
  if (NULL != (strstr(inputString, "+DTMF:1"))) { // запускаем систему
  
   sim900_check_with_cmd("AT+VTS=\"1\"\r\n","OK\r\n", CMD);
   if (digitalRead(dt_m)==HIGH) {
    DoorOpen=false;
    sim900_check_with_cmd("AT+VTS=\"1,9\"\r\n","OK\r\n", CMD);
    StatusArm=true;   
    EEPROMWriteInt(1,1); // записали в 1 адрес единицу
    delay(1000);
    lastcomm=numtel-1;
    sim900_check_with_cmd("ATH0\r\n","OK\r\n", CMD);
    DialUp = false;
    timeAT = millis();
     } else
      {
        sim900_check_with_cmd("AT+VTS=\"9,9,9\"\r\n","OK\r\n", CMD);
        StatusArm=false;
        EEPROMWriteInt(1,0); // записали в 1 адрес 0
        delay(100);
      }  
  }


    if (NULL != (strstr(inputString, "+DTMF:3"))) { // запускаем систему
     
      sim900_check_with_cmd("AT+VTS=\"3\"\r\n","OK\r\n", CMD);
      sim900_check_with_cmd("AT+CMGDA=\"DEL ALL\"\r\n","OK\r\n", CMD);
      sim900_check_with_cmd("AT+VTS=\"3,3\"\r\n","OK\r\n", CMD);
    }

    if (NULL != (strstr(inputString, "+DTMF:9"))) { // запускаем систему
     timeAT = millis();
      sim900_check_with_cmd("AT+VTS=\"9\"\r\n","OK\r\n",CMD);
      sim900_check_with_cmd("ATH0\r\n","OK\r\n", CMD);
      DialUp = false;
      char flsend[60];
      strcpy(flsend, "Last telephone: "); 
      strcat(flsend, Tel[lastcomm]);          
      
      if (digitalRead(pwr_st) == HIGH) {
      strcat(flsend, "; 220B OK; SigGSM="); 
      } else {
       strcat(flsend, "; HET 220B; SigGSM=");  
      }        
      strcat(flsend, SigGMS); 
      sms_text(flsend);
      timeAT = millis();
    }

    if (NULL != (strstr(inputString, "NO CARRIER"))) { // запускаем систему
      DialUp = false; 
      timeAT = millis();   
    }

    if (NULL != (strstr(inputString, "ReInitAT"))) { // запускаем систему
     
      DialUp = false;
      char pwm2[22]="SIM Module is restart";
      if (sendSMS(Tel1,pwm2)) {     
        delay(5000);
        PowerSw();
      }
    }

    sim900_clean_buffer(inputString, 99);
    stringComplete = false;
  }
  
if ((digitalRead(pwr_st)==LOW) && (newStatePw==1)) {
   SendSmsA=false;   
}

if ((digitalRead(pwr_st)==HIGH) && (newStatePw==0)) {
   SendSmsSt=false;
}

if (millis() - timeT3 >= pauseT3) {
newStatePw=EEPROMReadInt(0);  

 if ((digitalRead(pwr_st)==HIGH) && (SendSmsSt==false))  { // Если от сети
  if (GPRSOnline==true) {
   char pwm[15]="Power 220B OK!";
   sms_text(pwm);    
   SendSmsSt=true;
   simInitAT();
   EEPROMWriteInt(0,1); 
   delay(80);  
  }
 }
 
if ((digitalRead(pwr_st)==LOW) && (SendSmsA==false))  { // Если от сети
  if (GPRSOnline==true) {
   char alm1[19]="Alarm!!! HET 220B!";
   sms_text(alm1);    
   SendSmsA=true;
   simInitAT();
   EEPROMWriteInt(0,0); 
   delay(80);  
  }
 }
 
newStatePw=EEPROMReadInt(0); 
 timeT3=millis(); 
}
  if (StatusArm == true) {
    if (digitalRead(dt_m) == LOW) {
      DoorOpen=true;
    }
    if (DoorOpen==true) {
      StatusArm = false;
      EEPROMWriteInt(1, 0);
      delay(100);
      char alm[23]="Alarm!!! DOOR IS OPEN!";
      sms_text(alm);
      delay(8000);
      timeAT = millis();
      Serial.println("ATD8xxxxxxxx1;");
      timeAT = millis();
    }
  }


}

Поглядите, проанализируйте, может где реальный косяк в коде?

P.S. может кто посоветует еще антенну для более уверенного сигнала GSM? Сейчас получаю AT+CSQ
+CSQ: 14,0 среднее. А так варьируется от 9 до 19. А иногда долго ищет связь...
 

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Ну хоть кто-нибудь уже пропробовал этот код потестить? Есть какие-нибудь результаты?

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

Dr_grizzly, боюсь вас разочаровать, но вряд ли кто станет тестить ваш пример из 500 строк. Думаю, даже просто загрузить и откомпилировать код желающих не найдется. Поиск нестабильности в программе - серьезная работа на много часов, поэтому не думаю, что кто-то бросится делать это за вас, когда вы даже не взяли себе за труд внятно описать, какие проблемы в коде.

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

toc
Offline
Зарегистрирован: 09.02.2013

Dr_grizzly,
1. у меня была аналогичная проблема с распознаванием дтмф, когда режим включал однократно в setup. Обошёл так: после каждого "разговора" включаю DDET повторно.
2. CSQ выдаёт значения от 1 до 32. У меня почти всегда меньше 10. Не придаю значения, работает же. Антенну советую оставить имеющуюся, особенно если связь стабильна. Не мудрить с антенной без серьёзной подготовки можно повредить радио модуль.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

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

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

Сейчас хочется реализовать этот проект в жизнь не через пол года, а уже.

Я уже пробовал отлаживать обмен данными между арду мини и шилдом через Мегу, таким образом, что Serial для отладки в комп, Serial1 для шилды, Serial2 для арду мини, тем самым вижу обмен АТ командами и текущее состояние шилды. Может еще какие-то навороты для отладки можно сделать? Поделитесь опытом плиз

 

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

toc пишет:
Не мудрить с антенной без серьёзной подготовки можно повредить радио модуль.

А если покупать готовую антенну GSM? например 3-5 dB? Существенно ли будет усилен сигнал? Я так понял что в комплекте идет антена 1-2 dB?

Разве можно спалить модуль антенной?

DDET я так же инициализирую как только связь с модулем пропадает., т.е если он не отвечает на АТ команду. Но попробовать можно после звонков повторять команду ))

А что на счет прошивки шилды? Рабочая ли эта версия прошивки? Я уже на нее грешным делом думать начал ))

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

Dr_grizzly, говорят SIM900 очень капризен по питанию.  Ему в пике нужно до 2А, его нужно подключить к хорошему мощному БП. Если у вас шилд питается от ардуины - стабильно работать он не будет.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

С питанием я уже сталкивался ранее, на других шилдах, сейчас в схеме питание у меня от внешнего power-банка, который отдает до 1А, но это питание временное, если нет питания от зарядника (который тож 1А ) А так же на линии питания у меня 5 кондеров по 1000мкФ. Думаете 1А может ему не хватать?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Начну помаленьку писать проблемы которые встречаю с ним. Вообщем сегодня: Включаю питание, приходит смс о состоянии питания(акб или 220), затем звоню на модуль, в ответ слышу 3 сигнала дтмф, означающих что охрана отключена. Жму любые клавиши дтмф, а в ответ тишина. Даже 9-ка не реагирует. Выключаю питание, включаю снова, все повторилось. Отправляю смс ReInitAT - модуль перезапустился но смс в ответ не прислал. Происходит запуск и приходит смс о питании и следом смс о принятой команде Restart... Звоню - слышу 3 гудка дтмф, пытаюсь дать команду дтмф - а в ответ тишина. Т.е не понимает или не слышит команды... Сейчас буду диагностировать через мегу

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Купил антену GSM. Испытываю.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Чудеса блин... подключил в разрыв линии передач Мегу и все работает стабильно! и отвечает дтмф и принимает команды...

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

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Стал по одной команде инициализиации записывать через Sеrial порт в GSM и звонить и проверять на работу дтмф приема. После команды AT+DDET=1 все заработало. Глюк прошивки видать. Добавил код для установки и снятии с охраны через смс, для пущей точности.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Еще заморочка - функция CheckSignal не хочет нормально отрабатывать. Постоянно дает значение 99, хотя в обмене gsm шлет значения от 14 до 19. А результат фукнции постоянно 99... Подозрение, что скорость обработки выше чем может gsm, хотя на прошивке 1137B06SIM900M64_ST_ENHANCE такого не было. Ну может раз-два за все время проскакивало.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Ну так и есть, просто сменил прошивку SIm900 на предыдущую и функция стала нормально работать

Кстати прошивки есть тут - http://simcom.ee/?gsm-gprs