BiNome
BiNome
2153 просмотров0 комментариев

Часть 2. Программное управление линиями GPIO Repka Pi 3 в режиме вывода с примерами на Python (libgpiod).

Содержание


Представленный в статье материал предназначен для изучения возможности применения ЯП Python для программного управления линиями GPIO на Repka Pi 3 с использованием библиотеки libgpiod. Подробно рассмотрены примеры работы со светодиодами, регистром 74HC595 и магнитными реле. Настоящая статья не является законченным продуктом, в дальнейшем будет корректироваться и наполняться новыми материалами соответствующими теме статьи.

См. также:
Часть 1. Программное управление GPIO Repka Pi 3 через системные вызовы к драйверу символьных устройств. Общие понятия. Настройка RepkaOS. Использование инструментов управления GPIO из пользовательского режима

СОДЕРЖАНИЕ

I. Введение
Подготовка Repka Pi 3 к работе с GPIO

1. Светодиоды
   1.1. Что такое светодиод?
   1.2. Схема подключения к контактам Repka Pi 3
   1.3. Расчет номинального сопротивления токоограничительного (“защитного“) резистора на примере светодиода

2. Сдвиговый регистр 74HC595N
   2.1. Что такое сдвиговый регистр?
   2.2. Схема подключения регистра к контактам Repka Pi 3

3. Электромагнитное реле
   3.1. Что такое электромагнитное реле?
   3.2. Схема подключения реле к контактам Repka Pi 3

II. Заключение

От автора, или для кого написана эта статья #

Repka Pi 3 это действительно уникальный отечественный проект, который помимо всего прочего, позволяет построить на его основе универсальное рабочее место обучаемого. И это не просто слова, вычислительной мощности устройства достаточно, чтобы использовать его как рабочую станцию с графическим интерфейсом (используя “магию” оптимизации), позволяющую освоить работу в ОС Linux (в т.ч. администрирование); изучать языки программирования; проектировать, разрабатывать и программно управлять электронными устройствами; выполнять лабораторные работы по информатике, физике и т.д. Но в настоящее время, к сожалению, отсутствуют какие-либо учебные и методические материалы, позволяющие учителям, преподавателям, руководителям тематических кружков использовать данное устройство в своей работе. Целью данной статьи (как и предыдущей и запланированных последующих частей) является попытка решения вышеуказанной проблемы.

Дополнительно хотелось бы отметить, что благодаря таким людям, как Мария Котоусова (ник пользователя канала Репка/Repka-Pi Telegram) из г. Коломна (Московская обл.) и ее 8 летнего ученика (несмотря на его возраст занял первое место в конкурсе и получил Репку в качестве приза), и их нацеленности на применение Репки в учебном процессе, желание написать эту статью подкрепилось дополнительным стимулом. Надеюсь, что количество таких людей будет только увеличиваться, и когда нибудь, от них появится обратная связь по использованию опубликованных учебных материалов в виде замечаний, рекомендаций, а может быть и в виде предложения о совместной работе над новыми, востребованными на практике материалами.

Введение #

Repka Pi 3 является сложным электронным устройством, требующим от пользователя определенных знаний, умений и соблюдения правил электробезопасности. Все схемы и программы, приведенные в статье, проверялись и тестировались автором перед публикацией. Тем не менее, при сборке схем и написании программ во время выполнения заданий для самостоятельной работы читателями могут быть допущены ошибки, которые могут привести к выходу из строя электрооборудования или его элементов. Материал статьи распространяется по принципу “как-есть“, выполняя задания вы должны осознавать возможные риски и последствия ваших действий, и автор не несет ответственность за допущенные вами ошибки, приведшие к выходу из строя оборудования.

В целях предотвращения выхода Repka Pi 3 из строя, при сборке схем и подключении электронных компонент к GPIO-разъему, категорически ЗАПРЕЩАЕТСЯ:

  1. Подавать на разъемы напряжение более 3.3В;
  2. Подключать к разъемам схемы, приводящие к короткому замыканию;
  3. Подключать к разъему элементы суммарно потребляющие ток более 40мА;
  4. Подключать или отключать электронные компоненты, в том числе в составе схемы, а также изменять их при работающем устройстве Repka Pi 3;
  5. Использовать блок питания для Repka Pi 3 не соответствующий характеристикам заявленным разработчиками устройства (5В, 3А);
  6. Использовать внешние источники энергии не соответствующие требованиям к номинальному напряжению и силе тока элементов электросхемы;
  7. Соединять элементы схемы проводами находящимися под натяжением.

Для работы с устройствами, подключаемыми к GPIO-разъему РЕКОМЕНДУЕТСЯ:

  1. Использовать макетную плату для соединения элементов проводами;
  2. Использовать плату для GPIO расширение (GPIO Extension Board for Raspberry Pi) совместно с 40-pin шлейфом, который сведет к минимуму риски повреждения контактов GPIO-разъема на Repka Pi 3;
  3. Электронные компоненты схемы потребляющие большой ток необходимо запитывать от внешнего источника питания;
  4. Использовать модуль питания макетной платы с функцией стабилизатора, для подключения внешнего источника питания;
  5. Исключить возможность повреждения электронных компонент статическим электричеством с помощью специальных средств (например, заземляющий браслет);
  6. Сборку схемы на макетной плате осуществлять в хорошо освещенном помещении, использовать пинцет и увеличительное стекло (лупу).

