Raspberry Pi Pico: веб-сервер для управления выходами (Arduino IDE)

Перевод статьи Raspberry Pi Pico: Web Server to Control Outputs (Arduino IDE) — Rui Santos & Sara Santos, Random Nerd Tutorials.
Это руководство показывает, как создать простой веб-сервер на Raspberry Pi Pico W, запрограммированном в Arduino IDE, для управления выходами. Мы воспользуемся библиотекой ESPAsyncWebServer, чтобы поднять асинхронный веб-сервер.
Учтите: руководство подходит только для Raspberry Pi Pico W и Raspberry Pi Pico 2W — моделей с поддержкой Wi-Fi.
Raspberry Pi Pico и Arduino IDE#
Вам нужно установить поддержку плат Raspberry Pi Pico в Arduino IDE и уметь заливать код на плату. Если вы этого ещё не делали, сначала разберитесь с настройкой среды под Pico и Pico 2.
Установка библиотек#
Чтобы создать асинхронный веб-сервер на Raspberry Pi Pico в Arduino IDE, мы используем библиотеку ESPAsyncWebServer — она совместима с ESP32, ESP8266, а также с RPi Pico (RP2040 и RP2350) и другими родственными платами. Для Pico дополнительно нужна библиотека RPAsyncTCP.
Итого в Arduino IDE нужно установить:
- ESPAsyncWebServer от ESP32Async
- RPAsyncTCP от ayushsharma82
Порядок установки:
Откройте Sketch → Include Library → Manage Libraries или щёлкните иконку менеджера библиотек на левой панели.
Найдите ESPAsyncWebServer и установите библиотеку ESPAsyncWebServer от ESP32Async.

Установка ESPAsyncWebServer в Arduino IDE
- Найдите RPAsyncTCP и установите библиотеку RPAsyncTCP от Ayush Sharma.

Установка RPAsyncTCP
Обзор проекта#
В этом примере мы создадим простую веб-страницу с двумя кнопками для управления одним из выводов GPIO на Raspberry Pi Pico.

Как устроено управление выходом через веб-сервер
Когда вы открываете IP-адрес Raspberry Pi Pico в браузере, вы делаете запрос к серверу (то есть к Pico) по корневому URL
/.Pico отвечает HTML-текстом, из которого строится простая веб-страница.
На странице две кнопки — включить и выключить светодиод, подключённый к одному из выводов GPIO. При нажатии выполняется новый запрос к следующим адресам:
- кнопка «LED on» — запрос к
/lighton? - кнопка «LED off» — запрос к
/lightoff?
- Мы используем HTML-шаблон, который подставляет текущее состояние светодиода на страницу сразу после запроса. Иными словами, после запроса плата отправляет HTML-страницу с правильным состоянием вывода.
Замечание: состояние при этом фактически не проверяется — оно просто меняется в соответствии с сделанным запросом.
Схема подключения#
В этом примере мы управляем светодиодом, подключённым к GPIO 2 на Raspberry Pi Pico. Можно использовать любой другой подходящий вывод, если соответственно поправить код.

