Skip to content
  • Категории
  • Главная
  • Документация
  • Последние
  • Пользователи
Collapse
  1. Главная
  2. Блоги сообщества Raspberry Pi
  3. GPIO для чайников (часть 5)

GPIO для чайников (часть 5)

Запланировано Прикреплена Закрыта Перенесена Блоги сообщества Raspberry Pi
15 Сообщения 2 Posters 356 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • R Не в сети
    R Не в сети
    RomanNV5
    написал в отредактировано pi
    #1

    Снова возвращаемся к кнопкам и создаём первое полезное приложение.

    Во второй части статей «GPIO для чайников» мы подключали кнопку между двумя портами. Один порт устанавливали на «вывод» и в состояние «1», а другим портом читали эту «1» через кнопку. При отпущенной кнопке на втором порту читался «0», а при нажатой- «1».
    917b22bc-3308-4ccd-88a7-df5e6778142e-image.png
    Всё вроде бы работало. Но недавно у такого способа подключения обнаружился один неприятный недостаток. Такое подключение кнопки оказалось неустойчивым к помехам. Когда я свою RPI подключил к сети при помощи Wi-Fi USB донгла, то все программы, в которых использовалось такое включение кнопки, просто сошли с ума. RPI детектировал нажатие кнопки даже тогда, когда к ней никто не притрагивался. Виной всему оказался длинный провод, которым была подключена кнопка к RPI. Работающий Wi-Fi адаптер наводил на нём потенциал, с уровнем достаточным для детектирования «1» на порте GPIO. Такое поведение кнопки никуда не годится.

    Нужно принимать меры по помехозащищённости. В данном случае поможет использование экранированного провода до кнопки, либо даже простое уменьшение длины проводов, соединяющих кнопку с RPI. Но можно поступить проще. Раз наш RPI реагирует на помехи при отсутствии сигнала на входе, то разумным решением будет перевести порт, которым мы читаем состояние кнопки в состояние логической «1». Раз на нём всегда будет «1», то уже никакая помеха не сможет этот порт перевести в «0». А значит, наш порт станет невосприимчивым к помехам.

    Давайте подключим нашу кнопку по такой схеме:

    096ae400-849c-4ba5-bbf1-78517a531dd4-image.png

    Если вы использовали кнопку от системного блока с коннектором BLS, то достаточно его просто развернуть на 90 градусов. Теперь наша кнопка подключена к порту Р1-05 и к пину «GND» (земля, или 0 по русски).

    Ну и напишем такую простенькую программу button1.c

    // Проверка работоспособности кнопки, подключённой
    // к порту Р1_05 и GND. 
    // Компиляция: gcc -o button1 button1.c -lbcm2835 -lrt
    // Исполнение: sudo ./button1
    
    #include <stdio.h>
    #include <bcm2835.h>
    #define PIN_IN RPI_GPIO_P1_05  
    //#define PIN_IN RPI_V2_GPIO_P1_05  // Для RPI ревизии v2 раскомментировать эту строку и удалить предыдущую
    int main()
    {
      if (!bcm2835_init())   // Инициализация GPIO
      return 1;              //Завершение программы, если инициализация не удалась
       
    bcm2835_gpio_fsel(PIN_IN, BCM2835_GPIO_FSEL_INPT); // Порт на ввод
    printf(&quot;Ждём нажатия на кнопку.\n&quot;);
    while(bcm2835_gpio_lev(PIN_IN))   // Повторяем все действия, заключённые в скобки {} пока не будет нажата кнопка
            {}
            printf("Кнопочка нажата!\n");
    
            return (bcm2835_close ());     // Выход из программы
    }
    

    Компилируем и запускаем. Убеждаемся, что наша кнопка, включённая таким образом, действительно работает. Можно после запуска программы повертеть провод перед Wi-Fi донглом и убедиться, что RPI никак на него не реагирует, а реагирует только на нажатую кнопку.

    А теперь разберёмся, как это работает.

    Если мы зайдём на страницу http://elinux.org/RPi_Low-level_peripherals то в таблице «Header Pinout,bottom row:» мы увидим такое описание портов:
    Screenshot from 2024-12-24 05-26-51.png
    Мы видим, что в описании порта Р1-05 написано «1K8 pull up resistor». Это значит, что в RPI вывод этого порта подключён к шине +3,3в через резистор сопротивлением 1,8кОм. Это называется подтяжкой. А раз этот порт подключён к +3,3в, то это значит, что в любом состоянии на входе этого порта будет присутствовать логическая «1». Если мы теперь с учётом этой информации перерисуем схему подключения нашей кнопки, то она у нас будет выглядеть вот так:

    89966b10-70c4-4e68-b618-3b622bb938bf-image.png

    Теперь мы видим, что если кнопка не нажата, то с порта мы будем считывать «1». А когда мы нажмём на кнопку, то мы замкнём вход порта с «землёй», а значит, получим на входе в порт логический «0». Т.е. нам теперь, чтобы отследить нажатие на кнопочку, нужно просто ждать, когда на порте появится «0». Собственно чем наша выше написанная программа и занимается.

    Цикл while(bcm2835_gpio_lev(PIN_IN)){} повторяется до тех пор, пока функция bcm2835_gpio_lev(PIN_IN) не вернёт в программу «0». Мы эту функцию уже использовали раньше в наших программах, только там был ещё оператор инвертирования результата, в виде восклицательного знака перед функцией, что означало, что мы ждём возвращения «1». Тут же мы ждём возвращения «0», по этому от инверсии мы избавились.

    При замкнутой кнопке у нас через резистор течёт небольшой ток I=U/R=3,3/1800=1,8мА. Ток этот очень маленький, что практически никак не скажется на потребляемой RPI мощности. Как видим, это очень удачный способ подключения кнопки к RPI. Мало того, что он очень помехоустойчивый (ведь помеха может навести в проводе ток, но вот избавить провод от тока она не в состоянии), так ещё мы освободили целый порт для любых других нужд. Одна кнопка- один порт.

    Но, разумеется, это совершенно не значит, что наша первая схема подключения кнопки оказалась никуда негодной. Например, подключить матричную клавиатуру можно лишь первым способом. Тогда например, для подключения клавиатуры 4х4 кнопки нам понадобится всего 8 портов. Если же мы попытаемся подключить такую клавиатуру по нашему сегодняшнему способу, то мы займём 16 портов GPIO. И тем не менее, для всех остальных случаев, нашу сегодняшнюю схему подключения можно считать оптимальной.

    Теперь мы знаем, что благодаря наличию подтяжки на порту Р1-05, мы можем легко использовать этот порт для подключения кнопки. Так же из таблицы следует, что подтяжкой обладает ещё и порт Р1-03. И мы можем точно так же подключить к нему ещё одну кнопочку. Возникает резонный вопрос: «А если я хочу подключить, скажем, 3 кнопочки, а портов с подтяжкой всего 2, как быть?». Ответ прост- можно выполнить подтяжку любого порта самостоятельно, впаяв дополнительный резистор на своей плате и соединив им любой другой порт GPIO с +3,3в. К стати, сопротивление этого резистора не обязано быть именно 1,8кОм. Схема будет прекрасно работать и с резистором в 10кОм. Значит нам можно поставить в цепь подтяжки порта любой резистор сопротивлением от 1,8 кОм и до 10-12кОм. Но не торопитесь бежать за паяльником. У RPI маленькие секреты ещё не закончились. Попробуем обойтись без самодельной подтяжки.

    Для начала предлагаю провести маленький эксперимент. Давайте подключим нашу кнопку к портам Р1-13 и Р1-14. Р1-13, это обычный порт GPIO, а Р1-14, это GND. Собственно у нас ничего не изменилось. Всё так же наша кнопка подключена между портом GPIO и GND, за исключением того, что этот порт не имеет резистора подтяжки. Изменим нашу программу button1.c заменив определение порта Р1-05 на Р1-13. Откомпилируем программу и запустим её. Мы видим, что она не работает должным образом. Программа считает, что кнопка нажата, хотя мы к ней и не притрагивались. А всё потому, что отсутствует подтяжка порта и на нём всё время находится «0». А по логике работы нашей программы, наличие «0» на порту говорит о нажатии кнопки.

    Пришло время вспомнить о том, что я говорил в первой части статей «GPIO для чайников». А говорил я о том, что внутри процессора BCM2835

    порты GPIO имеют возможность подключения внутренними резисторами подтяжки как к +3,3в, так и к 0 (или GND). Так почему бы нам не воспользоваться этим чудесным свойством в своих корыстных целях? Для воплощения нашей задумки нам достаточно лишь включить подтяжку порта Р1-13 к +3,3в. Тогда наша схема подключения кнопки автоматически превратится в такую:

    f287c1b1-3dcf-426e-840e-eb5ec7fff32d-image.png

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

    Для включения подтягивающего резистора существует функция

    void bcm2835_gpio_set_pud (uint8_tpin, uint8_t pud)
    

    где:
    pin - номер порта, к которому мы применяем данную функцию;
    pud - управляющая команда, включающая нужный нам режим подтяжки (0- подтяжка отключена, 1- подтяжка к GND, 2- подтяжка к +3,3в).

    Ну что ж, добавим эту функцию в нашу программу. Теперь она должна выглядеть так:

    // Проверка работоспособности кнопки, подключённой
    // к порту Р1_13 и GND. 
    // Компиляция: gcc -o button2 button2.c -lbcm2835 -lrt
    // Исполнение: sudo ./button2
    
    #include 'stdio.h'
    #include 'bcm2835.h'
    
    #define PIN_IN RPI_GPIO_P1_13  
    //#define PIN_IN RPI_V2_GPIO_P1_13  // Для RPI ревизии v2 раскомментировать эту строку и удалить предыдущую
    
    int main()
    {
            if (!bcm2835_init())   // Инициализация GPIO
            return 1;              //Завершение программы, если инициализация не удалась
    
            bcm2835_gpio_fsel(PIN_IN, BCM2835_GPIO_FSEL_INPT); // Порт на ввод
    
            bcm2835_gpio_set_pud(PIN_IN, 2); // Включаем подтяжку порта к +3,3в
    
            printf(&quot;Ждём нажатия на кнопку.\n&quot;);
    
            while(bcm2835_gpio_lev(PIN_IN))   // Повторяем все действия, заключённые в скобки {} пока не будет нажата кнопка
            {}
    
            printf(&quot;Кнопочка нажата!\n&quot;);
    
            bcm2835_gpio_set_pud(PIN_IN, 0); // Отключаем подтяжку порта
    
            return (bcm2835_close ());     // Выход из программы
    
    }
    

    Сохраним нашу программу под именем button2.c , скомпилируем и запустим. Всё, теперь наша программа адекватно реагирует на нажатие кнопки.

    Ну вот, теперь вы знаете ещё полтора способа подключения кнопки к RPI.

    Настало время испытать наши знания в деле. На этот раз мы не будем играть с моргающими светодиодами. Наших знаний уже вполне достаточно, чтобы превратить RPI в самостоятельное, работающее, законченное устройство, которое сможет выполнять уже полезную работу. Предлагаю превратить наш RPI в интрнет-радио! Причём это «радио» должно быть автономным, т.е. обходиться без клавиатуры, мыши и монитора. А управлять мы им будем при помощи кнопочек, которые мы только что научились подключать к RPI.

    Некоторые пояснения.

    В связи с тем, что библиотека bcm2835 периодически обновляется, то в неё вносятся изменения, которые могут повлиять на работоспособность ранее написанных примеров.

    Так, на сегодняшний день доступна библиотека версии 1.16.

    Если вы установили себе библиотеку более новой версии, чем 1.8 (установка которой описана в первой статье "GPIO для чайников"), то у вас может возникнуть проблема с компиляцией написанных программ.

    Например при компиляции может вылезти сообщение:

    /usr/local/lib/libbcm2835.a(bcm2835.o): In function `bcm2835_delayMicroseconds':
    /home/pi/bcm2835-1.15/src/bcm2835.c:350: undefined reference to `clock_gettime'
    /home/pi/bcm2835-1.15/src/bcm2835.c:360: undefined reference to `clock_gettime'
    collect2: ld returned 1 exit status
    

    Чтобы обойти эту проблемму, достаточно при компиляции добавить опцию -l rt

    Т.е., если раньше мы компилировали нашу программу button командой:

    gcc -o button button.c -l bcm2835
    

    то теперь нужно писать так:

    gcc -o button button.c -lbcm2835 -lrt
    

    Просто автор библиотеки в более новых версиях модифицировал функцию bcm2835_delayMicroseconds, которая теперь учитывает скорость выполнения команд процессором и ей требуется обращение к real-time функциям.

    Если вы владелец Raspberry PI Version2:

    Для ревизии платы Raspberry PI v2 необходимо изменять определения портов GPIO.

    Например, если мы для ревизии v1 писали определение для порта Р1_03 так:

    #define PIN RPI_GPIO_P1_03
    

    то для ревизии v2 эта строка должна выглядеть вот так:

    #define PIN RPI_V2_GPIO_P1_03
    

    Т.е. для определения любых портов ревизии v2 нужно добавлять в запись "_V2" между "RPI" и "_GPIO"

    В прочем, это необходимо только тогда, когда вы используете в своих проектах порты с номерами: Р1-03, Р1-05 и Р1-13.

    Для других портов это не имеет никакого значения, какое определение вы используете, т.к. остальные порты GPIO совпадают в обеих ревизиях.

    Зато в ревизии v2 вывели дополнительно 4 новых порта на разъём Р5. Этих портов нет в ревизии v1 вобще. Обладатели же ревизии v2 могут использовать эти порты абсолютно так же, как и прочие. Номера этих портов: Р5-03, Р5-04, Р5-05 и Р5-06.

    Соответственно псевдонимами этих портов будут:

    RPI_V2_GPIO_P5_03
    RPI_V2_GPIO_P5_04  
    RPI_V2_GPIO_P5_05  
    RPI_V2_GPIO_P5_06
    
    1 ответ Последний ответ
    0
    • piP Не в сети
      piP Не в сети
      pi
      написал в отредактировано
      #2

      Нравятся мне ваши статьи. Разжёвано так всё всегда хорошо.
      Вам в школы/университеты надо идти преподавать

      1 ответ Последний ответ
      0
      • piP Не в сети
        piP Не в сети
        pi
        написал в отредактировано
        #3

        Спасибо. С нетерпением ждем продолжение.

        1 ответ Последний ответ
        0
        • piP Не в сети
          piP Не в сети
          pi
          написал в отредактировано pi
          #4

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

          if (bcm2835_gpio_eds(PIN))
          		{
          			// Now clear the eds flag by setting it to 1
          			bcm2835_gpio_set_eds(PIN);
          			printf(&quot;low event detect for pin 15\n&quot;);
          		}
          		// wait a bit
          		delay(500);
          

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

          while (1)
          	{
          delay(500);
                      }
          

          Инициализировалось это самое прерывание(на кнопочку например нажали) и программа заканчивает обрабатывать предыдущий delay и САМА(без опроса) запускает функцию ту которую мы обозначили.

          1 ответ Последний ответ
          0
          • piP Не в сети
            piP Не в сети
            pi
            написал в отредактировано
            #5

            Не совсем понял почему, когда нажимаем кнопку, то с порта P1-05 мы будем считывать ноль? Ведь на него же подается напряжение +3.3 В

            1 ответ Последний ответ
            0
            • piP Не в сети
              piP Не в сети
              pi
              написал в отредактировано
              #6

              3.3В присутствует всегда, это логическая 1, а когда конпка нажимается, то на порту появляется логический 0, т.к. 3,3В ушли на землю.

              1 ответ Последний ответ
              0
              • piP Не в сети
                piP Не в сети
                pi
                написал в отредактировано
                #7

                По схеме GPIO --1K8 pull up resistor-- имеют только P1-03 и P1-05... P1-13 не имеет внутренней подтяжки.. Соответственно включать нечего..

                1 ответ Последний ответ
                0
                • piP Не в сети
                  piP Не в сети
                  pi
                  написал в отредактировано
                  #8

                  А точно подтяжка у P1-05 через 1K8 pull up resistor на 3,3 В.. Или через 1K8 pull up на GND. тэ е. Куда именно подтяжка на землю или на питание 3.3 В?

                  1 ответ Последний ответ
                  0
                  • piP Не в сети
                    piP Не в сети
                    pi
                    написал в отредактировано
                    #9

                    Вопрос закрыт. Up значит вверх...к питанию...

                    1 ответ Последний ответ
                    0
                    • piP Не в сети
                      piP Не в сети
                      pi
                      написал в отредактировано
                      #10

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

                      1 ответ Последний ответ
                      0
                      • piP Не в сети
                        piP Не в сети
                        pi
                        написал в отредактировано
                        #11

                        Схема подключения кнопки в самом начале — это я даже не знаю как назвать. Такое даже любителю в голову не придёт. А уж в качестве «познавательного» материала это вообще нельзя показывать, это не может быть учебным материалом. Вы бы лучше это убрали и не позорились!
                        И где защита от дребезга контактов кнопки? В примере при нажатии кнопки просто выход из программы — прокатит, но если вы будете управлять программой, то такие фортели получите, мама не горюй! Стыдно должно быть такие «учебные» материалы выкладывать.

                        1 ответ Последний ответ
                        0
                        • piP Не в сети
                          piP Не в сети
                          pi
                          написал в отредактировано
                          #12

                          Есть ли разница как работать с пином: 3.3В + «Пин» или «Пин» + «Земля»?

                          1 ответ Последний ответ
                          0
                          • piP Не в сети
                            piP Не в сети
                            pi
                            написал в отредактировано
                            #13

                            То, что логика инвертируется — понятно.

                            1 ответ Последний ответ
                            0
                            • piP Не в сети
                              piP Не в сети
                              pi
                              написал в отредактировано
                              #14

                              Всем привет.
                              есть raspberry pi3 нужно собрать монтажную плату и подключить пару кнопок.
                              за вознаграждение.
                              пишите если у кого есть желание.

                              1 ответ Последний ответ
                              0
                              • piP Не в сети
                                piP Не в сети
                                pi
                                написал в отредактировано
                                #15

                                Блин.. да какие же суки кругом статьи пишут.. открываешь, читаешь, надо ко ко ко два резистора, поддяжку туда, поддтяжку сюда, иначе на землю замкнёт всё сгорит. В мне 4 кнопки надо, так там мешок резисторов погони, весь вечер их искал. А первая мысль, какой даун так схемы делает, в ардуино конечно тоже резисторы в каждую щель хотят, но никогда с ними не возился, всё так подключанию, ничего нигде не горело.. А тут на, особенная схема, помрёшь пока подключишь..

                                А не деле вот оно, как всё просто.

                                1 ответ Последний ответ
                                0

                                • Войти

                                • Нет учётной записи? Зарегистрироваться

                                • Login or register to search.
                                • Первое сообщение
                                  Последнее сообщение
                                0
                                • Категории
                                • Главная
                                • Документация
                                • Последние
                                • Пользователи