Подготовка Repka Pi 3 к работе с GPIO #

  1. Настройте ОС в соответствии с инструкциями описанными в разделе “Библиотека libgpiod2” первой части статьи.

  2. В состав RepkaOS 1.0.14 “из коробки“ установлен Python версии 3.8.10. Версию ЯП можно проверить командой:

    python3 --version
    
  3. Проверьте работу интерпретатора Python, введите команду:

    python3
    

    затем, введите с клавиатуры текст программы, затем нажмите Enter:

    print("Hello, Repka Pi 3!")
    

    Фраза, указанная в кавычках должна отобразиться на новой строке. Закройте интерпретатор командой:

    quit()
    
  4. Если планируете работать (программировать) непосредственно на Repka Pi 3:

    4.1. Установите IDE для работы с ЯП Python, например Thonny (версия в репозитории оптимизирована для Raspbery Pi и оптимально подойдет для Репки с 1 Gb ОЗУ, sudo apt install thonny) или VS Code (для Репки с 2 Gb ОЗУ, ссылки для загрузки, настройки быстродействия и настройки расширений).

    Примечание: для написания программ можно использовать установленную по умолчанию IDE Geany, для запуска выполнения программы необходимо в ее настройках изменить путь к интерпретатору Python (заменить python на python3). Для любителей CUI, в ОС по умолчанию установлен Vim tiny не поддерживающий подсветку синтаксиса, желательно заменить его на полную версию Vim - sudo apt install vim.

    4.2. Измените в настройках оконного менеджера ОС разрешение экрана на 720p или 800p (в зависимости от соотношения сторон используемого вами монитора), этого разрешения будет достаточно для комфортной работы с IDE и позволит высвободить до 40 Mb ОЗУ.

    Примечание: если используете подключение Репки к сети интернет через Ethernet-порт, отключите Bluetooth и Wi-Fi (через соответствующие иконки в правом верхнем углу), по субъективной оценке это дает небольшой прирост производительности (могу ошибаться, тесты не проводил).

    4.3. Используйте активное охлаждение на устройстве (если у вас только плата, можно “приколхозить“ кулер от ПК). При написании и выполнении примеров из статьи процессор нагреваться не будет, но как правило, потребуется доступ к материалам из интернета, и соответственно нужно будет запускать браузер, что и приведет к высокой нагрузке на процессор и следственно к его нагреву.

    Примечание: нагрев процессора выше 65°С приведет к снижению его частоты, что в итоге отразится на быстродействии устройства. При длительной вычислительной нагрузке его частота упадет до 228 MHz (при достижении 86°С), и он будет упорно пытаться выполнить поставленные перед ним задачи, пока не нагреется до 95 градусов и не выключится - одним словом Репка - патриот своего дела! Пытается выполнить поставленную задачу до конца не щедя себя.

    Примечание: например, я использую 12 вольтовый (с соответствующим блоком питания) практически бесшумный вентилятор DeepCool из состава системы охлаждения CPU ПК, постоянно работающий на 3000 оборотах. При его использовании температура Репки не поднималась выше 60 градусов даже при проведении высоконагруженных вычислительных стресс тестов (тестировались алгоритмы решения NP-сложных задач на графах). В режиме простоя поддерживается температура в районе 30 градусов. Но есть в этом и “-“, если Репка лежит близко - мерзнут руки.

  5. Если вы еще не установили библиотеку для работы с libgpiod из Python, выполните консольную команду:

    pip3 install gpiod
    

    Примечание: для установки утилиты pip3 (OS Repka установлена “из коробки“) используйте команду sudo apt install python3-pip

  6. Проверим работу библиотеки с помощью следующего скрипта:

    """
    Скрипт выводит в консоль сведения о доступных в системе контроллерах GPIO и управляемых ими линиях. Объединяет в себе функционал утилит gpiodetect и gpioinfo
    """
    
    import gpiod # подключаем библиотеку для работы с libgpiod
    
    # запускаем цикл для перечисления зарегистрированных в ОС контроллеров GPIO
    for chip in gpiod.chip_iter():
        # выводим информацию о текущем контроллере
        print(f"{chip.name} [{chip.label}] ({chip.num_lines} lines)")
        # запускаем цикл для перечисления управляемых контроллером линиях
        for line in gpiod.line_iter(chip):
            offset = line.offset # номер линии
            name = line.name # наименование линии (у Repka Pi 3 - все линии 'unnamed')
            consumer = line.consumer # имя процесса или пользовательская метка, указывает кем/чем занята линия
            direction = line.direction # направление линии вход/выход
            active_state = line.active_state # состояние напряжения в линии низкое/высокое
    
            print('\tline {:>3}: {:>18} {:>12} {:>8} {:>10}'.format(
                  offset,
                'unnamed' if name is None else name,
                'unused' if consumer is None else consumer,
                'input' if direction == gpiod.line.DIRECTION_INPUT else 'output',
                'active-low' if active_state == gpiod.line.ACTIVE_LOW 
                                  else 'active-high'))
    
  7. Запустите скрипт на выполнение. Сравните результат с выводом утилит gpiodetect и gpioinfo gpiochipN, где N - номер контроллера 0 или 1.

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

  1. Найдите в списке линии, настроенные на вывод.
  2. Найдите линии используемые Репкой для контактов выключения питания и перезагрузки устройства, определите их их параметры.
  3. Найдите линии для индикаторных светодиодов репки, определите их параметры.
  4. С помощью утилиты gpioset установите высокое напряжение на 11 линии 0 чипа, запустите программу, проанализируйте параметры измененной линии.
  5. Установите низкое напряжение на 11 линии 0 чипа, запустите скрипт, проанализируйте параметры измененной линии.

1. Светодиоды #

Что такое светодиод? #

Светодиод (LED) - это полупроводниковый источник света, который излучает свет при протекании через него тока. Чаще всего светодиод используется в качестве индикатора выполнения какого-либо процесса либо вывода сообщения о неисправности устройства. Частота мигания светодиода, как привило, представляет собой закодированное сообщения о статусе процесса или коде неисправности.

Рис. 1. Светодиод (слева - общий вид, справа - знак для отображения на принципиальной схеме ).

Схема подключения к контактам Repka Pi 3 #

