[Перевод] Starting Electronics: руководство по веб-серверам на Arduino. Часть 1

q3xfeztmxjwjpwsjub7shzdf5vw.jpeg

От переводчика. В сети есть много информации о работе веб-серверов на микроконтроллерах, но она плохо структурирована и не отличается системным подходом к изложению материала. Среди прочих есть в интернете один замечательный, можно сказать культовый, туториал (руководство) по работе веб-серверов на Arduino от проекта Starting Electronics. Его авторам удалось невозможное: всего в нескольких уроках просто и доступно донести сложные вещи — как сам принцип работы веб-вервера, так и работу сопутствующих технологий (HTTP, HTML, CSS, Javascript, AJAX и т. д.) и причём сделать в практической плоскости.

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

Часть 1. О руководстве и начало работы


Это руководство пошагово в нескольких простых уроках объясняет как работают веб-серверы на Arduino. Веб-серверы на микроконтроллерах имеют определённые ограничения и используются в основном для показа несложных веб-страниц, доступ к которым можно получить из браузера, работающего на вашем компьютере или смартфоне.

Ещё одна особенность веб-серверов на микроконтроллерах заключается в том, что с их веб-страниц можно получать доступ для управления аппаратными ресурсами самого контроллера, например включить и выключить светодиодный индикатор, или получать информацию, например о состоянии кнопки и отобразить её состояние на веб-странице и т. д.

В этом руководстве объясняется как работают веб-серверы, включая подробные пояснения по всем сопутствующим технологиям, таким как HTTP, HTML, CSS, JavaScript, AJAX и т. д. Сложность уроков постепенно возрастает, начиная с создания простой веб-страницы на Arduino и постепенно усложняясь (но всё равно оставаясь доступной для понимания начинающими).

Оборудование


Оборудование, необходимое для работы с этим руководством:

  • Контроллер Arduino, например Arduino Uno
  • Плата сетевого интерфейса Arduino Ethernet Shield
  • Сетевой Ethernet кабель для подключения к роутеру
  • USB кабель для питания и программирования контроллера Arduino
  • microSD карта памяти, например, размером 2 ГБ (требуется только для некоторых уроков)
  • Компьютер со слотом для microSD карты (требуется только для серверов с SD картами)


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

Настройка системы


rso_nb9npebinvx3jnduyvqksfw.jpeg

Перед началом работы нужно убедиться в общей работоспособности вашей системы (здесь предполагается, что вы обладаете начальными знаниями работы с Arduino):

  • Подключите Ethernet Shield к контроллеру Arduino и убедитесь в его работоспособности при помощи стандартных примеров.
  • Таким же образом протестируйте работу microSD карты памяти в составе вашей системы.


Часть 2. Базовый вариант Arduino веб-сервера


Это очень простой вариант веб-сервера, который с помощью Arduino Ethernet Shield обслуживает (передаёт в ответ на запрос пользователя) одну веб-страницу. SD карта в этом примере не используется, так как код веб-страницы хранится непосредственно в скетче Arduino.

Сервер с хранением веб-страницы в скетче Arduino


Следующий скетч позволяет контроллеру Arduino с Ethernet Shield передавать в ответ на запрос одну веб-страницу, которая затем отображается в браузере пользователя.

/*--------------------------------------------------------------
  Скетч: eth_websrv_page

  Описание: базовый пример веб-сервера Arduino со страницей, хранящейся в самом скетче (SD карта не используется)
  
  Оборудование: Arduino Uno и Arduino Ethernet Shield
                
  Программное обеспечение: Среда разработки Arduino IDE
  
  Ссылки: WebServer example by David A. Mellis and modified by Tom Igoe, Ethernet library documentation: http://arduino.cc/en/Reference/Ethernet

  Дата создания: 7 января 2013
 
  Автор: W. A. Smith (http://startingelectronics.org)
--------------------------------------------------------------*/

#include 
#include 

// MAC-адрес сетевой платы
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10, 0, 0, 20); // IP-адрес (нужно изменить на актуальный для вашей сети)
EthernetServer server(80);  // создаём сервер на 80 порту

