Помогите разобраться с сервером на ардуино и вводом цифр с клавиатуры одновременно

Grek303
Offline
Зарегистрирован: 01.07.2019

Доброго времени суток. Задумал сделать автоматизацию калитки, но не могу разобраться с кодом. Хочу сделать на ардуино мега (+ ethernet шилд ) веб сервер по считыванию показаний с датчиков: геркон, клавиатура ну и электрозамок. На ардуине должен работать веб сервер, и в тоже время ардуинка будет отсылать запрос на локальный веб сервер о статусах датчиков. Но при одновременном считывании цифер с клавиатуры веб сервер подвисает и не работает.

//=======================================================
// Имя устройства: Gate
// Геркон положение двери: 0=закрыто; 1=открыто.
// Кнопка звонка: 1=нажата.
// Электрозамок: 1=открыть.
// Клавиатура: ввод пароля 0123456789.
//=======================================================

//========== Настройки ==================================
//#define DEV_NAME "Gate"   // Название устройства 
//#define DEV_KEY  "35bd29" // Уникальный ключ устройства
//=======================================================

//========== Библиотеки =================================
#include <SPI.h>
#include <Ethernet.h>
#include <SoftwareSerial.h> // Серийный порт
#include <Keypad.h> //Клавиатура
//=======================================================

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //физический мак адрес
IPAddress ip(192,168,0,110); // IP адрес в сети
IPAddress gateway(192,168,0,1); // internet access via router
IPAddress subnet(255,255,255,0); //маска подсети
IPAddress myserver (192,168,0,2);//(192, 168, 0, 2); // IP удаленного сервера
EthernetServer server(80); //Порт сервера 80
EthernetClient client;
String readString;
//=======================================================

const char* DEV_KEY = "35bd29"; // ключ шифрования
const char* DEV_NAME = "Gate"; // наименование устройства
// ################################геркон################################
int Door_Sensor_Pin = 4; // контакт для геркона
int val = 0; // переменная для хранения состояния датчика геркона
// ######################################################################
SoftwareSerial RfidReader(0, 1); // Rfid ридер pin RX and pin TX
// ######################################################################
int Relay = 22; //Pin для подключения реле
// ######################################################################

void setup() {
  //==========================================================================
  Ethernet.begin(mac, ip, subnet, gateway);
  server.begin();

  Serial.begin(9600);
  Serial.println("Server/Client 1.0 test 24/06/19"); // keep track of what is loaded
  Serial.println("Send an g in serial monitor to test client"); // what to do to test client

  Serial.print("  DHCP assigned IP ");
  Serial.println(Ethernet.localIP());
  //==========================================================================

  pinMode(Relay, OUTPUT);  // ВЫХОД РЕЛЕ
  pinMode(Door_Sensor_Pin, INPUT); // ГЕРКОН установить Door_Sensor_Pin как вход
}

void loop() {
   WebSrv(); 
   passCheck();
}

//Функция клиента по отправке/принятию Get запроса с данными.
void sendGET(String sTrg) {
  if (client.connect(myserver, 80)) {
    Serial.println("connected");
    Serial.print("connected to ");
    Serial.println(client.remoteIP());
    Serial.println();
    Serial.println("GET " + sTrg + " HTTP/1.0");       
    client.println("GET " + sTrg + " HTTP/1.0");
    client.println();
  }
  else {
    Serial.println("Connection failed!");
    Serial.println();
  }

  while (client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read();
    Serial.print(c);
  }

  Serial.println();
  Serial.println("Disconnecting.");
  Serial.println("==================");
  Serial.println();
  client.stop();

}

// Функция открытия калитки
void OpenDoor () {
  digitalWrite(Relay, HIGH);   // реле включено
  delay(500);
  digitalWrite(Relay, LOW);  // реле выключено
}