При подключении светодиода нужно обязательно соблюдать полярность. Анод светодиода имеет более длинную ножку, чем катод. Номинальное напряжение светодиодов колеблется от 1,9 до 3,4 В, а номинальный ток от 10 до 20 мА, поэтому для их защиты от перегорания на схеме к катоду подключают “защитные” резисторы для понижения напряжения. Пока мы не будем вникать в порядок расчета сопротивления резистора и будем использовать резистор номиналом 220 Ом. На рисунке 2 представлена схема подключения светодиода к контактам Repka Pi 3.

Рис. 2. Макет схемы подключения светодиода.

Расчет номинального сопротивления токоограничительного (“защитного“) резистора на примере светодиода

Раздел добавлен по просьбе пользователей телеграмм-канала Репка/Repka-Pi.

Значение минимального сопротивления токоограничительного резистора вычисляем по формуле:

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

Таблица 1. Параметры светодиодов (прямой номинальный рабочий ток 20 мА).

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

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

Таблица 2.

Примеры:

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

    • Питание светодиода осуществляется от 3,3В.
    • Из таблицы 1: прямое напряжение красного светодиода с матовым красным цветом линзы - 1,9В, прямой номинальный рабочий ток - 20 мА.

    Вычисляем минимальное значение сопротивления по представленной выше формуле:

    (3,3 - 1,9) / 0,04 = 35 Ом.

    Из таблицы 2 выбираем большее значение, которое является ближайшим к 35, это буде 36 Ом.

    Мы нашли с вами номинальное значение сопротивления резистора, который можно использовать. Но есть одно большое НО, если вы установите такой резистор в схему, то при подаче питания он начнет греться, соответственно быстро израсходует свой ресурс. На практике, как правило, вычисленное минимальное значение еще умножают на 3, что позволяет увеличить срок службы резистора, но при этом снижается яркость светодиода. В нашем примере 35 × 3 = 105 Ом, номинальное значение из таблицы - 110 Ом.

    Ответ: в схеме напряжением 3,3В для красного светодиода рекомендуется использовать токоограничивающий резистор номиналом 110 Ом.

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

    Из таблицы 1: прямое напряжение красного светодиода с матовым красным цветом линзы - 1,9В, прямой номинальный рабочий ток - 20 мА.

    Вычисляем минимальное значение сопротивления по представленной выше формуле:

    (5 - 1,9) / 0,04 = 77,5 Ом.

    умножим полученное значение на 3, получим - 233 Ом. Из таблицы 2 получаем значение 240 Ом.

    Ответ: в схеме напряжением 5В для красного светодиода рекомендуется использовать токоограничивающего резистор номиналом 240 Ом.

    Примечание: в схеме на рисунке 1 используется токоограничивающий резистор номиналом 220 Ом, и он выбран не случайно. Во-первых его можно использовать с питанием сети как с 3,3В, так и с 5В. А во-вторых резисторы такого наминала чаще всего включаются в состав стартового набора для Arduino.

Важно! Приведенную в данном разделе информацию и порядок расчета нужно применять для расчета номинального значения сопротивления токоограничивающего резистора ДЛЯ ЗАЩИТЫ ВХОДНЫХ КОНТАКТОВ Repka Pi 3 при необходимости считывания состояния линии при использовании устройств, работающих с напряжением более 3,3В.

Пример: в схеме используется 5В датчик, значения которого необходимо подавать на линию ввода. Прямое подключение датчика к линии приведет к поломке Репки (не рекомендую проверять!). Подберем резистор: (5-3,3) / 0,04 = 42,5; 42,5 × 3 = 127,5 Ом, из таблицы 2 получаем значение 130 Ом.

Рекомендую собрать схему с внешним источником питания 5В, подключить к ней резистор номиналом 130 Ом и произвести замеры напряжения мультиметром до резистора и после. Тоже самое можно сделать со схемой, представленной на рисунке 2, устанавливая резисторы разных номиналов.

Задание 1.1. “Первый блин…“

Шаг. 1. Соберите схему представленную на рисунке 1.

Для выполнения задания вам понадобятся: Repka Pi 3, макетная плата, красный светодиод, резистор 220 Ом, черный и желтый провод мама-папа. Черный провод подключите к 6 контакту, а желтый к 32 контакту GPIO-разъема.

Шаг 2. Проверьте работу светодиода используя приведенный ниже код программы:

import gpiod # подключаем библиотеку для работы с libgpiod
import time # подключаем библиотеку для работы со временем

LED_CHIP = 0 # номер используемого контроллера
LED_LINE_OFFSET = 11 # номер используемой линии

chip = gpiod.chip(LED_CHIP) # получаем доступ к контроллеру 0
led = chip.get_line(LED_LINE_OFFSET) # получаем доступ к линии 11

# получаем структуру для настройки линии
config = gpiod.line_request() 

# указываем название программы или пользовательскую метку, 
# выбирайте название таким образом, 
# чтобы оно отражало суть использования линии
# (будет выводится для линии при вызове gpioinfo)
config.consumer = "Test LED" 
# задаем направление работы линии
config.request_type = gpiod.line_request.DIRECTION_OUTPUT 
# применяем настройки к линии
led.request(config)

# устанавливаем высокое напряжение в линии (включаем светодиод)
led.set_value(1)
# ждем 5 секунд
time.sleep(5)
# устанавливаем низкое напряжение в линии (выключаем светодиод)
led.set_value(0)

# КОНЕЦ ПРОГРАММЫ

Как видно из примера, управление светодиодами простая задача, весь алгоритм можно описать следующими шагами:

  1. Получить доступ к контроллеру по его номеру или имени (например “gpiochip0”).
  2. Получить доступ к линии по ее номеру.
  3. Задать параметры линии (название и направление) и присвоить их ей.
  4. Выполнить манипуляции с линией, путем подачи высокого или низкого напряжения.
  5. Повторять пункт 4 до выполнения поставленной задачи (чаще всего используется бесконечный цикл).
  6. Закончить выполнение программы.

