Первый пример иллюстрирует наиболее частый случай использования сетевых возможностей Arduino. Здесь плата выступает в роли веб-сервера. Подключившись к веб-серверу Arduino, посетители смогут не только читать аналоговые входы, но и изменять уровни на цифровых выходах, щелкая на кнопках в веб-странице (рис. 12.5).
Рис. 12.5. Интерфейс физического веб-сервера
Этот пример демонстрирует отличный способ связать плату Arduino со смартфоном или планшетным компьютером, так как для отправки запросов Arduino достаточно самого простого браузера. Скетч, реализующий этот пример (sketch_12_02_server), содержит 172 строки кода, поэтому он не будет приводиться здесь целиком, но я рекомендую открыть его в Arduino IDE и заглядывать в него в процессе чтения моих пояснений.
Первая часть скетча содержит код, стандартный для любого скетча, реализующего сетевые взаимодействия. Здесь выполняется импортирование библиотек и определение объектов EthernetServer и EthernetClient.
Далее определяются переменные, служащие разным целям:
const int numPins = 5;
int pins[] = {3, 4, 5, 6, 7};
int pinState[] = {0, 0, 0, 0, 0};
char line1[100];
char buffer[100];
Константа numPins определяет размер массивов pins и pinState. Массив pinState предназначен для хранения состояний цифровых выходов, HIGH или LOW. Функция setup настраивает все контакты, перечисленные в массиве pins, на работу в режиме цифровых выходов. Она также устанавливает соединение с сетью, как было показано в примерах ранее. Наконец, массивы символов line1 и buffer предназначены для хранения первой и последующих строк HTTP-запроса соответственно.
Далее приводится функция loop:
void loop()
{
client = server.available();
if (client)
{
if (client.connected())
{
readHeader();
if (! pageNameIs("/"))
{
client.stop();
return;
}
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Content-Type: text/html"));
client.println();
sendBody();
client.stop();
}
}
}
Функция проверяет наличие любых запросов от браузеров, ожидающих обработки. Если был получен запрос и соединение с клиентом еще не разорвано, вызывается функция readHeader. Эту функцию вы найдете ближе к концу скетча. Функция readHeader читает содержимое заголовка запроса в буфер (line1) и пропускает остальные строки запроса. Это необходимо, чтобы получить имя страницы, запрошенной браузером, и любые дополнительные параметры запроса, если они имеются.
Обратите внимание: из-за большого объема текста, который посылается скетчем в монитор последовательного порта и сеть, я использовал функцию F, сохраняющую массивы символов во флеш-памяти (см. главу 6).
После чтения заголовка вызывается функция pageNameIs (также находится ближе к концу скетча), чтобы проверить совпадение имени запрошенной страницы с именем корневой страницы (/). Если была запрошена не корневая страница, такой запрос игнорируется. Это важно, потому что многие браузеры посылают веб-серверу дополнительные запросы с целью получить значок для веб-сайта. Эти запросы не следует путать с другими запросами к серверу.
Теперь нужно сгенерировать ответ с заголовком и некоторой разметкой HTML, которую смог бы отобразить браузер. Функция sendHeader генерирует ответ «OK», чтобы показать, что запрос браузера признан допустимым. Функция sendBody, представленная далее, организована намного сложнее:
void sendBody()
{
client.println(F("
"));sendAnalogReadings();
client.println(F("
client.println(F("
setValuesFromParams();
setPinStates();
sendHTMLforPins();
client.println(F(""));
client.println(F(""));
client.println(F("