»»

Работа с Ethernet Shield W5100 на примере метеостанции на Arduino. Часть 2

2015-10-19 в 20:35

Вот и логическое продолжение предыдущей статьи.

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

В процессе разработки была выявлена  недостаточность памяти. Поэтому нужно создать файл index.htm и загрузить в корень SD карты.
Содержание файла index.htm следующее:

Код

<!DOCTYPE HTML>
<html>
<head>
user-scalable=0;" />
<meta http-equiv='content-type' content='text/html; charset=UTF-8'>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<title>Данные с датчиков</title>
<script>
function GetFlameState()
{
nocache = "&nocache=" + Math.random() * 1000000;
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (this.readyState == 4) {
if (this.status == 200) {
if (this.responseText != null) {
var from = 0;
var to = this.responseText.indexOf(':');
document.getElementById("flame_txt").innerHTML = this.responseText.substring(from,to);
from = to+1;
to = this.responseText.indexOf(':',from);
document.getElementById("temp_txt").innerHTML = this.responseText.substring(from,to);
from = to+1;
document.getElementById("humid_txt").innerHTML = this.responseText.substring(from);
}
}
}
}
request.open("GET", "ajax_flame" + nocache, true);
request.send(null);
setTimeout('GetFlameState()', 1000);
}

</script>

</head>

<body onload="GetFlameState()">
<img src='flame.png' />Датчик дыма = <span id="flame_txt">null</span><br>
<img src='temp.png' />Температура = <span id="temp_txt">null</span>°C<br>
<img src='humid.png' />Влажность = <span id="humid_txt">null</span>%<br><br>
<form action='https://vk.com/programerge" target="_blank"><button type="submit" >Кнопка</button></form>
</Body>
</html>

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

Прошивка для Arduino выглядит так:

Код

#include <dht11.h>
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#define REQ_BUF_SZ 20
#define DHT11_PIN 7
dht11 DHT;
File webFile;

char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0; // index into HTTP_req buffer
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 0, 20);

EthernetServer server(80);

