Глава 1: Начало работы

Отлично! Мы начинаем Главу 1 нашего справочника по GUI для Raspberry Pi Zero 2 W. Эта глава посвящена началу работы и включает в себя пример кода для управления светодиодом с помощью графического интерфейса GTK.

Введение

В этой главе мы создадим простейший графический интерфейс (GUI) на Raspberry Pi Zero 2 W с использованием:

  • Библиотеки GTK — для построения самого графического интерфейса.

  • Библиотеки libgpiod — для взаимодействия с контактами GPIO (General Purpose Input/Output) вашего Raspberry Pi.

В результате мы получим окно с кнопкой, которая будет включать и выключать светодиод, подключенный к пину GPIO17 (это пин 11 на физической раскладке контактов Raspberry Pi).

Схема подключения

Для работы примера вам потребуется подключить светодиод к Raspberry Pi. Ниже представлена схема, которая покажет, как это сделать:

Схема подключения светодиода

Пример кода: Управление светодиодом

Этот C-код создает простое GTK-окно с кнопкой для управления светодиодом через GPIO.

#include <gtk/gtk.h> // Основная библиотека для создания GUI-приложений на GTK
#include <gpiod.h>   // Библиотека для работы с GPIO на Linux-системах
#include <stdio.h>   // Стандартная библиотека ввода/вывода для функций вроде perror

// Определяем константы для удобства
#define CONSUMER "GUI_for_Zero2W" // Имя, под которым ваше приложение будет "запрашивать" линию GPIO
#define CHIPNAME "gpiochip0"      // Имя GPIO-контроллера на Raspberry Pi (обычно 'gpiochip0')
#define LED_LINE 17               // Номер GPIO-пина, к которому подключен светодиод (GPIO17)

// Структура для хранения всех необходимых виджетов и данных
// Передаем указатель на эту структуру в колбэк-функцию, чтобы иметь доступ к данным
struct app_widgets {
    GtkWidget *button;          // Указатель на объект кнопки GTK
    struct gpiod_line *line;    // Указатель на объект конкретной линии GPIO
    int led_on;                 // Переменная для отслеживания текущего состояния светодиода (0 - выключен, 1 - включен)
};

// Функция, которая будет вызываться при нажатии на кнопку
static void toggle_led(GtkButton *button, gpointer user_data) {
    // Приводим обобщенный указатель user_data к нашему типу struct app_widgets
    struct app_widgets *widgets = (struct app_widgets *)user_data;

    // Инвертируем текущее состояние светодиода
    widgets->led_on = !widgets->led_on;
    // Устанавливаем значение на линии GPIO: 1 (HIGH) для включения, 0 (LOW) для выключения
    gpiod_line_set_value(widgets->line, widgets->led_on);

    // Обновляем текст на кнопке в зависимости от нового состояния светодиода
    gtk_button_set_label(button, widgets->led_on ? "Выключить LED" : "Включить LED");
}

// Главная функция программы
int main(int argc, char *argv[]) {
    // Инициализируем GTK. Это необходимо сделать в самом начале любого GTK-приложения.
    gtk_init(&argc, &argv);

    struct gpiod_chip *chip; // Указатель на объект GPIO-чипа
    struct gpiod_line *line; // Указатель на объект конкретной линии GPIO

    // Открываем GPIO-чип по его имени (gpiochip0)
    chip = gpiod_chip_open_by_name(CHIPNAME);
    if (!chip) {
        perror("Ошибка при открытии gpiochip"); // Выводим ошибку, если не удалось открыть чип
        return 1; // Завершаем программу с кодом ошибки
    }

    // Получаем конкретную линию GPIO по её номеру (LED_LINE = 17)
    line = gpiod_chip_get_line(chip, LED_LINE);
    if (!line) {
        perror("Ошибка при получении линии GPIO"); // Выводим ошибку
        gpiod_chip_close(chip); // Не забудьте закрыть чип, если произошла ошибка
        return 1;
    }

    // Запрашиваем линию GPIO как выходную (output) с начальным значением 0 (выключено)
    if (gpiod_line_request_output(line, CONSUMER, 0) < 0) {
        perror("Ошибка при запросе линии для вывода"); // Выводим ошибку
        gpiod_chip_close(chip); // Закрываем чип
        return 1;
    }

    // Инициализируем нашу структуру app_widgets
    struct app_widgets widgets = {0}; // Обнуляем всю структуру
    widgets.line = line;             // Сохраняем указатель на линию GPIO
    widgets.led_on = 0;              // Изначально светодиод выключен

    // Создаем главное окно приложения
    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    // Устанавливаем заголовок окна
    gtk_window_set_title(GTK_WINDOW(window), "LED Toggle");
    // Устанавливаем размер окна по умолчанию
    gtk_window_set_default_size(GTK_WINDOW(window), 200, 100);
    // Подключаем сигнал "destroy" (закрытие окна) к функции gtk_main_quit,
    // чтобы приложение завершалось при закрытии окна
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    // Создаем кнопку с начальным текстом
    widgets.button = gtk_button_new_with_label("Включить LED");
    // Подключаем сигнал "clicked" (нажатие) кнопки к нашей функции toggle_led
    // Передаем в качестве user_data адрес нашей структуры widgets
    g_signal_connect(widgets.button, "clicked", G_CALLBACK(toggle_led), &widgets);
    // Добавляем кнопку в окно
    gtk_container_add(GTK_CONTAINER(window), widgets.button);

    // Показываем все виджеты в окне (окно и кнопка)
    gtk_widget_show_all(window);

    // Запускаем основной цикл GTK. Здесь приложение будет ожидать событий
    // (нажатий кнопок, закрытия окна и т.д.) до вызова gtk_main_quit.
    gtk_main();

    // --- Блок очистки ресурсов после выхода из gtk_main ---

    // Убедимся, что светодиод выключен при завершении программы
    gpiod_line_set_value(line, 0);
    // Освобождаем линию GPIO
    gpiod_line_release(line);
    // Закрываем GPIO-чип
    gpiod_chip_close(chip);

    return 0; // Возвращаем 0, сигнализируя об успешном выполнении программы
}