void WebSrv() {

// check for serial input
  if (Serial.available() > 0)
  {
    byte inChar;
    inChar = Serial.read();
    if (inChar == 'g')
    {
      sendGET("/arduino.txt"); // call sendGET function
    }
  }

  EthernetClient client = server.available();

  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string
          readString += c;
          //Serial.print(c);
        }
          //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging

          //now output HTML data header
          if (readString.indexOf('?') >= 0)  {//don't send new page
            client.println("HTTP/1.1 204 GSH");
            client.println();
            client.println();
          }
          else {
            client.println("HTTP/1.1 200 OK"); //send new page
            client.println("Content-Type: text/html");
            client.println();

            client.println("<HTML>");
            client.println("<HEAD>");
            client.println("<TITLE>Smart Device GATE v1.0</TITLE>");
            client.println("</HEAD>");
            client.println("<BODY>");

            client.println("<H1>Smart device GATE v1.0 by Arduino</H1>");

            client.println("Open gate: ");
            client.println("<a href=\"/?gateOpen\" target=\"inlineframe\">Open</a>");
            //client.println("<a href=\"/?off\" target=\"inlineframe\">OFF</a>");
            client.println("");
            client.println("Status Gate: Close");
            client.println("Bell button: Not pressed");
            
            //client.println("<IFRAME name=inlineframe src=\"res://D:/WINDOWS/dnserror.htm\" width=1 height=1\">");
            client.println("<IFRAME name=inlineframe style=\"display:none\" >");
            client.println("</IFRAME>");

            client.println("</BODY>");
            client.println("</HTML>");
          }

          //delay(1);
          //stopping client
          client.stop();
          
          ///////////////////// control arduino pin
          if (readString.indexOf("gateOpen") > 0) //checks for on
          {
           // digitalWrite(4, HIGH);    // set pin 4 high
            Serial.println("Gate OPEN");
            OpenDoor();
          }
          if (readString.indexOf("off") > 0) //checks for off
          {
           // digitalWrite(4, LOW);    // set pin 4 low
            Serial.println("Led Off");
          }
          //clearing string for next read
          readString = "";

        }
      }
    }
    
  }
  
}
/*
Модуль работы с цифровой клавиатурой
*/

#define NUM_KEYS 6 // количество знаков в коде

char key;
char myarraw[NUM_KEYS] = { '2', '0', '1', '1', '8', '6'}; // массив с верным кодом
char button_pressed[NUM_KEYS]; //массив для хранения нажатых кнопок
int k=0; // счетчик нажатий
int s=0; // счетчик совпадений нажатых кнопок с верными
const byte ROWS = 4; // количество строк в матрице клавиатуры
const byte COLS = 4; // количество столбцов
char keys[ROWS][COLS] = { // таблица соответствия кнопок символам
                        {'1','2','3','A'},
                        {'4','5','6','B'},
                        {'7','8','9','C'},
                        {'*','0','#','D'}};
byte rowPins[ROWS] = {12, 11, 10, 9}; // пины подключенных строк
byte colPins[COLS] = {8, 7, 6, 5}; // пины подключенных столбцов

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); // создаем объект клавиатуры для работы с ней

/*void setup() {
  Serial.begin(9600);
  Serial.print("Введите пароль:");
}*/

/*void loop (){
passCheck();
}*/

void passCheck(){
 key = keypad.getKey(); // спрашиваем у клавиатуры, есть нажатая кнопка?
   if ( key != NO_KEY ){ // если она все-таки есть
    button_pressed [k] = key; //сохраняем эту кнопочку в массиве
    Serial.print(key);
    k = k + 1; // запоминаем сколько уже кнопок нажали
      if(k == NUM_KEYS){ // если нажали нужное количество кнопок
        for ( uint8_t i = 0; i < NUM_KEYS; i++){ // пройдемся по всему массиву
          if (button_pressed[i] == myarraw[i]){ // и проверим нажатые кнопки с верным кодом
            s = s + 1; // плюсуем счетчик совпадений
          }
         }
      if(s == NUM_KEYS){ //если у нас все кнопки совпали с кодом, то включаем реле
        Serial.println("открыто");        
        Serial.println("");
        sendGET("/robots.txt");
        k=0; //сбрасываем счетчик нажатий нашей переменной
        s=0; // сбрасываем счетчик совпадений нашей переменной
      } else { // если не все кнопки совпали с верным кодом
         Serial.println("ошибка доступа");
         // включаем красный светик (пользователь ввел неверный код)
          //delay (5000); // ждем 5 секунд
        // гасим красн светик
        k=0; // обнуляем счетчики, чтобы начать все заново
        s=0; //
      }
    }
  }
} 

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Первое что вижу это:

 

Ethernet.begin(mac, ip, subnet, gateway);
045

  server.begin();

Если объявил переменную server, то и оперируй ей. 

Мне кажется вместо этих двух строчек должна быть одна:

server.begin(mac, ip, subnet, gateway);
045  