void setup() {
    Ethernet.begin(mac, ip);  // инициализируем Ethernet
    server.begin();           // начинаем ожидать запросы от клиента
}

void loop() {
    EthernetClient client = server.available();  // (если есть) «получаем» клиента

    if (client) {  // есть клиент?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // данные от клиента доступны для чтения
                char c = client.read(); // чтение 1 байта (символа) от клиента
                // последняя строка от запроса клиента пустая и заканчивается на \n
                // отвечаем клиенту только после окончания запроса
                if (c == '\n' && currentLineIsBlank) {
                    // посылаем стандартный заголовок ответа
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    //посылаем саму веб-страницу
                    client.println("");
                    client.println("");
                    client.println("");
                    client.println("Arduino Web Page");
                    client.println("");
                    client.println("");
                    client.println("

Hello from Arduino!

"); client.println("

A web page from the Arduino server

"); client.println(" "); client.println(""); break; } // каждая строка текста, принятая от клиента, оканчивается на \r\n if (c == '\n') { // последний символ в строке принятого текста // начинаем новую строку со следующего прочитанного символа currentLineIsBlank = true; } else if (c != '\r') { // от клиента получен текстовый символ currentLineIsBlank = false; } } // end if (client.available()) } // end while (client.connected()) delay(1); // даём время браузеру для приёма наших данных client.stop(); // закрываем соединение } // end if (client) }


Важное замечание!

Если неинициализированная SD карта находится в картридере платы Ethernet Shield, то это может вызвать проблемы в работе Ethernet интерфейса. Внешне эта проблема проявляется как зависание или постоянные рестарты системы. Это связано с тем, что Ethernet чип и SD карта работают на одной шине SPI и попытки прочитать неисправную карту блокируют нормальную работу сетевого интерфейса.

Если SD карта не используется в вашем скетче, то вам нужно или извлечь ее из системы, или добавить в скетч следующий код, чтобы отключить SD карту программно:

void setup() {
    // Отключите SD карту, установив высокий уровень на 4 пине
    pinMode(4, OUTPUT);
    digitalWrite(4, HIGH);
    
    // прочий код инициализации...
}

Использование скетча


Скопируйте приведенный выше код и вставьте его в новый скетч Arduino IDE. Вы можете изменить MAC-адрес, указанный в скетче (но делать это не обязательно). Если указанный в скетче IP-адрес (10.0.0.20) не соответствует вашей подсети, то его нужно изменить соответствующим образом.

Примечание переводчика. В наших краях, указанный в скетче IP-адрес 10.0.0.20 будет скорее всего выглядеть как 192.168.1.20, где »192.168.1» — это номер вашей подсети (должен быть как и у других компьютеров в локальной сети), а »20» — это номер вашего контроллера Arduino в локальной сети (не должен быть занят другими сетевыми устройствами).

К этому моменту ваше оборудование должно быть настроено и проверено, как описано в 1-й части этого руководства. Загрузите скетч в плату Arduino, а затем откройте браузер на компьютере, подключенном к той же сети, что и ваш контроллер.

Введите IP-адрес контроллера Arduino (10.0.0.20 или ваш актуальный) в поле URL-адреса браузера на вашем компьютере. Браузер должен отобразить веб-страницу, как показано ниже.

_he0ao8uuggm9n3etljawfntg4w.jpeg

Решение проблем


Перезагрузка


Если вам не удалось подключиться к вашему Arduino веб-серверу, то попробуйте перезагрузить его, нажав кнопку Reset на плате Ethernet Shield, а затем снова повторите попытку подключения.

IP-адрес и диапазон адресов


Убедитесь, что вы установили правильный IP-адрес контроллера Arduino. Первые три цифры IP-адреса должны соответствовать вашей сети. Последний номер должен быть уникальным, то есть это должно быть единственное устройство в сети с таким номером.

Шлюз и маска подсети


Если остались проблемы с сетевым подключением, то попробуйте указать в скетче IP-адрес сетевого шлюза (роутера) и маску подсети. Вам нужно будет изменить адреса в приведенном ниже коде, чтобы они соответствовали вашей сети.

Добавьте новые параметры в скетче под MAC-адресом:

// IP-адрес шлюза
byte gateway[] = { 10, 0, 0, 1 };
// Маска подсети
byte subnet[] = { 255, 255, 0, 0 };


А затем измените в функции setup () строку инициализации Ethernet с новыми параметрами:

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

Ethernet кабель


При подключении к сети контроллера Arduino через роутер или коммутатор, используйте Ethernet кабель с «прямым» соединением проводов, а не с перекрестным.

Как работает веб-сервер


Ознакомьтесь с комментариями в вышеприведенном скетче, чтобы понять, что делают различные строки кода. Это поможет вам понять как работает веб-сервер, как он принимает запросы и как формирует и отсылает ответы на них по сети.

Запрос клиента


Когда вы обращаетесь к серверу Arduino из адресной строки браузера, он, выступая в роли клиента, отправляет на сервер запрос, подобный этому:

GET / HTTP/1.1\r\n
Host: 10.0.0.20\r\n
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: en-ZA,en-GB;q=0.8,en-US;q=0.5,en;q=0.3\r\n
Accept-Encoding: gzip, deflate\r\n
Connection: keep-alive\r\n
\r\n


Конкретное содержание запроса будет отличаться в зависимости от браузера и операционной системы, из которой он отправляется.

Символы \r\n, которые вы видите в конце каждой строки текста в запросе, являются невидимыми (непечатаемыми). \r — это символ возврата каретки, а \n — символ новой строки.

Окончание запроса клиента определяется передачей пустой строки с символами \r\n (без предшествующего текста). Появление в запросе такой строки проверяется кодом нашего скетча и, после её получения, веб-сервер фиксирует факт окончания запроса и начинает отправку ответа клиенту.

Другими словами, код скетча считывает каждый символ из запроса и определяет его окончание, когда находит пустую строку с символами \r\n.

Ответ сервера


После получения запроса веб-страницы от клиента, сервер сначала отправляет стандартный (определённый спецификациями) HTTP-ответ, а затем тело самой веб-страницы.

Ответ, отправляемый сервером Arduino, выглядит так:

HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Connection: close\r\n
\r\n


В приведенном выше ответе снова показаны невидимые символы \r\n. Функция println () в скетче автоматически добавляет символы \r\n в конец каждой строки. Пустая функция println () в конце HTTP-ответа просто отправляет пару символов \r\n без текста перед ними.

Формат приведенных выше запроса клиента и ответа веб-сервера определяется стандартом протокола HTTP (Hypertext Transfer Protocol).

Веб-страница


После того, как сервер отправил HTTP-ответ клиенту, он начинает отправку тела самой запрошенной веб-страницы, которая затем отображается в браузере.

Веб-страница состоит из текста с HTML-тегами. Сами теги не отображаются в браузере, поскольку предназначены только для разметки текста и интерпретации её браузером.

Чтобы увидеть исходный HTML код, в браузере кликните правой кнопкой мыши на веб-странице и выберите пункт контекстного меню «Просмотреть исходный код страницы».

Полный код сформированной нашим сервером страницы и её HTML-разметку можно увидеть на скриншоте ниже:

2nevuszbd_wnlfw3rc_rw7eqfoc.jpeg

HTML разметку и прочий код веб-страниц мы подробно рассмотрим в следующей части этого руководства.

От переводчика о 1-й и 2-й части


Пока я переводил эти части туториала от Starting Electronics, то постоянно боролся с желанием развернуть каждый абзац текста в более объёмное объяснение. Но видимо магия этого руководства заключается в том, что его авторам удалось отделить существенное от несущественного и оставить только самую суть.

От себя я бы порекомендовал начинающим собрать свой (первый) веб-сервер на Arduino и провести практические эксперименты со скетчем из этой статьи. Приобретённые в их ходе навыки и понимание понадобятся вам для успешного освоения следующих частей туториала.

p-u9l27ynelxi92bcmdxhu76ma8.png

© Habrahabr.ru