Что такое кейс SPI: Полное руководство и примеры использования

Конструкция switch-case служит для сравнения выражения с набором значений. Она имеет следующий формат:

После ключевого слова switch в скобках указывается выражение, которое будет сравниваться с каждым значением, заданным после оператора case. При совпадении будет выполнен соответствующий блок case.

Важно отметить, что выражение в switch должно быть одного из целочисленных, символьных типов или представлять перечисление (обсуждается далее).

В конце конструкции switch может находиться блок default. Он не является обязательным и выполняется, если ни одно из значений после switch не соответствует ни одному оператору case. Например:

#include <iostream>

std::cout << "x is undefined";

}

Чтобы предотвратить выполнение последующих блоков case или default, в конце каждого блока необходимо использовать оператор break. Таким образом, если выражение совпадает с case 2, выполнится оператор break и дальнейшие операторы case будут проигнорированы, что приведет к выводу на консоль строки «x = 2».

Важно всегда использовать оператор break. Без него выполнение блока case продолжится до следующего блока case. Например, если удалить все операторы break:

#include <iostream>

std::cout << "x is undefined";

}

В данном случае, поскольку x равно 2, сначала выполнится case 2, затем case 3, а затем и default, что приведет к выводу:

x = 2 x = 3 x is undefined

Совмещение условий

Можно задать один набор инструкций для нескольких меток case:

#include <iostream>

std::cout << "x = 1 или 2";

}

Переменные в блоках case

Определение переменных в блоках case возможно, но требует особого подхода. Если переменная объявляется в блоке case, все инструкции блока должны быть заключены в фигурные скобки (для блока default это не обязательно):

#include <iostream>

std::cout << "a = " << a;

std::cout << "b = " << b;

std::cout << "c = " << c;

}

Блок switch с инициализацией переменной

В конструкции switch для промежуточных вычислений можно определить переменную. Начиная с C++17, язык поддерживает особую форму switch:

switch(инициализация; выражение) {

}

Эта форма также принимает выражение, которое сравнивается с константами case, но перед ним можно определить и инициализировать переменную. Например:

#include <iostream>

std::cout << "Результат: " << (n + k);

std::cout << "Результат: " << (n - k);

}

