Программируем Arduino. Основы работы со скетчами - Страница 39
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("
Output Pins
"));client.println(F("
"));client.println(F(""));
}
Она выводит простой макет HTML-страницы, опираясь на множество вспомогательных функций, которые были созданы, чтобы разбить код на более управляемые фрагменты. Первая из них — sendAnalogReadings:
void sendAnalogReadings()
{
client.println(F("
Analog Inputs
"));client.println(F("
| A")); client.print(i); client.print(F(" | ")); client.print((float) reading / 205.0); client.println(F(" V |
}
Она выполняет обход всех аналоговых входов, читает их значения и выводит HTML-таблицу с прочитанными значениями в вольтах.
Возможно, вы обратили внимание на то, что sendBody вызывает также функции setValuesFromParams и setPinStates. Первая записывает в массив pinStates состояния HIGH или LOW цифровых выходов, извлекая их из параметров запроса с помощью функции valueOfParam:
int valueOfParam(char param)
{
for (int i = 0; i < strlen(line1); i++)
{
if (line1[i] == param && line1[i+1] == '=')
{
return (line1[i+2] — '0');
}
}
return 0;
}
Функция valueOfParam ожидает получения параметра запроса в виде единственной цифры. Как выглядят эти параметры, можно увидеть, если запустить пример, открыть страницу в браузере и щелкнуть на кнопке Update (Обновить). Адрес URL в адресной строке браузера изменится, и в нем появятся параметры, как показано далее:
192.168.1.10/?0=1&1=0&2=0&3=0&4=0
Список параметров начинается после символа ?. Параметры имеют вид X=Y и отделяются друг от друга символом &. Слева от знака = находится имя параметра (в данном случае цифры от 0 до 4), а справа — значения (в данном примере 1 означает «включено», а 0 — «выключено»). Для простоты параметры в этом примере могут иметь только односимвольные значения. Функция setPinStates устанавливает состояние цифровых выходов в соответствии со значениями элементов массива pinStates.
А теперь вернемся к функции sendBody. Вслед за таблицей со значениями аналоговых входов нужно послать разметку HTML с коллекцией раскрывающихся списков, соответствующих цифровым выходам. В каждом списке нужно выбрать пункт On (Включено) или Off (Выключено) в зависимости от текущего состояния цифрового выхода. Для этого нужно добавить текст «selected» в значение, соответствующее состоянию данного выхода в массиве pinStates.
Код разметки HTML для цифровых выходов заключается в форму, чтобы посетитель мог изменить значения в форме и, щелкнув на кнопке Update (Обновить), сгенерировать новый запрос к этой странице с соответствующими параметрами для установки цифровых выходов. А теперь посмотрим, как выглядит разметка HTML-страницы:
| A0 | 0.58 V |
| A1 | 0.63 V |
| A2 | 0.60 V |
| A3 | 0.65 V |
| A4 | 0.60 V |
Output Pins
Увидеть этот код можно, воспользовавшись функцией View Source (Исходный код страницы) в браузере.
Использование веб-службы JSON
Для иллюстрации возможности отправки веб-запросов из платы Arduino внешним веб-сайтам я воспользуюсь веб-службой, возвращающей данные о погоде в определенном географическом пункте. Плата будет выводить краткое описание погоды в монитор последовательного порта (рис. 12.6). Описываемый скетч посылает запрос один раз в момент запуска, но его нетрудно изменить, чтобы он запрашивал погоду каждый час и выводил результаты на двухстрочный жидкокристаллический дисплей.