void setup() {
  Ethernet.begin(mac, ip);
  server.begin();
  (!SD.begin(4));
}

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {

    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (req_index < (REQ_BUF_SZ - 1)) {
          HTTP_req[req_index] = c; // save HTTP request character
          req_index++;
        }
        if (c == '\n' && currentLineIsBlank) {

          if (StrContains(HTTP_req, "GET / ")) {
            // send a standard http response header
            client.println("HTTP/1.1 200 OK");

            client.println("Connection: close");

            client.println();
            client.println("<!DOCTYPE HTML>");
            client.println("<html>");
            client.println("<link rel='shortcut icon' href='favicon.ico' type='image/x-icon'>");
            client.println("<meta http-equiv='refresh' content='10'/>");
            client.println("<meta http-equiv='content-type' content='text/html; charset=UTF-8'>");
            client.println("<title>Данные с датчиков</title>");
            
            int smoke_gas = 0; //пин на котором подключен MQ-2
            int sensorReading = analogRead(smoke_gas);
            client.print("<img src='/flame.png'/>Датчик дыма = ");
            client.print(sensorReading);
            client.println("<br />");

            int chk;
            chk = DHT.read(DHT11_PIN);
            client.print("<img src='temp.png' />Температура = ");
            client.print(DHT.temperature);
            client.print(" °C<br/>");
            client.print("<img src='humid.png /'>Влажность = ");
            client.print(DHT.humidity);
            client.print(" %");
            client.print("</br>");
            client.print("</br>");
            client.print("<form action='http://tehnopage.ru 'target='_blank'><button type='submit' >Tehnopage.ru</button></form>");

            client.println("</html>");
          } else if (StrContains(HTTP_req, "GET /temp.png")) {
            webFile = SD.open("temp.png");
            if (webFile) {
              client.println("HTTP/1.1 200 OK");
              client.println();
            }
          }
          else if (StrContains(HTTP_req, "GET /humid.png")) {
            webFile = SD.open("humid.png");
            if (webFile) {
              client.println("HTTP/1.1 200 OK");
              client.println();
            }
          }
          else if (StrContains(HTTP_req, "GET /flame.png")) {
            webFile = SD.open("flame.png");
            if (webFile) {
              client.println("HTTP/1.1 200 OK");
              client.println();
            }
          }
          else if (StrContains(HTTP_req, "GET /favicon.ico")) {
            webFile = SD.open("favicon.ico");
            if (webFile) {
              client.println("HTTP/1.1 200 OK");
              client.println();
            }
          }
            if (webFile) {
            while (webFile.available()) {
              client.write(webFile.read()); // send web page to client
            }
            webFile.close();
          }
          
          req_index = 0;
          StrClear(HTTP_req, REQ_BUF_SZ);
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}

void StrClear(char *str, char length)
{
  for (int i = 0; i < length; i++) {
    str[i] = 0;
  }
}

char StrContains(char *str, char *sfind)
{
  char found = 0;
  char index = 0;
  char len;

  len = strlen(str);

  if (strlen(sfind) > len) {
    return 0;
  }
  while (index < len) {
    if (str[index] == sfind[found]) {
      found++;
      if (strlen(sfind) == found) {
        return 1;
      }
    }
    else {
      found = 0;
    }
    index++;
  }
  return 0;
}

Как видите, сейчас занимаем места в памяти меньше чем в прошлой статье за счет загрузки части информации в файл index.htm.
В следующей части будем пробовать дальше развивать тему. Если у вас есть идеи, предлагайте.
UPD 26.10.15 Продолжение.

Список электронных компонентов.

Наименование Тип Количество Магазин
Arduino UNO R3 1 Найти
Ethernet Shield W5100 1 Найти
Датчик температуры и влажности DHT-11 1 Найти
Датчик дыма и газов MQ-2 1 Найти
Провода Dupont Папа-Мама Провода Dupont Папа-Мама 6 Найти
Cashback на Aliexpress
Если Вы заметили ошибку, нажмите Ctrl+Enter и сообщите нам.
Оценка статьи: 4.5/5 Уже оценило 12
Всего комментариев: 8
Дмитрий 2016-02-13 17:23
Спасибо большое вам за статьи. Очень помогают в изучении. К сожалению, в данной содержится ошибка. У вас не верно скопировалась прошивка для Arduino
Администратор
Администратор 2016-02-13 19:45
Дмитрий, да, в прошивке была ошибка. Заменили весь код на рабочий.
Vetrinus
Vetrinus 2016-04-16 12:12
Что-то я не совсем понял, а обработка ajax запроса где?
Это же новое соединение, в параметрах  request.open() указан url "ajax-flame", следовательно запрос должен адресоваться этому адресу.
Но фиг бы с ним, но я даже просто не могу найти код, который отдает данные новому соединению. Т.е. что-то вроде этого:
if (StrContains(HTTP_req, "ajax_flame")) {
   client.print(//некоторая функция, которая вернет нужные значения)
}

Я что-то упустил?
Буду крайне благодарен за пояснения
Vetrinus
Vetrinus 2016-04-16 12:25
Окей, идем дальше:
send() Отсылает запрос. Аргумент - тело запроса. Например, GET-запроса тела нет, поэтому используетсяsend(null), а для POST-запросов тело содержит параметры запроса.

Узрел, что в index.htm внутри спанов с нужными id находится null, а не функция, возвращающая результат опроса датчиков. Значит, нужно искать, в каком конкретно фрагменте кода происходит опрос датчиков. Т.к. можно догадаться, что при первичной генерации страницы данных и датчиков на ней никаких нет, то стало быть обновляются они только с помощью ajax. Стало быть, где обработка датчиков, там и обработка ajax запросов
Vetrinus
Vetrinus 2016-04-16 12:32
Эм.. Обработку запросов я так и не нашел, но зато нашел, что в скетче есть код, который отдает ВЕСЬ контент заново. С учетом того, что он уже отдан из index.htm. А зачем? Как мне кажется, ajax ведь и призван, чтобы отдавать ТОЛЬКО НУЖНЫЕ данные, а не все целиком.
Vetrinus
Vetrinus 2016-04-16 12:33
А то получается, перезагрузка страницы без перезагрузки страницы)
Mick 2016-08-17 17:34
Скажите, на каком пине сидит датчик дыма?
Администратор
Администратор 2016-08-17 22:23
Mick,
Код
int smoke_gas = 0; //пин на котором подключен MQ-2
Добавить комментарий

Вход на сайт

Яндекс.Метрика Рейтинг@Mail.ru Проверка орфографии