Задания для самостоятельной работы. Измените код программы из задания 1.1, так чтобы:

  1. Светодиод светил 3 секунды и выключался.
  2. Светодиод загорался на 1 секунду 5 раз, с интервалами между вспышками 0,5 секунды (без использования циклов).
  3. (*) Дополнительно для задания 2. Запросите через консоль у пользователя длительность свечения светодиода и паузы между вспышками.
  4. (*) Реализуйте аналог утилиты gpiodset, для управления линией через параметры командной строки (пример запуска скрипта: python3 mygpioset.py gpiochip0 11=1).

Задание 1.3. “Спасательный маячок“. Введите код программы (см. ниже) для реализации сигнала SOS с помощью красного светодиода. Форма подачи сигнала: 3 коротких - 3 длинных - 3 коротких проблеска, между проблесками короткая пауза. Сигнал SOS должен подаваться непрерывно, паузы между сообщениями должны быть в два раза длиннее чем между проблесками. Используйте схему из задания 1.1.

import gpiod # подключаем библиотеку для работы с libgpiod
import time # подключаем библиотеку для работы со временем

# зададим временные интервалы для сигналов и присвоим их переменным
SHORT_SIGNAL = 0.25
LONG_SIGNAL = 0.5
PAUSE_SIGNAL = 0.25

# зададим код сигнала в виде списка, где 0 - точка, 1 - тире
SIGNAL = [0,0,0,1,1,1,0,0,0]

LED_CHIP = 0 # номер используемого контроллера
LED_LINE_OFFSET = 11 # номер используемой линии

chip = gpiod.chip(LED_CHIP) # получаем доступ к контроллеру 0
led = chip.get_line(LED_LINE_OFFSET) # получаем доступ к линии 11

# получаем структуру для настройки линии
config = gpiod.line_request() 

# указываем название для линии
config.consumer = "SOS LED" 
# задаем направление работы линии
config.request_type = gpiod.line_request.DIRECTION_OUTPUT 
# применяем настройки к линии
led.request(config)

# запускаем "бесконечный" цикл
while True:
    # запустим цикл подачи сигнала SOS, путем пошагового обхода списка SIGNAL
    for delta in SIGNAL:
        # устанавливаем высокое напряжение в линии (включаем светодиод)
        led.set_value(1)
        # если сигнал короткий (точка) ждем 0,25 сек
        if delta == 0:    
            time.sleep(SHORT_SIGNAL)
        # если сигнал длинный (тире) ждем 0,5 сек
        else:
            time.sleep(LONG_SIGNAL)
        # устанавливаем низкое напряжение в линии (выключаем светодиод)
        led.set_value(0)
        # ждем 0,25 сек для передачи следующего сигнала
        time.sleep(PAUSE_SIGNAL)

    # все сигналы переданы, ждем 0,5 сек и передаем пакет сигналов снова
    time.sleep(PAUSE_SIGNAL*2)

# КОНЕЦ ПРОГРАММЫ

Запустите программу. Проверьте тайминги и порядок подачи сигналов. Программа будет выполнятся в бесконечном цикле, чтобы завершить процесс (закрыть программу) нажмите Ctrl+C в консоли (или соответствующую кнопку в IDE).

Задания для самостоятельной работы:

  1. После остановки программы проверьте с помощью утилиты gpioinfo 0 состояние 11 линии.
  2. (*) Используя международную таблицу азбуки Морзе, внесите изменения в код программы, чтобы светодиод вывел сигналы “Hello Repka“.
  3. (*) На основе скрипта из задания 1.3. реализуйте прототип устройства кодирования введенного пользователем сообщения в сигналы азбуки Морзе. Используйте международную таблице для азбуки Морзе.

Задание 1.4. “Модуль управление светофором”. #

Постановка задачи: Светофор регулирует движение транспортных средств на перекрестке и оснащен световыми сигналами трех цветов: красный, желтый и зеленый. Зеленый сигнал разрешает движение через перекресток в течение 2 мин. Про прошествию 2 мин. зеленый сигнал мигает 3 раза в течении 3 сек и выключается. После зеленого сигнала включается желтый сигнал светофора на 3 сек. Желтый сигнал сменяется красным, и запрещает движение транспортных средств на 3 мин. По окончанию 3 мин. к красному сигналу на 3 сек. добавляется желтый сигнал, после чего красный и желтый сигналы выключаются и включается зеленый. Количество циклов работы светофора не ограничено.

Для выполнения задания усовершенствуем макет, собранный при выполнении задания 1.1. Дополнительно нам понадобятся: желтый и зеленый светодиод, два резистора 220 Ом, желтый и зеленый провод мама-папа.

Шаг 1. Соберите схему в соответствии с макетом представленным на рисунке 2. Желтый провод подключите к 36 контакту, а зеленый к 38 контакту GPIO-разъема.

Рис. 3. Макет схемы светофора.

Шаг 2. Введите код программы:

import gpiod # подключаем библиотеку для работы с libgpiod
import time # подключаем библиотеку для работы со временем

# зададим временные интервалы для сигналов и присвоим их переменным
R_LED_SIGNAL = 180           # 3 * 60 сек
RY_LED_SIGNAL = 3 
Y_BLINK_SIGNAL = 3
G_BLINK_SIGNAL = 0.5
G_SIGNAL = 120               # 2 * 60 сек

LED_CHIP0 = 0 # номер используемого контроллера для красного светодиода
LED_CHIP1 = 1 # номер используемого контроллера для желтого и зеленого светодиода
R_LED = 11 # номер линии для красного светодиода
Y_LED = 13 # номер линии для желтого светодиода
G_LED = 15 # номер линии для зеленого светодиода

