От переводчика. В сети есть много информации о работе веб-серверов на микроконтроллерах, но она плохо структурирована и не отличается системным подходом к изложению материала. Среди прочих есть в интернете один замечательный, можно сказать культовый, туториал (руководство) по работе веб-серверов на 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)
Mike-M
13.01.2023 14:55-2Пока я переводил эти части туториала от Starting Electronics, то постоянно боролся с желанием развернуть каждый абзац текста в более объёмное объяснение.
Очень хорошо, что Вам удалось побороть желание «развернуть каждый абзац».
Приобретённые в их ходе навыкиMike-M
13.01.2023 16:04Вниманию желающих поставить минус: через Ctrl-Enter я уже сообщал.
И ещё. За статью я проголосовал положительно.
Если же минус прилетел от автора, то… лучше бы Вы ошибки исправили.smart_alex Автор
13.01.2023 17:09Mike-M, за плюс спасибо. А по поводу ошибок - мы же с вами уже обсуждали, что 95% ваших исправлений носят субъективный и крайне спорный характер.
А попытки править авторский стиль вообще неуместны (это не говоря о куче ляпов в ваших собственных текстах).
Mike-M
13.01.2023 19:08-2В моих статьях нет «кучи ляпов». Я вам это наглядно доказал. На моё предложение привести дополнительные примеры вы ответили молчанием.
«Приобретённые в их ходе навыки» — это авторский стиль?
Или может конструкция «Пока…, то ...» — это авторский стиль?
Нет, это явные синтаксические ошибки. На русском языке так не говорят.
На 14 замечаний в вашей статье приходится четыре ошибки:- В этой статье я рассажу — расскажу.
- и рассказал о его схемотехнике, сегодня я попытаюсь осветить ещё один важный аспект — вместо запятой должна быть точка и новое предложение.
- резисторы R21-R24 — диапазон значений задается через тире, а не дефис.
- можно делать всё, что угодно — лишняя запятая.
Но даже если ошибок всего 5%, это не значит, что их не нужно исправлять.smart_alex Автор
13.01.2023 19:19-1Mike-M, пожалуйста, не нужно превращать комменты к статье о веб-серверах в цирк и ярмарку вашего тщеславия.
Если вы нашли какие-то ошибки, то просто пришлите мне их в личку — я их посмотрю и, если сочту справедливыми, то исправлю и поблагодарю вас за бдительность.
Mike-M
13.01.2023 19:50Не ожидал, что человеку с ником smart нужно повторять дважды.
Повторяю: в личку я вам уже сообщал, но прошло более трех месяцев, а ошибки до сих пор не исправлены.
И тщеславие здесь ни при чем. Это вы зарабатываете на корпоративном блоге. Я с ваших ошибок не имею ни копейки.
Тоже против никчемных обсуждений. Просто впредь пишите грамотнее — меньше минусов будет. А значит, выше ваш заработок.
Самый простой вариант — перед публикацией статьи внимательно перечитайте её свежим взглядом.smart_alex Автор
13.01.2023 20:19Это же надо, зайти в комменты обучающей статьи (ни слова не сказав по сути темы) и так всё изгадить...
Mike-M
13.01.2023 21:07Это же надо, так долго заниматься пустословием, вместо того чтобы за пару минут исправить ошибки… Или просто промолчать на худой конец, раз уж виноват…
По сути темы я действительно ничего не сказал — вместо этого поставил плюс статье, причем двойной.
Я могу бесконечно долго отвечать на ваши неумелые попытки перейти на личности. Это вам надо статьи писать и деньги зарабатывать, а мне торопиться некуда )smart_alex Автор
13.01.2023 21:22Mike-M, я с вами общался и отвечал на ваши вопросы, как отвечаю любому обратившемуся ко мне. В личной переписке и в этих комментах вы достаточно себя показали — я больше не вижу смысла терять время на общение с вами.
Mike-M
14.01.2023 12:00Забавно, как это вы отвечали на мои вопросы, если я их не задавал ))
Рад, что вы наконец-то приняли решение прекратить бесполезный флуд.
Главное — чтобы в ваших будущих публикациях не встречалось нелепостей вроде «Приобретённые в их ходе навыки», а также других ошибок правописания, прикрытых «авторским стилем».
Chupakabra303
14.01.2023 12:06В качестве прикола подключал Arduino по USB Serial к роутеру Mikrotik. У последнего можно прокинуть tcp порт на serial порт Arduino (raw). Mikrotik выступал в роли типа CGI шлюза )
Под Ардуино написал обработчик GET запроса, который по Serial в него приходил, когда я браузером запрашивал TCP порт микротика. В ответ Ардуино выдавало "web страничку", которая благополочно выплевывалась микротиком в браузер. Такой вот занятный web сервер. Хотел даже статью написать, но ума не приложу кому это может понадобиться )
D_dMer
14.01.2023 12:08Ждем продолжения
smart_alex Автор
14.01.2023 12:40Продолжение будет, а пока можно поэкспериментировать со скетчем из статьи - тут очень важна практика.
sav13
Идеальная платформа для таких поделок ESP32
Ничего подключать не нужно
smart_alex Автор
От себя добавлю: это отлично работает даже на 8-битной Mega2560 + W5100, не говоря уже о более крутом железе.
sav13
Я не спорю, что работает
Просто в статье зачем то много времени уделено конфликту Ethernet шилда м SD-карты, вместо того чтобы больше времени уделить собственно работе веб-сервера
smart_alex Автор
Ну, это автор так написал, я тут выступил только как переводчик.
Вообще, это моя тема и в процессе перевода мне всё время хотелось что-то добавить, но я наступил на горло своему креативу и старался строго придерживаться оригинала.
SanekK
Оригинальная статья 10 летней давности, ESP еще не изобрели
smart_alex Автор
Кстати, 14 января будет юбилей — туториалу ровно 10 лет.
Но сам материал нисколько не устарел — он описывает принципы по которым это работает на любых платформах. Например, у меня одни и те же куски кода (HTML, CSS, Javascript) работают и на микроконтроллерах и на моём сайте в интернете.
jmdorian
Вероятно потому что HTML, CSS и JavaScript выполняются в браузере, а не на сайте или микроконтроллере.