От переводчика. В сети есть много информации о работе веб-серверов на микроконтроллерах, но она плохо структурирована и не отличается системным подходом к изложению материала. Среди прочих есть в интернете один замечательный, можно сказать культовый, туториал (руководство) по работе веб-серверов на 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 картами)

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

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




Перед началом работы нужно убедиться в общей работоспособности вашей системы (здесь предполагается, что вы обладаете начальными знаниями работы с 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 <SPI.h>
#include <Ethernet.h>

// 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("<!DOCTYPE html>");
                    client.println("<html>");
                    client.println("<head>");
                    client.println("<title>Arduino Web Page</title>");
                    client.println("</head>");
                    client.println("<body>");
                    client.println("<h1>Hello from Arduino!</h1>");
                    client.println("<p>A web page from the Arduino server</p>");
                    client.println("</body>");
                    client.println("</html>");
                    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-адреса браузера на вашем компьютере. Браузер должен отобразить веб-страницу, как показано ниже.



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


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


Если вам не удалось подключиться к вашему 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-разметку можно увидеть на скриншоте ниже:



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

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


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

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


Комментарии (20)


  1. sav13
    12.01.2023 17:18
    +1

    Идеальная платформа для таких поделок ESP32
    Ничего подключать не нужно


    1. smart_alex Автор
      12.01.2023 17:35
      +1

      От себя добавлю: это отлично работает даже на 8-битной Mega2560 + W5100, не говоря уже о более крутом железе.


      1. sav13
        12.01.2023 17:38
        +1

        Я не спорю, что работает
        Просто в статье зачем то много времени уделено конфликту Ethernet шилда м SD-карты, вместо того чтобы больше времени уделить собственно работе веб-сервера


        1. smart_alex Автор
          12.01.2023 18:07
          +2

          Ну, это автор так написал, я тут выступил только как переводчик.

          Вообще, это моя тема и в процессе перевода мне всё время хотелось что-то добавить, но я наступил на горло своему креативу и старался строго придерживаться оригинала.


    1. SanekK
      12.01.2023 20:39

      Оригинальная статья 10 летней давности, ESP еще не изобрели


      1. smart_alex Автор
        12.01.2023 20:50
        +1

        Кстати, 14 января будет юбилей — туториалу ровно 10 лет.

        Но сам материал нисколько не устарел — он описывает принципы по которым это работает на любых платформах. Например, у меня одни и те же куски кода (HTML, CSS, Javascript) работают и на микроконтроллерах и на моём сайте в интернете.


        1. jmdorian
          13.01.2023 11:47

          Вероятно потому что HTML, CSS и JavaScript выполняются в браузере, а не на сайте или микроконтроллере.


  1. Mike-M
    13.01.2023 14:55
    -2

    Пока я переводил эти части туториала от Starting Electronics, то постоянно боролся с желанием развернуть каждый абзац текста в более объёмное объяснение.
    Приобретённые в их ходе навыки
    Очень хорошо, что Вам удалось побороть желание «развернуть каждый абзац».


    1. Mike-M
      13.01.2023 16:04

      Вниманию желающих поставить минус: через Ctrl-Enter я уже сообщал.
      И ещё. За статью я проголосовал положительно.
      Если же минус прилетел от автора, то… лучше бы Вы ошибки исправили.


      1. smart_alex Автор
        13.01.2023 17:09

        Mike-M, за плюс спасибо. А по поводу ошибок - мы же с вами уже обсуждали, что 95% ваших исправлений носят субъективный и крайне спорный характер.

        А попытки править авторский стиль вообще неуместны (это не говоря о куче ляпов в ваших собственных текстах).


        1. Mike-M
          13.01.2023 19:08
          -2

          В моих статьях нет «кучи ляпов». Я вам это наглядно доказал. На моё предложение привести дополнительные примеры вы ответили молчанием.

          «Приобретённые в их ходе навыки» — это авторский стиль?
          Или может конструкция «Пока…, то ...» — это авторский стиль?
          Нет, это явные синтаксические ошибки. На русском языке так не говорят.

          На 14 замечаний в вашей статье приходится четыре ошибки:

          1. В этой статье я рассажу — расскажу.
          2. и рассказал о его схемотехнике, сегодня я попытаюсь осветить ещё один важный аспект — вместо запятой должна быть точка и новое предложение.
          3. резисторы R21-R24 — диапазон значений задается через тире, а не дефис.
          4. можно делать всё, что угодно — лишняя запятая.
          Четыре ошибки — это не 5%, как вы утверждаете, а более 25%.

          Но даже если ошибок всего 5%, это не значит, что их не нужно исправлять.


          1. smart_alex Автор
            13.01.2023 19:19
            -1

            Mike-M, пожалуйста, не нужно превращать комменты к статье о веб-серверах в цирк и ярмарку вашего тщеславия.

            Если вы нашли какие-то ошибки, то просто пришлите мне их в личку — я их посмотрю и, если сочту справедливыми, то исправлю и поблагодарю вас за бдительность.


            1. Mike-M
              13.01.2023 19:50

              Не ожидал, что человеку с ником smart нужно повторять дважды.
              Повторяю: в личку я вам уже сообщал, но прошло более трех месяцев, а ошибки до сих пор не исправлены.

              И тщеславие здесь ни при чем. Это вы зарабатываете на корпоративном блоге. Я с ваших ошибок не имею ни копейки.

              Тоже против никчемных обсуждений. Просто впредь пишите грамотнее — меньше минусов будет. А значит, выше ваш заработок.

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


              1. smart_alex Автор
                13.01.2023 20:19

                Это же надо, зайти в комменты обучающей статьи (ни слова не сказав по сути темы) и так всё изгадить...


                1. Mike-M
                  13.01.2023 21:07

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

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

                  Я могу бесконечно долго отвечать на ваши неумелые попытки перейти на личности. Это вам надо статьи писать и деньги зарабатывать, а мне торопиться некуда )


                  1. smart_alex Автор
                    13.01.2023 21:22

                    Mike-M, я с вами общался и отвечал на ваши вопросы, как отвечаю любому обратившемуся ко мне. В личной переписке и в этих комментах вы достаточно себя показали — я больше не вижу смысла терять время на общение с вами.


                    1. Mike-M
                      14.01.2023 12:00

                      Забавно, как это вы отвечали на мои вопросы, если я их не задавал ))

                      Рад, что вы наконец-то приняли решение прекратить бесполезный флуд.

                      Главное — чтобы в ваших будущих публикациях не встречалось нелепостей вроде «Приобретённые в их ходе навыки», а также других ошибок правописания, прикрытых «авторским стилем».


  1. Chupakabra303
    14.01.2023 12:06

    В качестве прикола подключал Arduino по USB Serial к роутеру Mikrotik. У последнего можно прокинуть tcp порт на serial порт Arduino (raw). Mikrotik выступал в роли типа CGI шлюза )

    Под Ардуино написал обработчик GET запроса, который по Serial в него приходил, когда я браузером запрашивал TCP порт микротика. В ответ Ардуино выдавало "web страничку", которая благополочно выплевывалась микротиком в браузер. Такой вот занятный web сервер. Хотел даже статью написать, но ума не приложу кому это может понадобиться )


  1. D_dMer
    14.01.2023 12:08

    Ждем продолжения


    1. smart_alex Автор
      14.01.2023 12:40

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