Но могу ошибаться, до Ethernet мне ещё далеко, а записи смущают точно. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Это разные объекты. Ethernet управляет общей конфигурацией чипа - адреса, маки, гейтвеи и пр. EthernetServer - виртуальный sockets set, который разруливает входящие коннекты (в чипе его нет, существует только в воображении программиста).

Grek303
Offline
Зарегистрирован: 01.07.2019

Получается тут ошибки нет?

sadman41
Offline
Зарегистрирован: 19.10.2016

Почему же нет... Если не работает, значит есть. Обычно хрень получается на строках типа 80 и 81.

Grek303
Offline
Зарегистрирован: 01.07.2019

А как её побороть? Хотя без подключения клавиатуры все работает.

sadman41
Offline
Зарегистрирован: 19.10.2016

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

Grek303
Offline
Зарегистрирован: 01.07.2019

Ну ведь функция loop она зацикливается и ждет завершения функции по порядку. А функция обработки клавиатуры ждет ввода с клавиатуры до 6 символов. Может она по этому зависает и ждет завершения функции?

Morroc
Offline
Зарегистрирован: 24.10.2016

Зависает при нажатии первой же кнопки ? Ожидания нет, функцию опроса оно вроде должно проскакивать и с нажатой кнопкой и без.

Grek303
Offline
Зарегистрирован: 01.07.2019

Мне кажется зависает сразу после запуска.

Morroc
Offline
Зарегистрирован: 24.10.2016

А если убрать passCheck(); виснет ? 

Grek303
Offline
Зарегистрирован: 01.07.2019

Нет. Работает так как надо.

Morroc
Offline
Зарегистрирован: 24.10.2016

Если key = keypad.getKey(); заменить на key = NO_KEY;  ?

Grek303
Offline
Зарегистрирован: 01.07.2019

Спасибо за совет. Доберусь до ардуинки и отпишусь.

Grek303
Offline
Зарегистрирован: 01.07.2019

Morroc пишет:

Если key = keypad.getKey(); заменить на key = NO_KEY;  ?

В этом случае работает только web server. Клавиатура по понятным причинам нет.

Grek303
Offline
Зарегистрирован: 01.07.2019

Но при этом клавиатура работает...

sadman41
Offline
Зарегистрирован: 19.10.2016

В Serial Monitor что написано?

Grek303
Offline
Зарегистрирован: 01.07.2019

20:31:10.233 ->
20:31:10.233 ->
20:31:10.233 ->
20:31:10.233 ->
20:31:10.233 ->
20:31:10.273 ->
20:31:10.273 ->
20:31:10.273 ->
20:31:10.273 ->

Очень быстро выдает...
 

sadman41
Offline
Зарегистрирован: 19.10.2016

Не вижу, из какого фрагмента кода это.

Grek303
Offline
Зарегистрирован: 01.07.2019

Вообщем все перепробовал. Как только функцию  passCheck(); вставляю в любой части кода сервер виснет полностью...

sadman41
Offline
Зарегистрирован: 19.10.2016

Я же говорю - собирать надо. Так, в голове, не отследишь что куда и почем.

Grek303
Offline
Зарегистрирован: 01.07.2019

Пустые строки выдает клавиатура.... я ставил вывод в порт переменной key.

Grek303
Offline
Зарегистрирован: 01.07.2019

Ну вообщем заменил библиотеку на <Adafruit_Keypad.h> та же самая проблема. Но если убрать из блока setup вот это код customKeypad.begin(); в мониторе отображается:

19:34:32.639 -> 6 released
19:34:32.639 -> # released
19:34:32.679 -> 1 released
19:34:32.679 -> * released
19:34:32.679 -> # released
19:34:32.719 -> 1 released
19:34:32.719 -> * released
19:34:32.719 -> # released
19:34:32.759 -> 1 released
19:34:32.759 -> * released
19:34:32.759 -> # released
19:34:32.799 -> 4 pressed
19:34:32.799 -> * released
19:34:32.799 -> 2 pressed
19:34:32.799 -> 5 pressed
19:34:32.839 -> 3 pressed
19:34:32.839 -> 6 pressed
19:34:32.839 -> # released
19:34:32.879 -> 1 released
19:34:32.879 -> 4 released
19:34:32.879 -> * released
19:34:32.919 -> 5 released
19:34:32.919 -> 3 released
19:34:32.919 -> 6 released
19:34:32.919 -> # released
И при этом работает сервер в штатном режиме....

Вообщем копаю дальше....