Светодиод на GPIO 2 через резистор 220 Ом
Что понадобится:
- Raspberry Pi Pico W / Raspberry Pi Pico 2W
- 1 светодиод
- 1 резистор на 220 Ом (или близкого номинала)
- макетная плата
- соединительные провода
Код: веб-сервер на Raspberry Pi Pico для управления выходами#
Следующий код поднимает веб-сервер, отдающий показанную выше страницу.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Полное описание проекта: https://RandomNerdTutorials.com/raspberry-pi-pico-web-server-outputs-arduino/
*********/
// Подключаем нужные библиотеки
#include <WiFi.h>
#include <RPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
// Замените на данные своей сети
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Светодиод, которым управляем
#define LED_PIN 2
// Текущее состояние светодиода (для отображения на странице)
String ledState = "OFF";
// Создаём объект AsyncWebServer на порту 80
AsyncWebServer server(80);
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>Pico Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
body {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
h1 { color: #333; }
h2 { color: #666; }
form { margin: 10px 0; }
.button {
background-color: #4CAF50;
border: none;
color: white;
padding: 10px 20px;
text-decoration: none;
font-size: 20px;
margin: 2px;
cursor: pointer;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
transition: background-color 0.3s, box-shadow 0.3s;
}
.button:hover {
background-color: #45a049;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}
.button2 { background-color: #f44336; }
.button2:hover { background-color: #da190b; }
.state {
font-size: 1.4em;
margin: 20px 0;
color: #444;
}
</style>
</head>
<body>
<h1>Raspberry Pi Pico Web Server</h1>
<h2>Led Control</h2>
<p class="state">LED State: %STATE%</p>
<form action="./lighton">
<input type="submit" value="LED on" class="button" />
</form>
<form action="./lightoff">
<input type="submit" value="LED off" class="button button2" />
</form>
</body>
</html>
)rawliteral";
// Функция-обработчик шаблона
String processor(const String& var){
if(var == "STATE"){
return ledState;
}
return String();
}
void setup(){
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Подключаемся к Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
// Печатаем локальный IP-адрес Pico
Serial.println(WiFi.localIP());
// Маршрут для корневой страницы /
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/html", index_html, processor);
});
// Маршрут для включения светодиода
server.on("/lighton", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(LED_PIN, HIGH);
ledState = "ON";
request->send(200, "text/html", index_html, processor);
});
// Маршрут для выключения светодиода
server.on("/lightoff", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(LED_PIN, LOW);
ledState = "OFF";
request->send(200, "text/html", index_html, processor);
});
// Запускаем сервер
server.begin();
}
void loop() {
}
Не забудьте вписать SSID и пароль своей сети в эти строки, после чего можно заливать код на плату.
// Замените на данные своей сети
const char* ssid = "";
const char* password = "";
Как работает код#
Разберём код по частям.
Подключение библиотек#
Сначала подключаем библиотеки, нужные для подключения Pico к сети и создания веб-сервера: WiFi, RPAsyncTCP и ESPAsyncWebServer.
// Подключаем нужные библиотеки
#include <WiFi.h>
#include <RPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
Данные сети#
Впишите в эти строки данные своей сети, чтобы Pico мог к ней подключиться.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Вывод светодиода#
Мы управляем светодиодом на GPIO 2. Можно взять любой другой вывод — достаточно поправить эту строку.
#define LED_PIN 2
Состояние светодиода#
Создаём глобальную переменную, чтобы отслеживать состояние светодиода. При запуске программы он выключен.
String ledState = "OFF";
AsyncWebServer на порту 80#
Создаём объект AsyncWebServer с именем server на порту 80.
AsyncWebServer server(80);
HTML-текст#
Переменная index_html хранит HTML, из которого строится страница, и представляет собой «сырой» строковый литерал: он размещается между R"rawliteral( и )rawliteral". Это позволяет писать строку в несколько строк без экранирующих символов вроде \n и кавычек в каждой строке — очень удобно, чтобы вставить HTML как есть. Переменная хранится во флеш-памяти (PROGMEM).
Секция между тегами <style></style> — это CSS, отвечающий за внешний вид страницы. Дальше идут заголовок и подзаголовок, которые можно поменять на любые:
<h1>Raspberry Pi Pico Web Server</h1>
<h2>Led Control</h2>
Следующий абзац показывает текущее состояние светодиода. %STATE% — это плейсхолдер для фактического значения (переменной ledState). Перед отправкой страницы клиенту функция processor() подставит вместо него правильное значение.
<p class="state">LED State: %STATE%</p>
А эти строки создают кнопки включения и выключения светодиода:
<form action="./lighton">
<input type="submit" value="LED on" class="button" />
</form>
<form action="./lightoff">
<input type="submit" value="LED off" class="button button2" />
</form>
Функция processor()#
Функция processor() ищет плейсхолдеры и заменяет их заданными значениями. В нашем случае мы ищем плейсхолдер STATE и подставляем текущее состояние светодиода из переменной ledState.
String processor(const String& var){
if(var == "STATE"){
return ledState;
}
return String();
}
Функция setup()#
В setup() инициализируем монитор порта на скорости 115200, настраиваем вывод светодиода как выход и устанавливаем его в LOW. Затем подключаем Pico к локальной сети с указанными ранее данными.
// Подключаемся к Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Печатаем IP-адрес Pico — позже он понадобится для доступа к странице.
Serial.println(WiFi.localIP());
Обработка запросов#
Следующие строки обрабатывают запросы к Pico по корневому URL / — это происходит, когда вы вводите IP-адрес платы в браузере. Получив такой запрос, Pico отправляет клиенту текст из переменной index_html.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/html", index_html, processor);
});
Параметры функции send():
200— HTTP-код, означающий, что запрос принят;text/html— мы отправляем страницу в формате HTML;index_html— содержимое страницы;processor— функция-обработчик, которая найдёт плейсхолдеры и подставит нужные значения.
При запросе на /lighton или /lightoff плата включает или выключает светодиод функцией digitalWrite() и обновляет переменную ledState. После этого страница отправляется клиенту — обратите внимание, что мы снова передаём функцию processor четвёртым параметром, чтобы страница ушла с правильным состоянием вывода.
// Маршрут для включения светодиода
server.on("/lighton", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(LED_PIN, HIGH);
ledState = "ON";
request->send(200, "text/html", index_html, processor);
});
// Маршрут для выключения светодиода
server.on("/lightoff", HTTP_GET, [](AsyncWebServerRequest *request){
digitalWrite(LED_PIN, LOW);
ledState = "OFF";
request->send(200, "text/html", index_html, processor);
});
Наконец, запускаем веб-сервер.
server.begin();
Функция loop()#
Поскольку веб-сервер асинхронный (функция server.on() срабатывает при получении запроса), в loop() ничего добавлять не нужно. При желании вы можете дописать туда код, необходимый вашему проекту.
void loop() {
}
Заливка кода на Pico#
Чтобы залить код на Raspberry Pi Pico W, плата должна быть в режиме загрузчика. Если сейчас на ней стоит прошивка MicroPython, переведите её в этот режим вручную: подключите Pico к компьютеру, удерживая кнопку BOOTSEL. Откроется окно нового съёмного диска — его можно проигнорировать и закрыть. При последующих загрузках из Arduino IDE плата должна уходить в режим загрузчика автоматически, без нажатия BOOTSEL.
Теперь откройте верхнее выпадающее меню и выберите Select other board and port…. В качестве платы выберите Raspberry Pi Pico W или Raspberry Pi Pico 2W — в зависимости от того, что у вас. COM-порт может не появиться при первой загрузке, поэтому отметьте галочку Show all ports и выберите пункт UF2 Board / UF2 Devices. После этого можно заливать код — должно появиться сообщение об успехе.
Монитор порта#
Теперь нужно узнать IP-адрес Pico — он печатается в монитор порта. Откройте монитор на скорости 115200. Затем отключите плату и подключите её обратно: через несколько секунд она установит связь с монитором и покажет свой IP-адрес. У автора это 192.168.1.83.

IP-адрес Pico в мониторе порта
Открываем веб-сервер#
Откройте окно браузера и введите IP-адрес Pico. Плата отдаст содержимое переменной index_html, и вы увидите такую страницу.

Страница с кнопками управления светодиодом
Нажимайте кнопки, чтобы управлять светодиодом на GPIO 2.

Светодиод выключен

Светодиод включён
Подводя итог#
В этом руководстве вы научились создавать веб-сервер на Raspberry Pi Pico, запрограммированном в Arduino IDE, с помощью библиотеки ESPAsyncWebServer — и управлять через него выводом GPIO.
Эту же библиотеку мы обычно используем для веб-серверов на ESP32 и ESP8266. Методы и функции работы с веб-сервером на платах ESP и на RPi Pico одинаковы.