Статьи

Управление светодиодом с помощью Raspberry PI 2 с использованием Mono и C #

Мой коллега MVP  Питер Новак  из Германии указал мне на  этот удивительный набор  на Amazon.de, в котором есть огромный набор датчиков.

Он поставляется с 37 датчиками и периферийными устройствами, которыми можно управлять с помощью Raspberry PI2. Первоначально он был сделан для PI B +, но, поскольку он совместим по выводам с PI 2, это работает нормально. Он поставляется с мини-диском с примером кода, но, к сожалению, это все C — вам нужно скомпилировать его с помощью GCC. Не программируя на C с конца 90-х, это не тот код, с которым мне очень удобно возиться. С другой стороны, я также с нетерпением жду, чтобы это пылилось до появления Windows 10 для устройств.

Теперь все примеры кода на C, которые идут с этим комплектом, используют библиотеку  wiringPI , созданную одним  Гордоном Хендерсоном . Я в основном использовал эту библиотеку как основу для работы с C #. Сначала вы должны установить библиотеку. У Гордона есть  простое пошаговое руководство  о том, как это сделать. Просто откройте консоль, перейдите в каталог, куда вы хотите загрузить исходные коды библиотеки, и следуйте его инструкциям. «Установка» в Linux, очевидно, означает установку git, клонирование репозитория и запуск файла сборки, который, по-видимому, компилирует весь shebang и ставит это «где-то». Конечным результатом является то, что вы можете скомпилировать примеры программ на С, которые поставляются с комплектом, используя библиотеку Гордона для управления датчиками.

Затем есть этот парень,  Даниэль Рише , который создал простую библиотеку для оболочки на C #. Как это работает, ошеломительно просто — он просто использует DllImport, чтобы обернуть вызовы в библиотеку C и сделать их доступными для C #. Я не видел эту технику в гневе с 1999 года, в проекте Visual Basic 6. Но, по-видимому, это все еще работает — и, что более важно, — оно, очевидно, работает и под Mono, даже если импортированный код вообще не приходит из DLL, а является файлом «так».

Он вроде описывает, что вам нужно сделать — после установки библиотеки Гордона вы переходите (все еще в командной строке, конечно) к подпапке «wiringPi» папки, в которой вы начали сборку, а затем запускаете три команды для создания: разделяемые библиотеки:

cc -shared wiringPi.o -o libwiringPi.so
cc -shared wiringPiI2C.o -o libwiringPiI2C.so
cc -shared wiringPiSPI.o -o libwiringPiSPI.so

И, очевидно, вы можете просто удалить папку, в которую вы скачали исходники wiringPi. Библиотека установлена ​​и может использоваться.

Теперь пример Дэниела показывает, как, к сожалению, для моей цели не хватает одной ключевой функции — для управления  светодиодом вам потребуется доступ к процедурам «softPwm» wiringPi. Просматривая источники Си, я нашел файл softPwm.c с процедурами, которые мне нужны для доступа. Итак, я создал свой собственный класс оболочки:

using System.Runtime.InteropServices;

namespace WiringPi
{
  public class SoftPwm
  {
    [DllImport("libwiringPi.so", EntryPoint = "softPwmCreate")]
    public static extern void Create(int pin, int initialValue, int pwmRange);

    [DllImport("libwiringPi.so", EntryPoint = "softPwmWrite")]
    public static extern void Write(int pin, int value);

    [DllImport("libwiringPi.so", EntryPoint = "softPwmStop")]
    public static extern void Stop(int pin);
  }
}

Как видите, все это довольно уродливо — все общедоступно, оно очень близко следует макету исходного кода и в настоящее время полностью не объектно-ориентировано. Но как бы то ни было, все еще рано, и это временная мера, пока Windows 10 все равно не появится. Это делает несколько подпрограмм C доступными для C # — например, подпрограмма C «softPwmWrite», которая помещает значение в вывод GPIO, становится доступной как SoftPwm.Write.

И тогда я могу написать следующую простую программу, которая позволяет многоцветному светодиоду, входящему в комплект SunFounder, получать все виды цветов:

using System;
using System.Threading;
using WiringPi;

namespace SunfounderTest
{
  class Program
  {
    const int LedPinRed = 0;
    const int LedPinGreen = 1;
    const int LedPinBlue = 2;

    static void Main(string[] args)
    {
      if (Init.WiringPiSetup() != -1)
      {
        SoftPwm.Create(LedPinRed, 0, 100);
        SoftPwm.Create(LedPinGreen, 0, 100);
        SoftPwm.Create(LedPinBlue, 0, 100);
        Console.WriteLine("Init succeeded");

        for (var i = 1; i < 3; i++)
        {
          ShowColor(255, 0, 0, "Red");
          ShowColor(0, 255, 0, "Green");
          ShowColor(0, 0, 255, "Blue");
          ShowColor(255, 255, 0, "Yellow");
          ShowColor(255, 0, 255, "Pink");
          ShowColor(0, 255, 255, "Cyan");
          ShowColor(195, 0, 255, "Purple");
          ShowColor(255, 255, 255, "White");
        }

        SoftPwm.Stop(LedPinRed);
        SoftPwm.Stop(LedPinGreen);
        SoftPwm.Stop(LedPinBlue);
      }
      else
      {
        Console.WriteLine("Init failed");
      }
    }

    private static void ShowColor(int r, int g, int b, string label)
    {
      SetLedColor(r, g, b);
      Console.WriteLine(label);
      Thread.Sleep(1000);
    }

    private static void SetLedColor(int r, int g, int b)
    {
      SoftPwm.Write(LedPinRed, r);
      SoftPwm.Write(LedPinGreen, g);
      SoftPwm.Write(LedPinBlue, b);
    }
  }
}

Я даже не начну притворяться, что я на самом деле полностью понимаю, что я делаю — и я даже меньше понимаю  почему  — но сначала вам   нужно вызвать метод Init.WiringPiSetup — который уже был упакован Дэниелом — а  затем вам нужно вызовите «Create» на трех выводах — только тогда вы можете установить значение для выводов, используя SoftPwm.Write. Я обернул вызовы этим в SetLedColor, который принимает значения красного, зеленого и синего (примерно 0-255), который, в свою очередь, обернут в процедуру, которая записывает информацию о прогрессе и немного ждет, прежде чем прогрессировать. И в конце вам нужно будет вызвать Stop на всех трех контактах, чтобы светодиод снова погас, иначе он с удовольствием останется включенным.

Чистый эффект: если вы подключите светодиодный контакт R к GPIO17, контакт G к 18, контакт B к 27 и контакт заземления к одному из заземления, светодиод будет мигать во всем диапазоне цветов.

Это будет работать только если вы запустите приложение с помощью sudo, поэтому

sudo mono SunfounderTest.exe

Раздражает то, что в образцах, поставляемых с этим набором, эти штифты 17, 18 и 27 обозначены как 0, 1 и 2. Это, очевидно, имеет исторические причины. На  этой странице  в element14 я нашел схему вывода с переводом с одного имени на другое. Обратите внимание, что контактный номер 11 называется как GPIO17, так и GPIO_GEN0. Это соответствует контакту 1 в  коде . Я предполагаю, что где-то есть какая-то логика, но я еще должен это обнаружить ?

Как обычно, вы можете найти демонстрационное решение  здесь . Имейте в виду — не весь код мой, часть его от  Даниэля Рича