chip0 = gpiod.chip(LED_CHIP0) # получаем доступ к контроллеру 0
chip1 = gpiod.chip(LED_CHIP1) # получаем доступ к контроллеру 1

R_led = chip0.get_line(R_LED) # получаем доступ к линии 11
Y_led = chip1.get_line(Y_LED) # получаем доступ к линии 13
G_led = chip1.get_line(G_LED) # получаем доступ к линии 15

# получаем структуру для настройки линии
config = gpiod.line_request() 
# задаем направление работы линии
config.request_type = gpiod.line_request.DIRECTION_OUTPUT 

# указываем название линии
config.consumer = "RED LED" 
# применяем настройки к 11 линии
R_led.request(config)

config.consumer = "YELLOW LED" 
# применяем настройки к 13 линии
Y_led.request(config)

config.consumer = "GREEN LED" 
# применяем настройки к 15 линии
G_led.request(config)

# подаем низкое напряжение на все линии
R_led.set_value(0)
Y_led.set_value(0)
G_led.set_value(0)

# запускаем "бесконечный" цикл работы светофора
while True:
    # последовательно выполняем алгоритм работы светофора
    # включаем зеленый сигнал
    G_led.set_value(1)
    # ждем 2 минуты
    time.sleep(G_SIGNAL)
    # выключаем зеленый сигнал
    G_led.set_value(0)
    # мигаем 3 раза зеленым сигналом
    for i in range(3):
        G_led.set_value(1)
        time.sleep(G_BLINK_SIGNAL)
        G_led.set_value(0)
        time.sleep(G_BLINK_SIGNAL)
    # зажигаем желтый сигнал на 3 сек
    Y_led.set_value(1)
    time.sleep(Y_BLINK_SIGNAL)
    Y_led.set_value(0)
    # зажигаем красный сигнал на 3 мин
    R_led.set_value(1)
    time.sleep(R_LED_SIGNAL)
    # зажигаем красный и желтый на 3 сек
    Y_led.set_value(1)
    time.sleep(RY_LED_SIGNAL)
    # гасим красный и желтый, переходим к следующему шагу цикла работы светофора
    R_led.set_value(0)
    Y_led.set_value(0)

# КОНЕЦ ПРОГРАММЫ

Шаг 4. Запустите программу на выполнение. Проверьте тайминги подачи сигнала и их очередность. Завершите работу программы комбинацией клавиш Ctrl+C или нажмите соответствующую кнопку в IDE.

Задания для самостоятельной работы:

  1. После остановки программы проверьте с помощью утилиты gpioinfo состояние линий.
  2. Внесите изменения в программу, чтобы красный и зеленый сигналы светофора работали 1 и 1,5 минуты соответственно. Сделайте вывод о целесообразности использования переменных для хранения значений параметров работы проектируемого устройства.
  3. (*) Добавьте в схему еще три светодиода (красный, желтый и зеленый) для второго светофора, который должен работать в противофазе первому. Подключите их к свободным контактам, руководствуясь справочной таблицей из первой части статьи. Внесите изменения в программу для их одновременной работы на одном перекрестке для разных потоков. Проверьте правильность работы светофора, будет обидно, если из-за ошибки в коде будут случаться ДТП.

2. Сдвиговый регистр 74HC595N #

При реализации схем прототипов электронных устройств или реализации проектов “умный” дом, как на контроллерах, так и на одноплатных компьютерах, рано или поздно, возникает одна и таже проблема, это недостаточное количество цифровых выходов. И даже Repka Pi 3 не является исключением, так например при использовании первого варианта распиновки мы имеем доступ к максимально возможному количеству цифровых выходов - 24 (+2 на страх и риск), но если возникнет необходимость использовать 6 вариант (появился в версии ОС 1.0.15), то останется довольствоваться только 11 выходами. При этом, скорее всего, часть выходов необходимо будет задействовать как входы. Для примера, односекционный ЖК-дисплей имеет 8 контактов, а светодиодная матрица 8х8 аж целых 16 контактов.

Что такое сдвиговый регистр? #

Сдвиговый регистр 74HC595N - это 8 битная цифровая схема, позволяющая увеличивать количество цифровых выходов. Одна схема управляется с помощью 3 контактов, при этом позволяет управлять 8 устройствами. Регистры 74HC595N могут объединяться каскадно, кратно увеличивая количество цифровых выходов, при этом количество задействованных контактов для управление ими остается неизменным.

Рис. 4. Схема расположения ножек сдвигового регистра 74HC595

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

  • Q0-Q7 - выходы разрядов
  • VCC - плюс питания
  • GND - общий (земля)
  • DS - вход последовательных данных (DATA) восемь бит: единица - включить, ноль - выключить
  • ST-CP - тактовый вход регистра сдвига (CLOCK), тактирование занимает отдельную линию, однако позволяет не привязываться к строгим таймингам, что значительно повышает надежность и помехоустойчивость передачи данных, а также позволяет работать с любой скоростью, которую обеспечивает программа и контроллер (процессор)
  • SH-CP - тактовый вход регистра хранения, так называемая “защелка” (LATCH), позволяет (после сессии передачи данных) устанавливать уровни на всех восьми выходных ножках одновременно
  • Q7’ - выход переноса, к нему подключается входной DS следующего регистра каскада, тактовые сигналы подключаются ко всем регистрам параллельно.

Алгоритм записи в регистр (программная реализация интерфейса SPI):

  1. Открываем “защелку“, подаем на ST_CP низкое напряжение (0);
  2. подаем на DS высокое (1) или низкое (0) напряжение;
  3. Синхронизируем линию, подаем на ST-CP высокое напряжение (1);
  4. Подаем на SH-CP и DS низкое напряжение (0);
  5. Повторяем пп. 2-4 для оставшихся 7 бит;
  6. Закрываем “защелку“, подаем на ST_CP высокое напряжение (1).

