»»
Добавить статью

Работа с 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
Arduino UNO
Хорошая платка. В подарок шел usb кабелек.
Индикатор EDC190
Прикольный индикатор. Можно понастольгировать=)

Всего комментариев: 13
СЕргей 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

Ответ Автора: Александр, попробуйте скетч сохранить в корневой папке какого либо диска, у вас видимо имя пользователя русскими буквами написано может
поэтому и ругается
Роман 2016-12-31 15:14
Скажите пожалуйста из за чего не переводит на русский язык. То есть. Изначально все было хорошо а потом все стало квадратиками с знаком вопроса, переписал на англ язык читается пишешь русскими опять квадраты.

Ответ Автора: Необходимо подключить кодировку utf8 Проверьте правильность кода либо скопируйте со страницы. Так же почистите кэш браузера.
Андрей 2017-01-18 13:33
Что это и для чего? И если не затруднит объясните подробными коментариями джава скрипт для динамического обновления.

Код
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][/i]) {
found++;
if (strlen(sfind) == found) {
return 1;
}
}
else {
found = 0;
}
index++;
}
return 0;
}

Ответ Автора: Данный скрипт позволяет осуществлять обновление только поступающих данных с датчиков. При этом нет нужды обновлять всю страницу целиком.
Андрей 2017-01-18 15:04
Я конечно понимаю, интеллектуальная собственность и всё такое, но если не хотите отвечать, так и скажите... джава скрипт, без комментариев и следовательно непонятно как он работает, по данному вопросу в инете мало информации и в таком скрипте разберётся только человек всю жизнь пишущий на джаве. Например: request.open("GET", "ajax_flame" + nocache, true); в данной строке "Путь" это "ajax_flame" Где в коде видно что это такое? Я не понимаю какой в итоге ПУТЬ для запроса скрипта данных для датчика.

Ответ Автора: Если бы я был автором данного скрипта, я бы смог вам помочь куда больше)
Помогал с этими проектами один человек, но более он такой возможностью не обладает.
Андрей 2017-01-18 17:59
Спасибо! Будем дальше копать инфу:)

Игорь 2017-03-22 13:11
Доброго времени суток! Воспользовался я данным скетчем но почему то не выводит Вэб сервер ничего Страница не найдена. IP и MAC Прописывал свои! Ошибок при компиляции не было! Что может быть?

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

byte mac[] = {
0x78, 0xAC, 0xC0, 0x9B, 0x19, 0xC8
};
IPAddress ip(192, 168, 13, 3);
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("Content-Type: text/html");
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();
}
}

Игорь 2017-03-22 15:26
Всё снимается вопрос! Забыл SD карту в кардридере! Всё работает! Автору темы Спасибо! biggrin

Добавить комментарий
Яндекс.Метрика Рейтинг@Mail.ru webmoney attestation Проверка орфографии