[Перевод] Starting Electronics: руководство по веб-серверам на Arduino. Часть 1
От переводчика. В сети есть много информации о работе веб-серверов на микроконтроллерах, но она плохо структурирована и не отличается системным подходом к изложению материала. Среди прочих есть в интернете один замечательный, можно сказать культовый, туториал (руководство) по работе веб-серверов на 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
#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-адреса браузера на вашем компьютере. Браузер должен отобразить веб-страницу, как показано ниже.
❯ Решение проблем
Перезагрузка
Если вам не удалось подключиться к вашему 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 и провести практические эксперименты со скетчем из этой статьи. Приобретённые в их ходе навыки и понимание понадобятся вам для успешного освоения следующих частей туториала.