Примечание: каскадное подключение регистров 74HC595 и алгоритм работы с ними будут добавлены в эту статью позднее.

Схема подключения регистра к контактам Repka Pi 3 #

Рассмотрим вариант подключения регистра 74HC595 к Repka Pi 3 на примере схемы управления 8 светодиодами (рис. 5).

Примечание: для улучшения читаемости схемы крайний правый светодиод подключен к ножке Q0, а самый левый к ножке Q7. Данная особенность подключения влияет на порядок передачи бит в регистр.

Рис. 5. Макет схемы управления 8 светодиодами с помощью регистра 74HC595.

Задание 2.1. Соберите схему представленную на рисунке 5.

Для выполнения задания вам понадобятся: Repka Pi 3, макетная плата, четыре красных и четыре зеленых светодиода, восемь резисторов 220 Ом, комплект проводов мама-папа для подключения макетной платы к GPIO-разъему и комплект проводов папа-папа для соединений элементов на макетной плате.

Запитайте макетную плату от 3,3В (разъем 1), а “Землю“ подключите к разъему 6;

Ножку регистра DS (синий провод) подключите к разъему 32;

Ножку регистра ST-CP (зеленый провод) подключите к разъему 38;

Ножку регистра SH-CP (желтый провод) подключите к разъему 40;

Расположите элементы на макетной плате и соедините их проводами в соответствии со схемой.

Примечание: при отсутствии проводов указанного на схеме цвета или недостаточном их количестве замените их на провода других цветов.

Задание 2.2 “Проверка работы регистра 74HC595”.

Шаг 1. Введите код программы:

import gpiod # подключаем библиотеку для работы с libgpiod
import time # подключаем библиотеку для работы со временем

# Присваиваем номера линий переменным
DS_PIN = 11
STCP_PIN = 15
SHCP_PIN = 14

# Получаем доступ к контроллерам и линиям
chip0 = gpiod.chip("gpiochip0")
ds = chip0.get_line(DS_PIN)

chip1 = gpiod.chip("gpiochip1")
stcp = chip1.get_line(STCP_PIN)
shcp = chip1.get_line(SHCP_PIN)

# функция, реализующая интерфейс SPI для записи значений бит в регистр
# значения бит передаются в виде списка из 8 элементов
# каждый элемент может иметь значение 0 или 1
def writeToChip(pins):
    # инвертируем порядок следования бит (см. примечание к схеме)
    pins.reverse()
    for i in range(8):
        # Используем значение элемента списка для линии DS
        ds.set_value(pins[i])
        # Синхронизируем линию, подаем на ST-CP высокое напряжение
        shcp.set_value(1)
        # Подаем на SH-CP и DS низкое напряжение
        shcp.set_value(0)
        ds.set_value(0)
    # Закрываем “защелку“, подаем на ST_CP высокое напряжение
    stcp.set_value(1)
    # Подготовим регистр к приему новых данных
    # Открываем “защелку“, подаем на ST_CP низкое напряжение
    stcp.set_value(0)

# функций инициализации линий GPIO
def init():
    # настройка параметров линий
    config = gpiod.line_request()
    config.request_type = gpiod.line_request.DIRECTION_OUTPUT

    config.consumer = "DS"
    ds.request(config)

    config.consumer = "STCP"
    stcp.request(config)

    config.consumer = "SHCP"
    shcp.request(config)

    # Подаем на DS низкое напряжение
    ds.set_value(0)
    # Подаем на SH-CP низкое напряжение
    shcp.set_value(0)
    # Подготовим регистр к получению данных
    # Открываем “защелку“, подаем на ST_CP низкое напряжение
    stcp.set_value(0)

# ***
# НИЖЕ ДОБАВЛЯЕМ НОВЫЕ ФУНКЦИИ,
# РЕАЛИЗУЮЩИЕ АЛГОРИТМЫ УПРАВЛЕНИЯ СВЕТОДИОДАМИ
# ***

# функция, реализующая алгоритм включение и выключение всех 8 светодиодов
def blinkLeds():
    # для включения всех светодиодов
    # генерируем список из 8 элементов, содержащий только 1
    pins = [1 for i in range(8)]
    # записываем значения в регистр
    writeToChip(pins)
    # ждем 1 секунду
    time.sleep(1)
    # для выключения всех светодиодов
    # генерируем список из 8 элементов, содержащий только 0
    pins = [0 for i in range(8)]
    # записываем значения в регистр
    writeToChip(pins)
    # ждем 1 секунду
    time.sleep(1)

# ***
# КОНЕЦ БЛОКА ФУНКЦИИ,
# РЕАЛИЗУЮЩИХ АЛГОРИТМЫ УПРАВЛЕНИЯ СВЕТОДИОДАМИ
# ***


# функция, реализующая основной цикл приложения
def run():
    while True:
        # здесь вызываем функции, реализующие алгоритмы управление светодиодами
        blinkLeds() # запускаем режим мигания всех светодиодов
        

# точка входа в программу
if __name__ == "__main__":
    # инициализация контроллеров и линий
    init()
    # основной цикл приложения
    run()

# КОНЕЦ ПРОГРАММЫ

Шаг 2. Запустите программу. Все 8 светодиодов должны одновременно загораться и гаснуть в соответствии с заданными интервалами.

Примечание: в целях сокращения объема листинга, далее в примерах будет приводится только текст функций, реализующей алгоритм управления светодиодами и функция, реализующая основной цикл приложения (то что изменяется). В конце раздела приведен полный листинг приложения. Представленные в примерах функции управления светодиодами желательно вводить в раздел помеченный соответствующим комментарием.

