»»

Работа с Ethernet Shield W5100 на примере метеостанции

2015-10-18 в 11:51

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

Нашей командой разработчиков была разработана и протестирована за несколько вечеров и одну бессонную ночь прошивка, с который вы сейчас ознакомитесь на примере Arduino метеостанции.
Здесь мы разберемся, как вывести значения с датчиков, добавить картинки на страницу загрузив их из карты памяти.
Назовем это все Arduino метеостанция.
Ethernet Shield представляется из себя "ломтик сыра для батона", где батон это будет у нас Arduino Uno. Ведь способ их подключения похож на бутерброд=)

 

подключение ethernet shield к ардуино

 

ethernet shield

Теперь открываем Arduino IDE и открываем Файл - Образцы - Ethernet - WebServer либо копируем отсюда.

Код
#include <SPI.h>
#include <Ethernet.h>

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 0, 20);

EthernetServer server(80);

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
 
// start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write©;
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");
          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();
    Serial.println("client disconnected");
  }
}

Вот что мы получим, если в строке браузера введем ip-адрес который прописан в коде.

пример работы ethernet shield

Страница толком не сформирована, только 6 аналоговых датчиков. Кому может быть это интересным? Идем дальше.
Убираем лишнее, оставляя один для датчика дыма и газов MQ-2. А еще добавим строку для подключения датчика температуры и влажности Dht11. А так же сделаем страничку нашу немного информативнее.

Что бы работать с DHT-11, подключаем библиотеку dht11.h прописываем пин на котором подключен датчик (у нас будет 7 цифровой пин) и вводим переменные. Верхняя часть кода получится такой.

Код
#include <dht11.h>
#include <SPI.h>
#include <Ethernet.h>
dht11 DHT;
#define DHT11_PIN 7

Чтобы на страницу выводить русские символы, кириллицу, вызываем команду установки кодировки текста:

Код
client.println("<meta http-equiv='content-type' content='text/html; charset=UTF-8'>");

Сделаем имя странице, то есть тайтл:

Код
client.println("<title>Данные с датчиков</title>");

А чтобы наша страничка обновляла значения с датчиков пишем тег "refresh" со значением 5 секунд.

Код
client.println("<meta http-equiv='refresh' content='5'/>");

У нас должен получится такой код:

Код
#include <dht11.h>
#include <SPI.h>
#include <Ethernet.h>
dht11 DHT;
#define DHT11_PIN 7

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();
}

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 (c == '\n' && currentLineIsBlank) {
          // 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("<meta http-equiv='refresh' content='5'/>");
          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("Датчик дыма = ");
          client.print(sensorReading);
          client.println("<br />");

          int chk;
          chk = DHT.read(DHT11_PIN);
          client.print("Температура = ");
          client.print(DHT.temperature);
          client.print(" °C<br/>");
          client.print("Влажность = ");
          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>");
          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();
 }
}

Есть русские символы, тайтл и обновляемая информация с наших датчиков.

вывод показаний с датчиков ethernet shield

Это еще не все.

На борту w5100 имеет слот sd карты памяти, помоему глупо, делать статью и не вставить в нашу страничку пару иконок.

Подключаем библиотеку для работы с SD картой памяти (она по дефолту идет в IDE).

Код
#include <SD.h>

Говорим программе что надо работать с SD картой. Теперь "Setup" получился такой:

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

Изображения делаем небольшого размера, чтобы не были на всю страницу. Favicon имеет фиксированый размер 16х16 пикселей и расширение .ico.
Этой строкой мы вызываем показ favicon:

Код
client.println("<link rel='shortcut icon' href='favicon.ico' type='image/x-icon'>");

В начало строки выводим картинку.

Код
client.print("<img src='/flame.png'/>Датчик дыма = ");

К остальным значениям по этому примеру.
Но мало прописать ссылку на картинку. Надо еще дать команду на открытие этой картинки. Это необходимо проделать для каждого файла.

Код
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();
          }

Вот что должно получиться:

Код

#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;
}

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

чтение SD карты ethernet shield

Библиотека DHT11
Архив с иконками. Распаковать в корень карты.

Продолжение следует. А вот и продолжение!

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

Наименование Тип Количество Магазин
Arduino UNO R3 1 Найти
Ethernet Shield W5100 1 Найти
Датчик температуры и влажности DHT-11 1 Найти
Датчик дыма и газов MQ-2 1 Найти
Провода Dupont Папа-Мама Провода Dupont Папа-Мама 6 Найти
Cashback на Aliexpress
Если Вы заметили ошибку, нажмите Ctrl+Enter и сообщите нам.
Оценка статьи: 4.9/5 Уже оценило 346
Всего комментариев: 7
СЕргей 2016-03-02 22:38
Я понимаю что все понятно для спецов. Но подскажите как подключать шилд? Я сделал пирог, ардуино уно и шилд, подключил ардуинку к компу залил скетч. Но я так понимаю надо шилд к роутеру подключить? провод надо? допустим провод найду, у меня сразу сервак появится?
Администратор
Администратор 2016-03-02 22:51
Сергей, проводом можете подключить к ноутбуку, к роутеру. Чтобы работало необходимо подбирать адрес в скетче чтобы был похож на ваши адреса в сети домашней.
Сергей 2016-07-15 14:06
Добрый день! Все сделал как у вас написано, но не отображаются картинки. При компиляции вылезает предупреждение - красная надпись "deprecated conversion from string constant to char". Загрузка программы в Ардуино происходит и сервер работает, но вместо картинок квадраты. Помогите разобраться что не так.
Сергей 2016-07-15 14:18
Вопрос снимаю. Заменил флешку и все заработало! biggrin
Хотя странно, флешка на компе нормально работала...
ВЛАДиМИР 2016-08-04 13:19
Добрый день уважаемый Админ! Подскажите почему страница с показаниями датчика открывается только в домашней сети? А смартфон с его 3G страницу не видит? Надо как-то подбирать и прописывать внешний ip???
Mick 2016-09-01 17:23
ВЛАДиМИР, Вам нужно белый IP-адрес получить у вашего провайдера. Обычно стоит денег. У ДоМру 450р подключение + 20 р каждый месяц. Затем нужно настроить в роутере правило трансляции и проброс порта.
Александр 2016-11-13 17:28
При компиляции ругается:
Код
:\Users\Александр\Documents\Arduino\MH02\MH02.ino: In function 'void loop()':

MH02:39: error: 'StrContains' was not declared in this scope

MH02:108: error: 'StrClear' was not declared in this scope

exit status 1
'StrContains' was not declared in this scope

Что делать? cry
Ответ: Александр, попробуйте скетч сохранить в корневой папке какого либо диска, у вас видимо имя пользователя русскими буквами написано может
поэтому и ругается
Добавить комментарий

Вход на сайт

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