В данном примере в конструкции switch объявляется переменная k, которая доступна только внутри этой конструкции. Выражение сравнивается с значением переменной op, и в зависимости от этого выполняется соответствующая операция с переменными n и k.

  • Глава 1. Введение в С++
  • Язык программирования С++
  • Первая программа на Windows. Компилятор g++
  • Первая программа на Windows. Компилятор Clang
  • Начальная программа на Windows. Компилятор Microsoft Visual C++
  • Начальная программа на Linux. Компилятор g++
  • Начальная программа на MacOS. Компилятор Clang
  • Конфигурация параметров компиляции
  • Локализация и поддержка кириллицы в консоли
  • Структура программы
  • Переменные
  • Типы данных
  • Константы
  • Ввод и вывод данных в консоли
  • Использование. Подключение пространств имен и создание псевдонимов
  • Арифметические операции
  • Статическая типизация и преобразование типов
  • Побитовые операции
  • Операции присваивания
  • Условные выражения
  • Конструкция if-else и тернарный оператор
  • Конструкция switch-case
  • Циклы
  • Ссылки
  • Массивы
  • Многомерные массивы
  • Массивы символов
  • Введение в строки
  • Что такое указатели
  • Операции с указателями
  • Арифметика указателей
  • Константы и указатели
  • Указатели и массивы
  • Определение и объявление функций
  • Область видимости объектов
  • Параметры функций
  • Передача аргументов по значению и по ссылке
  • Константные параметры
  • Оператор return и возвращение результата
  • Указатели в параметрах функций
  • Массивы в параметрах функций
  • Параметры функции main
  • Возвращение указателей и ссылок
  • Перегрузка функций
  • Рекурсивные функции
  • Рекурсия на примере быстрой сортировки
  • Указатели на функции
  • Указатели на функции как параметры
  • Тип функции
  • Указатель на функцию как возвращаемое значение
  • Разделение программы на файлы
  • Внешние объекты
  • Динамические объекты
  • Динамические массивы
  • unique_ptr
  • shared_ptr
  • Определение классов
  • Конструкторы и инициализация объектов
  • Управление доступом. Инкапсуляция
  • Объявление и определение функций класса
  • Конструктор копирования
  • Константные объекты и функции
  • Ключевое слово this
  • Дружественные функции и классы
  • Статические члены класса
  • Деструктор
  • Структуры
  • Перечисления
  • Наследование
  • Управление доступом в базовых и производных классах
  • Скрытие функционала базового класса
  • Множественное наследование
  • Виртуальные функции и их переопределение
  • Преобразование типов
  • Динамическое преобразование
  • Особенности динамического связывания
  • Чистые виртуальные функции и абстрактные классы
  • Перегрузка операторов
  • Операторы преобразования типов
  • Оператор индексирования
  • Переопределение оператора присваивания
  • Пространства имен
  • Вложенные классы
  • Обработка исключений
  • Вложенные try-catch
  • Создание собственных типов исключений
  • Тип exception
  • Типы исключений
  • Шаблоны функций
  • Шаблон класса
  • Специализация шаблона класса
  • Наследование и шаблоны классов
  • Типы контейнеров
  • Вектор
  • Итераторы
  • Операции с векторами
  • Forward_list
  • Стек std::stack
  • Очередь std::queue
  • Приоритетная очередь std::priority_queue
  • Множества
  • Словарь std::map
  • Определение строк
  • Строки с поддержкой Unicode
  • Преобразование типов и строки
  • Сравнение строк
  • Получение подстроки и проверка начала и конца строки
  • Поиск подстрок
  • Модификация строк
  • Манипуляции с символами
  • Слово-сканер
  • Тип std::string_view
  • rvalue ссылки
  • Конструкторы перемещения
  • Операторы перемещения
  • Значение noexcept в перемещении
  • Функциональные объекты
  • Лямбда-функции
  • Захват переменных в лямбда-выражениях
  • Шаблон std::function<>
  • Минимальные и максимальные элементы
  • Поиск элементов
  • Копирование элементов
  • Удаление элементов и идиома Remove-Erase
  • Сортировка
  • Фильтрация представлений
  • Проецирование данных
  • Пропуск элементов: drop_view и drop_while_view
  • Выборка элементов: take_view и take_while_view
  • Цепочки представлений
  • Оператор requires
  • Концепты
  • Выражение requires
  • Ограничения типа для auto
  • Основные типы потоков
  • Работа с файловыми потоками
  • Чтение и запись текстовых файлов
  • Переопределение операторов ввода и вывода
  • Математические константы и операции
  • Форматирование строк и функция format
  • Управление ресурсами: идиома RAII
  • Идиома копирования и замены
  • Идиома Move-and-Swap
  • Первая программа в Visual Studio
  • Первая программа в Qt Creator
  • Java 6 представила возможность обнаружения и загрузки реализаций, соответствующих данному интерфейсу, под названием интерфейс поставщика услуг (SPI).

    В этом руководстве мы рассмотрим компоненты Java SPI и продемонстрируем, как его можно использовать на практике.

    2.1. Обслуживание

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

    2.2. Интерфейс поставщика услуг

    Интерфейс или абстрактный класс, действующий как прокси или конечная точка для сервиса.

    Если сервис представлен единственным интерфейсом, он совпадает с интерфейсом поставщика услуг.

    Сервис и SPI вместе образуют API в экосистеме Java.

    2.3. Поставщик услуг

    Конкретная реализация SPI. Поставщик услуг включает один или несколько классов, реализующих или расширяющих тип сервиса.

    Поставщик услуг настраивается и определяется через файл конфигурации, который размещается в каталоге ресурсов META-INF/services. Имя файла соответствует полному имени SPI, а его содержимое — полное имя реализации SPI.

    Поставщик услуг устанавливается как расширение, jar-файл, который добавляется в classpath приложения, расширения Java или определенный пользователем путь к классам.

    2.4. ServiceLoader

    Ключевым компонентом SPI является класс ServiceLoader. Он отвечает за обнаружение и ленивую загрузку реализаций провайдеров, используя контекстный classpath для поиска реализаций и их кэширования.

    4.1. Создание нашего API

    Начнем с создания проекта Maven под названием exchange-rate-api. Хорошей практикой является окончание имени на api, но можно выбрать любое другое название.

    Далее создадим модельный класс для представления валютных курсов:

    package com.example.rate.api; public class Quote

    Затем определим Service для получения котировок, создав интерфейс QuoteManager:

    package com.example.rate.api; public interface QuoteManager { List<Quote> getQuotes(String baseCurrency, LocalDate date); }

    Теперь создадим SPI для нашего сервиса:

    package com.example.rate.spi; public interface ExchangeRateProvider

    В завершение нам нужно создать вспомогательный класс ExchangeRate.java, который будет использоваться клиентским кодом. Этот класс будет делегировать работу ServiceLoader.

    Сначала вызываем статический фабричный метод load(), чтобы получить экземпляр ServiceLoader:

    ServiceLoader loader = ServiceLoader.load(ExchangeRateProvider.class);

    Затем используем метод iterate() для поиска и получения всех доступных реализаций.

    Iterator iterator = loader.iterator();

    Результат поиска кэшируется, поэтому для обнаружения недавно добавленных реализаций можно вызвать метод ServiceLoader.reload():

    loader.reload();
    public class ExchangeRate {

    ServiceLoader loader = ServiceLoader.load(ExchangeRateProvider.class);

    public Iterator providers(boolean refresh) {

    }

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

    Важно отметить, что этот вспомогательный класс не обязательно должен быть частью проекта API. Клиентский код может самостоятельно вызывать методы ServiceLoader.

    4.2. Создание провайдера услуг

    Создадим проект Maven с именем exchange-rate-impl и добавим зависимость API в pom.xml:

    com.exampleexchange-rate-api1.0.0-SNAPSHOT

    Теперь создаем класс, который реализует наш SPI:

    public class YahooFinanceExchangeRateProvider implements ExchangeRateProvider {

    return new YahooQuoteManagerImpl();

    }

    А вот реализация интерфейса QuoteManager:

    public class YahooQuoteManagerImpl implements QuoteManager {

    public List getQuotes(String baseCurrency, LocalDate date) {

    }

    Чтобы быть обнаруженным, создадим файл конфигурации провайдера:

    META-INF/services/com.example.rate.spi.ExchangeRateProvider

    Содержимое файла должно содержать полное имя класса реализации SPI:

    com.example.rate.impl.YahooFinanceExchangeRateProvider

    4.3. Объединение компонентов

    Создадим клиентский проект под названием exchange-rate-app и добавим зависимость exchange-rate-api в пути классов:

    com.exampleexchange-rate-api1.0.0-SNAPSHOT

    Теперь можно вызывать SPI из нашего приложения:

    ExchangeRate.providers().forEach(provider -> provider.create());

    4.4. Запуск приложения

    Сосредоточимся на сборке всех наших модулей:

    mvn clean package

    Запускаем наше приложение с помощью Java без использования провайдера:

    java -cp ./exchange-rate-api/target/exchange-rate-api-1.0.0-SNAPSHOT.jar:./exchange-rate-app/target/exchange-rate-app-1.0.0-SNAPSHOT.jar com.example.rate.app.MainApp

    Теперь включим нашего провайдера в расширение java.ext.dirs и снова запустим приложение:

    java -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:./exchange-rate-impl/target:./exchange-rate-impl/target/depends -cp ./exchange-rate-api/target/exchange-rate-api-1.0.0-SNAPSHOT.jar:./exchange-rate-app/target/exchange-rate-app-1.0.0-SNAPSHOT.jar com.example.rate.app.MainApp

    Мы видим, что наш провайдер загружен.

    Что такое SPI

    SPI, или Serial Peripheral Interface, представляет собой последовательный интерфейс периферийных устройств. Этот протокол последовательной связи был разработан компанией Motorola в 1970 году. Интерфейс SPI позволяет передавать и получать данные одновременно благодаря полному дуплексному соединению. Это значит, что ведущий (master) может отправлять данные ведомому (slave), который, в свою очередь, может одновременно отправлять данные ведущему. SPI — это синхронный протокол, что означает необходимость синхронизации всех устройств. Ранее мы рассматривали использование этого интерфейса для подключения графического ЖК дисплея Nokia 5110 к плате Arduino.

    Как работает интерфейс SPI

    Для работы по принципу ведущий/ведомый (master/slave) протокол SPI использует 4 линии. В этом протоколе всегда один ведущий и несколько ведомых. Ведущим устройством обычно является микроконтроллер, а ведомыми могут быть микроконтроллеры, датчики, АЦП, ЦАП, ЖК дисплеи и другие устройства.

    Ниже показан принцип работы протокола SPI с одним ведущим (Master) и одним ведомым (Slave).

    Для своей работы SPI использует 4 линии: MISO, MOSI, SCK и SS. Их назначение:

    • MISO (Master In Slave Out) – линия для передачи данных от ведомого к ведущему;
    • MOSI (Master Out Slave In) – линия для передачи данных от ведущего к ведомому;
    • SCK (Serial Clock) – линия для передачи синхронизирующих импульсов, формируемых ведущим;
    • SS (Slave Select) – линия для включения и выключения определенных устройств (ведомых).

    Ниже представлен принцип работы протокола SPI с одним ведущим (Master) и несколькими ведомыми (Slave).

    Для начала связи между ведущим и ведомым необходимо установить на контакте ведомого Slave Select (SS) низкий уровень напряжения, чтобы он мог взаимодействовать с ведущим. Когда на этом контакте высокий уровень напряжения, ведомый игнорирует ведущего. Это позволяет подключить множество ведомых устройств к одним и тем же линиям MISO, MOSI и SCK ведущего устройства. Как видно из схемы, для 4-х ведомых устройств линии SCLK, MISO и MOSI общие, а линии SS каждого ведомого подключены к отдельным контактам SS (SS1, SS2, SS3, SS4) ведущего. Устанавливая на нужном контакте SS низкий уровень напряжения (LOW), ведущий может взаимодействовать с необходимым ведомым.

    Контакты SPI на плате Arduino Uno

    На следующем изображении красным прямоугольником отмечены контакты на плате Arduino Uno, которые могут быть использованы для связи по протоколу SPI.

    SPI интерфейс Пин Arduino Uno
    MOSI 11 или ICSP-4
    MISO 12 или ICSP-1
    SCK 13 или ICSP-3
    SS 10

    С контактами разобрались, идем дальше.

    Описание программы для Arduino

    Нам потребуются две программы: одна – для ведущей платы Arduino, другая – для ведомой платы. Коды обеих программ приведены в конце статьи, а здесь мы кратко обсудим их ключевые части.

    Программа для ведущей платы Arduino (Master)

    1. Вначале программы необходимо подключить библиотеку SPI, чтобы использовать функции этого протокола.

    Что такое SPI?

    SPI расшифровывается как Serial Peripheral Interface. Это протокол синхронной последовательной передачи данных. Он используется для связи между периферийными устройствами, такими как входные и выходные устройства, и микроконтроллерами. SPI позволяет передавать данные на высокой скорости. Он популярен в цифровых коммуникационных приложениях и встроенных системах. SPI может передавать и получать данные между устройствами одновременно.

    Компоненты SPI

    Serial Peripheral Interface (SPI) – это процесс синхронного последовательного протокола передачи данных. Он в основном используется для подключения микроконтроллеров к периферийным устройствам, таким как датчики, дисплеи и чипы памяти. SPI обеспечивает полнодуплексную, синхронную последовательную связь между одним или несколькими ведомыми устройствами и микроконтроллером.

    Советуем прочитать:  Наложенный платеж
    Понравилась статья? Поделиться с друзьями:
    Добавить комментарий

    ;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

    Adblock
    detector