Внимание! Задания для самостоятельной работы в данном разделе будут добавлены в ближайшее время.

Задание 2.3 “Четное не четное“.

Шаг 1. Введите код программы:

...

# Функция, реализующая алгоритм включения только четных светодиодов
def evenLeds():
    pins = [(i % 2) for i in range(8)]
    writeToChip(pins)

# Функция, реализующая алгоритм включения только нечетных светодиодов
def oddLeds():
    pins = [not(i % 2) for i in range(8)]
    writeToChip(pins)

# функция, реализующая основной цикл приложения
def run():
    while True:
        # здесь вызываем функции, реализующие алгоритмы управление светодиодами
        evenLeds() # зажигаем только четные светодиоды
        oddLeds() # зажигаем только нечетные светодиоды
...

Шаг 2. Запустите программу. При выполнении программы должны сначала светить 4 нечетных по порядку слева на право светодиода, затем 4 четных.

Задание 2.4 “Карусель“.

Шаг 1. Введите код программы:

...

# Функция, реализующая алгоритм включения светодиодов "каруселью"
def carouselLeds():
    # Цикл для смещения активного элемента
    for i in range(8):
        # генерируем список из 8 элементов, содержащий только один элемент с 1
        leds = [(i == j) for j in range(8)]
        # записываем значения в регистр
        writeToChip(leds)
        # ждем 500 миллисекунд
        time.sleep(0.5)

def run():
    while True:
        # здесь вызываем функции, реализующие алгоритмы управление светодиодами
        carouselLeds() # зажигаем светодиоды каруселью
...

Шаг 2. Запустите программу. При работе программы одновременно должен светить только один светодиод, последовательное включение светодиодов должно осуществляться слева на право.

Задание 2.5 “Цветная карусель“.

Шаг 1. Введите код программы:

...

# Функция, реализующая алгоритм включения светодиодов "каруселью" по их цветам
# параметр isIner задает направление карусели True - во внутрь, False - наружу
def halfLeds(isIner: bool):
    # Цикл для смещения активного элемента
    for i in range(4):
        # генерируем список из 4 элементов (красных),
        # содержащий только один активный элемент
        left_leds = [(i == j) for j in reversed(range(4))]
        
        # генерируем список из 4 элементов (зеленых),
        # содержащий только один активный элемент
        rigth_leds = [(i == j) for j in range(4)]
        
        # объединяем массивы в один,
        # порядок зависит от направления карусели
        if isIner:
            writeToChip(rigth_leds + left_leds)
        else:
            writeToChip(left_leds + rigth_leds)
        # ждем 500 миллисекунд
        time.sleep(.5)
    
# ***
# КОНЕЦ БЛОКА ФУНКЦИИ,
# РЕАЛИЗУЮЩИХ АЛГОРИТМЫ УПРАВЛЕНИЯ СВЕТОДИОДАМИ
# ***

# функция, реализующая основной цикл приложения
def run():
    while True:
        # здесь вызываем функции, реализующие алгоритмы управление светодиодами
        halfLeds(False) # зажигаем светодиоды каруселью (наружу) по цветам
        halfLeds(True) # зажигаем светодиоды каруселью (вовнутрь) по цветам 
...

Шаг 2. Запустите программу. Результат должен быть аналогичен результату в задании 2.4, только с разделением карусели по цветам.

Полный листинг программы:

import gpiod # подключаем библиотеку для работы с libgpiod
import time # подключаем библиотеку для работы со временем

# Присваиваем номера линий переменным
DS_PIN = 11
STCP_PIN = 15
SHCP_PIN = 14

# Получаем доступ к контроллерам и линиям
chip0 = gpiod.chip("gpiochip0")
ds = chip0.get_line(DS_PIN)

chip1 = gpiod.chip("gpiochip1")
stcp = chip1.get_line(STCP_PIN)
shcp = chip1.get_line(SHCP_PIN)

# функция, реализующая интерфейс SPI для записи значений бит в регистр
# значения бит передаются в виде списка из 8 элементов
# каждый элемент может иметь значение 0 или 1
def writeToChip(pins):
    # Так как ножки регистра на схеме инвертированы (Q7 - 1, ..., Q0 - 8)
    # Заменим порядок передачи бит в регистр
    pins.reverse()
    # Записываем значения элементов списка в регистр
    for i in range(8):
        # Используем значение элемента списка для линии DS
        ds.set_value(pins[i])
        # Синхронизируем линию, подаем на ST-CP высокое напряжение
        shcp.set_value(1)
        # Подаем на SH-CP и DS низкое напряжение
        shcp.set_value(0)
        ds.set_value(0)
    # Закрываем “защелку“, подаем на ST_CP высокое напряжение
    stcp.set_value(1)
    # Подготовим регистр к приему новых данных
    # Открываем “защелку“, подаем на ST_CP низкое напряжение
    stcp.set_value(0)

# функций инициализации линий GPIO
def init():
    # настройка параметров линий
    config = gpiod.line_request()
    config.request_type = gpiod.line_request.DIRECTION_OUTPUT

    config.consumer = "DS"
    ds.request(config)

    config.consumer = "STCP"
    stcp.request(config)

    config.consumer = "SHCP"
    shcp.request(config)

    # Подаем на DS низкое напряжение
    ds.set_value(0)
    # Подаем на SH-CP низкое напряжение
    shcp.set_value(0)
    # Подготовим регистр к получению данных
    # Открываем “защелку“, подаем на ST_CP низкое напряжение
    stcp.set_value(0)

# ***
# НИЖЕ ДОБАВЛЯЕМ НОВЫЕ ФУНКЦИИ,
# РЕАЛИЗУЮЩИЕ АЛГОРИТМЫ УПРАВЛЕНИЯ СВЕТОДИОДАМИ
# ***