Компиляция и запуск

Чтобы скомпилировать и запустить это приложение на вашем Raspberry Pi Zero 2 W, выполните следующие шаги в терминале:

  1. Установите необходимые библиотеки: Перед компиляцией убедитесь, что у вас установлены библиотеки разработки для GTK3 и libgpiod.

    sudo apt update                 # Обновляем список пакетов
    sudo apt install libgtk-3-dev libgpiod-dev # Устанавливаем библиотеки разработки
    
  2. Сохраните код: Сохраните приведенный выше C-код в файл с именем, например, led_gui.c.

  3. Скомпилируйте программу: Используйте компилятор gcc для создания исполняемого файла. Флаги $(pkg-config --cflags --libs gtk+-3.0 libgpiod) автоматически добавят все необходимые пути к заголовочным файлам и библиотекам GTK3 и libgpiod.

    gcc led_gui.c -o led_gui $(pkg-config --cflags --libs gtk+-3.0 libgpiod) -Wall -Wextra
    
    • gcc: компилятор C.

    • led_gui.c: ваш исходный файл.

    • -o led_gui: указывает, что выходной исполняемый файл будет называться led_gui.

    • $(pkg-config --cflags --libs gtk+-3.0 libgpiod): эта команда динамически предоставляет компилятору флаги, необходимые для включения заголовочных файлов (--cflags) и линковки с библиотеками (--libs) GTK3 и libgpiod.

    • -Wall -Wextra: включают все стандартные и дополнительные предупреждения компилятора, что помогает выявлять потенциальные ошибки.

  4. Запустите программу: После успешной компиляции вы можете запустить ваше приложение.

    ./led_gui
    

    Если все настроено правильно, на рабочем столе Raspberry Pi должно появиться небольшое окно с кнопкой!

Подключение светодиода

Прежде чем запускать программу, убедитесь, что светодиод подключен правильно. Не забудьте использовать резистор, чтобы ограничить ток через светодиод и предотвратить его (и ваш Raspberry Pi) повреждение!

  • Длинная ножка светодиода (анод) → подключается к одному концу резистора (например, 220 Ом).

  • Другой конец резистора → подключается к GPIO17 (пин 11) на Raspberry Pi.

  • Короткая ножка светодиода (катод) → подключается к любому пину GND (земля) на Raspberry Pi.

Физическая схема на макетной плате

Для наглядности, вот как это может выглядеть на макетной плате:

Подключение на макетной плате

Создание ярлыка на рабочем столе

Чтобы ваше приложение было удобно запускать, вы можете создать ярлык на рабочем столе или в меню приложений.

  1. Создайте файл ``.desktop``: Сохраните следующий текст в файл с именем led_gui.desktop. Убедитесь, что пути Exec и Icon соответствуют фактическому расположению вашего исполняемого файла и иконки.

    [Desktop Entry]
    Name=LED Toggle                     # Имя, которое будет отображаться для ярлыка
    Comment=Управление светодиодом через GTK GUI # Краткое описание
    Exec=/home/pi/GUI4RPiZ2W/1/led_gui  # Полный путь к вашему исполняемому файлу
    Icon=/home/pi/GUI4RPiZ2W/1/icon.png # Полный путь к файлу иконки
    Terminal=false                      # Устанавливаем false, так как это графическое приложение
    Type=Application                    # Указывает, что это приложение
    Categories=Utility;                 # Категория, в которой ярлык будет отображаться в меню
    
    • Важно: Замените /home/pi/GUI4RPiZ2W/1/ на актуальный путь, где вы сохранили led_gui и icon.png.

  2. Сделайте файл исполняемым: Дайте файлу .desktop права на выполнение.

    chmod +x led_gui.desktop
    
  3. Переместите ярлык в меню приложений: Скопируйте файл .desktop в папку, где хранятся ярлыки приложений.

    cp led_gui.desktop ~/.local/share/applications/
    

    После этого ваш ярлык «LED Toggle» должен появиться в меню «Программирование» или «Утилиты» (в зависимости от вашей версии Raspberry Pi OS) или в общем списке приложений.

  4. Для рабочего стола: Если вы хотите, чтобы ярлык был прямо на рабочем столе, после копирования файла на рабочий стол (например, cp led_gui.desktop ~/Desktop/), возможно, потребуется щелкнуть по нему правой кнопкой мыши и выбрать опцию «Разрешить запуск» или «Allow Launching» в его свойствах.

Иконка приложения

Вы можете использовать любую иконку. Вот пример иконки, которую можно использовать:

Иконка светодиода

Заключение

Поздравляем! Вы только что успешно создали полноценное GTK-приложение на Raspberry Pi, которое управляет реальным светодиодом через GPIO. Это отличный первый шаг к созданию более сложных и интерактивных GUI-приложений для ваших проектов на Raspberry Pi.

В следующих главах мы продолжим развивать интерфейс, добавляя больше элементов управления, таких как поля ввода, ползунки, а также будем работать с таймерами и другими компонентами GUI для создания более функциональных приложений.