# функция, реализующая алгоритм включение и выключение всех 8 светодиодов
def blinkLeds():
    # для включения всех светодиодов
    # генерируем список из 8 элементов, содержащий только 1
    pins = [1 for i in range(8)]
    # записываем значения в регистр
    writeToChip(pins)
    # ждем 1 секунду
    time.sleep(1)
    # для выключения всех светодиодов
    # генерируем список из 8 элементов, содержащий только 0
    pins = [0 for i in range(8)]
    # записываем значения в регистр
    writeToChip(pins)
    # ждем 1 секунду
    time.sleep(1)
    

# Функция, реализующая алгоритм включения светодиодов "каруселью"
def carouselLeds():
    # Цикл для смещения активного элемента
    for i in range(8):
        # генерируем список из 8 элементов, содержащий только один элемент с 1
        leds = [(i == j) for j in range(8)]
        # записываем значения в регистр
        writeToChip(leds)
        # ждем 500 миллисекунд
        time.sleep(0.5)

# Функция, реализующая алгоритм включения только четных светодиодов
def evenLeds():
    pins = [(i % 2) for i in range(8)]
    writeToChip(pins)

# Функция, реализующая алгоритм включения только нечетных светодиодов
def oddLeds():
    pins = [not(i % 2) for i in range(8)]
    writeToChip(pins)

# Функция, реализующая алгоритм включения светодиодов "каруселью" по их цветам
# параметр isIner задает направление карусели True - во внутрь, False - наружу
def halfLeds(isIner: bool):
    # Цикл для смещения активного элемента
    for i in range(4):
        # генерируем список из 4 элементов (красных),
        # содержащий только один активный элемент
        left_leds = [(i == j) for j in reversed(range(4))]
        
        # генерируем список из 4 элементов (зеленых),
        # содержащий только один активный элемент
        rigth_leds = [(i == j) for j in range(4)]
        
        # объединяем массивы в один,
        # порядок зависит от направления карусели
        if isIner:
            writeToChip(rigth_leds + left_leds)
        else:
            writeToChip(left_leds + rigth_leds)
        # ждем 500 миллисекунд
        time.sleep(.5)
    
# ***
# КОНЕЦ БЛОКА ФУНКЦИИ,
# РЕАЛИЗУЮЩИХ АЛГОРИТМЫ УПРАВЛЕНИЯ СВЕТОДИОДАМИ
# ***

# функция, реализующая основной цикл приложения
def run():
    while True:
        # здесь вызываем функции, реализующие алгоритмы управление светодиодами
        blinkLeds() # запускаем режим мигания всех светодиодов
        evenLeds() # зажигаем только четные светодиоды
        oddLeds() # зажигаем только нечетные светодиоды
        carouselLeds() # зажигаем светодиоды каруселью
        halfLeds(False) # зажигаем светодиоды каруселью (наружу) по цветам
        halfLeds(True) # зажигаем светодиоды каруселью (наружу) по цветам 

# точка входа в программу
if __name__ == "__main__":
    # инициализация линий
    init()
    # основной цикл приложения
    run()

# КОНЕЦ ПРОГРАММЫ

3. Электромагнитное реле #

Что такое электромагнитное реле? #

Электромагнитное реле - это реле позволяющее подключить устройства, работающие в режимах с относительно большими токами (10-15А) или напряжением (~125-220В), которые не могут быть подключены к плате Repka Pi 3 напрямую. Например, мощные насосы, электродвигатели, электронагреватели, лампочки накаливания и т.д. Общий вид реле представлен на рисунке 6.

Рис. 6. Электромагнитное реле.

Примечание: вход реле инвертирован, поэтому высокий уровень на контакте “сигнал“ выключает катушку, а низкий – включает.

Схема подключения реле к контактам Repka Pi 3 #

На рисунке 7 приведен пример использования электромагнитного реле для управления лампой накаливания, работающей от напряжения ~220В.

Рис. 7. Макет схемы управления лампой накаливания.

Важно! Из соображений безопасности, данный пример не целесообразно рассматривать на занятиях с детьми. Для изучения работы реле можно воспользоваться функцией “прозвона“ сети на мультиметре.

Задание 3.1 “Щелк-Щелк“.

Шаг 1. Введите код программы:

import gpiod # подключаем библиотеку для работы с libgpiod
import time # подключаем библиотеку работы со временем

LED_CHIP = 1 # номер используемого контроллера
LED_LINE_OFFSET = 6 # номер используемой линии

chip = gpiod.chip(LED_CHIP) # получаем доступ к контроллеру 1
line = chip.get_line(LED_LINE_OFFSET) # получаем доступ к линии 6

# получаем структуру для настройки линии
config = gpiod.line_request() 

# указываем название линии
config.consumer = "Rele" 
# задаем направление работы линии
config.request_type = gpiod.line_request.DIRECTION_OUTPUT 
# применяем настройки к линии
line.request(config)

# устанавливаем высокое напряжение в линии (выключаем реле)
line.set_value(1)
# ждем 1 секунду
time.sleep(1)
# устанавливаем низкое напряжение в линии (включаем реле)
line.set_value(0)
# ждем 1 секунду
time.sleep(1)
# устанавливаем высокое напряжение в линии (выключаем реле)
line.set_value(1)

# КОНЕЦ ПРОГРАММЫ

Шаг 2. Запустите программу. Во время включения/выключения реле должны быть слышны щелчки в соответствии с установленными таймингами.

Заключение #

В следующей статье “Часть 3. Программное управление линиями GPIO Repka Pi 3 в режиме ввода с примерами на Python (libgpiod)” изучим работу с кнопками и магнито-контактными извещателями, рассмотрим примеры программного включения подтяжки и обработку событий.


Комментарии (0)

Для участия в обсуждении Вы должны быть авторизованным пользователем
Темы

Навигация

ВойтиРегистрация