CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

MIDI контроллер на Arduino

В прошлом году я случайно увидел на ютубе видео, где Richie Hawtin показывает свой домашний сетап, крутит ручки у пульта Allen&Heath XONE и управляет тем самым популярной диджейской программой NI Traktor. Меня очень впечатлило это визуально и технически. До этого я не имел ни малейшего понятия о MIDI протоколе и контроллерах, его использующих.

В то время в ящике стола давно валялась плата Arduino и я все хотел пограться с ней, светодиодом я уже помигал, на LCD экран Hello world! вывел, а какого-нибудь применения в голову не приходило. И тут это видео. В общем я решил сделать свой миди-контроллер. Практической цели особо не было, потому как я не диджей, просто хотелось сделать какое-нибудь устройство с нуля до готового продукта.

Самым трудным оказалось найти фейдеры. Купить их в городе невозможно, в российских интернет-магазинах какое то гуано, заказывать за рубежом не хотелось из за Почты России с ее молниеносной доставкой. Я уже, в общем то, хотел сделать все вообще без единого движкового резистора, когда коллега подкинул мне пару старых японских резисторов и я все же поставил один как кроссфейдер. Вообще, я почти не тратил деньги на этот проект и большинство деталей обрели вторую жизнь в этом устройстве. Корпус я пару месяцев до этого извлек из помойки на работе, в нем был собран какой то контроллер разряда аккумулятора (вероятно электропогрузчика, вероятно японского потому что там была дюймовая резьба, которую пришлось перенарезать). Мне понравилось что он литой и основательный. По работе мне часто приходится иметь дело с промышленной электроникой, что конечно наложило свой отпечаток и я постарался сделать устройство максимально технологичным в сборке. Я ненавижу шлейфы проводов вырывающиеся из устройства когда ты откручиваешь его крышку, поэтому я решил сделать мезониную конструкцию или этакий бутерброд из плат. Это несколько сложнее чем просто насверлить дырок в корпусе, вставить в них переменных резисторов и соединить все проводами, но зато у меня в корпусе нет ни одного провода и все разбирается-собирается как АК-47.

Первая плата в «бутерброде» это стандартный макетный «шилд» (shield) арудуино, на котором я по быстрому распаял аналоговый мультиплексор 4051, который занимается тем что переключает сигнал с каждого потенциометра на один из аналоговых входов ардуино. (всего их 6, а мне надо было минимум 8, поэтому пришлось мультиплексировать).

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

Вторая плата несет на себе все внешние органы управления ( потенциометры и кнопки) и является фальш панелью. Плата разведена в Layout Sprint и напечатана по кустарной ЛУТ технологии.



При сборке платы последовательно вставляются друг в друга, последняя закрывает корпус, через 4 фторопластовые шайбы накладывается лиецевая панель из матированного оргстекла и весь «бутерброд» стягивается 4 винтами.

Устройство в сборе выглядит так:

Вероятно это самый маленький диджейский миди контроллер).

Что до софтовой части, то примеров полно на форумах по программированию ардуино и большую часть кода написал умный человек, прекрасно комментируя каждую строчку кода. Вот здесь описание этого проекта.
Я легко переписал его под свои нужды не имея опыта программирования на C, добавив обработку мультиплексора.
#include <TimerOne.h>

// Basic MIDI Controller code for reading all of the Arduino's digital and analogue inputs
// and sending them as MIDI messages to the host PC.
//
// Author: Michael Balzer
// Author#2: 2nz
// Revision History:
// Date        |  Change
// ---------------------------------------------------
// 2011-02-22  |  Initial Release
// 2011-03-30  |  Multiplexing 8 Analogue to pin 0
//
// This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// See http://creativecommons.org/licenses/by-nc-sa/3.0/ for license details.

// Uncomment this line to send debug messages to the serial monitor
//#define DEBUG

// MIDI mapping taken from http://www.nortonmusic.com/midi_cc.html
#define MIDI_CC_MODULATION 0x01
#define MIDI_CC_BREATH 0x02
#define MIDI_CC_VOLUME 0x07
#define MIDI_CC_BALANCE 0x08
#define MIDI_CC_PAN 0x0A
#define MIDI_CC_EXPRESSION 0x0B
#define MIDI_CC_EFFECT1 0x0C
#define MIDI_CC_EFFECT2 0x0D

#define MIDI_CC_GENERAL1 0x0E
#define MIDI_CC_GENERAL2 0x0F
#define MIDI_CC_GENERAL3 0x10
#define MIDI_CC_GENERAL4 0x11
#define MIDI_CC_GENERAL5 0x12
#define MIDI_CC_GENERAL6 0x13
#define MIDI_CC_GENERAL7 0x14
#define MIDI_CC_GENERAL8 0x15
#define MIDI_CC_GENERAL9 0x16
#define MIDI_CC_GENERAL10 0x17
#define MIDI_CC_GENERAL11 0x18
#define MIDI_CC_GENERAL12 0x19
#define MIDI_CC_GENERAL13 0x1A
#define MIDI_CC_GENERAL14 0x1B
#define MIDI_CC_GENERAL15 0x1C
#define MIDI_CC_GENERAL16 0x1D
#define MIDI_CC_GENERAL17 0x1E
#define MIDI_CC_GENERAL18 0x1F

#define MIDI_CC_GENERAL1_FINE 0x2E
#define MIDI_CC_GENERAL2_FINE 0x2F
#define MIDI_CC_GENERAL3_FINE 0x30
#define MIDI_CC_GENERAL4_FINE 0x31
#define MIDI_CC_GENERAL5_FINE 0x32
#define MIDI_CC_GENERAL6_FINE 0x33
#define MIDI_CC_GENERAL7_FINE 0x34
#define MIDI_CC_GENERAL8_FINE 0x35
#define MIDI_CC_GENERAL9_FINE 0x36
#define MIDI_CC_GENERAL10_FINE 0x37
#define MIDI_CC_GENERAL11_FINE 0x38
#define MIDI_CC_GENERAL12_FINE 0x39
#define MIDI_CC_GENERAL13_FINE 0x3A
#define MIDI_CC_GENERAL14_FINE 0x3B
#define MIDI_CC_GENERAL15_FINE 0x3C
#define MIDI_CC_GENERAL16_FINE 0x3D
#define MIDI_CC_GENERAL17_FINE 0x3E
#define MIDI_CC_GENERAL18_FINE 0x3F

#define MIDI_CC_SUSTAIN 0x40
#define MIDI_CC_REVERB 0x5B
#define MIDI_CC_CHORUS 0x5D
#define MIDI_CC_CONTROL_OFF 0x79
#define MIDI_CC_NOTES_OFF 0x78



// Comment this line out to disable button debounce logic.
// See http://arduino.cc/en/Tutorial/Debounce what debouncing is used for.
#define DEBOUNCE
// Debounce time length in milliseconds
#define DEBOUNCE_LENGTH 5

// Comment this line out to disable analogue filtering
#define ANALOGUE_FILTER
// A knob or slider movement must initially exceed this value to be recognised as an input. Note that it is
// for a 7-bit MIDI value.
#define FILTER_AMOUNT 5
// Timeout is in microseconds
#define ANALOGUE_INPUT_CHANGE_TIMEOUT 1000000

// Number of digital inputs. Can be anywhere from 0 to 18.
#define NUM_DI 9
// Number of analogue inputs. Can be anywhere from 0 to 6.
//Commented out because of multeplexing to analogue pin0.
//#define NUM_AI 6

// Array containing a mapping of digital pins to channel index. This array size must match NUM_DI above.
byte digitalInputMapping[NUM_DI] = { 5, 6, 7, 8, 9, 10, 11, 12, 13 };
// Array containing a mapping of analogue pins to channel index. This array size must match NUM_AI above. 
//Line commented out because of the use multeplexing to the analogue pin0
//byte analogueInputMapping[NUM_AI] = { A0, A1, A2, A3, A4, A5 };

// Contains the current state of the digital inputs.
byte digitalInputs[NUM_DI];
// Contains the current value of the analogue inputs.
byte analogueInputs[8];

// Variable to hold temporary digital reads, used for debounce logic.
byte tempDigitalInput;
// Variable to hold temporary analogue values, used for analogue filtering logic.
byte tempAnalogueInput;

// Preallocate the for loop index so we don't keep reallocating it for every program iteration.
int i = 0;
// Variable to hold difference between current and new analogue input values.
int analogueDiff = 0;
// This is used as a flag to indicate that an analogue input is changing.
boolean analogueInputChanging;

int r0 = 0;      //value of select pin at the 4051 (s0)
int r1 = 0;      //value of select pin at the 4051 (s1)
int r2 = 0;      //value of select pin at the 4051 (s2)

void setup()
{
  // Enable serial I/O at 57600 kbps. This is faster than the standard MIDI rate of 31250 kbps.
  // The PC application which we connect to will automatically take the higher sample rate and send MIDI
  // messages out at the correct rate. We only send things faster in case there is any latency.
  Serial.begin(31250);
  
  pinMode(2, OUTPUT);    // s0 of 4051
  pinMode(3, OUTPUT);    // s1 of 4051
  pinMode(4, OUTPUT);    // s2 of 4051
  
  // Initialise each digital input channel.
  for (i = 0; i < NUM_DI; i++)
  {
    // Set the pin direction to input.
    pinMode(digitalInputMapping[i], INPUT);
    // Don't enable pullup resistor on pin 13, as the LED and resistor will always pull it low, meaning the input won't work.
    // Instead an external pulldown resistor must be used on pin 13.
    // NOTE: This will cause all of the high/low logic for pin 13 to be inverted.
    if (digitalInputMapping[i] != 13)
    {
      // Enable the pull-up resistor. This call must come after the above pinMode call.
      digitalWrite(digitalInputMapping[i], HIGH);
    }
    
    // Initialise the digital state with a read to the input pin.
    digitalInputs[i] = digitalRead(digitalInputMapping[i]);
  }
  
  // Initialise each analogue input channel.
  // Set the pin 0 direction to input.
    pinMode(0, INPUT);
  for (i = 0; i <=7; i++)
  {
    // multiplexor control
    r0 = i & 0x01;
    r1 = (i>>1) & 0x01;
    r2 = (i>>2) & 0x01;

    digitalWrite(2, r0);
    digitalWrite(3, r1);
    digitalWrite(4, r2);
    // Initialise the analogue value with a read to the input pin.
    analogueInputs[i] = analogRead(0)/8;
  }
  
  // Assume no analogue inputs are active
  analogueInputChanging = false;
  
  // This timer runs every 1 second
  Timer1.initialize(ANALOGUE_INPUT_CHANGE_TIMEOUT);
  // When the timer expires, call this function
  Timer1.attachInterrupt(analogueInputStopped);
  // Start the timer
  Timer1.start();
    
}



void loop()
{
  for (i = 0; i < NUM_DI; i++)
  {
    // Read the current state of the digital input and store it temporarily.
    tempDigitalInput = digitalRead(digitalInputMapping[i]);
    
    // Check if the last state is different to the current state.
    if (digitalInputs[i] != tempDigitalInput)
    {
      #ifdef DEBOUNCE
      // Wait for a short period of time, and then take a second reading from the input pin.
      delay(DEBOUNCE_LENGTH);
      // If the second reading is the same as the initial reading, assume it must be true.
      if (tempDigitalInput == digitalRead(digitalInputMapping[i]))
      {
      #endif
        // Record the new digital input state.
        digitalInputs[i] = tempDigitalInput;
        
        // Moved from HIGH to LOW (button pressed)
        if (digitalInputs[i] == 0)
        {
          // All the digital inputs use pullup resistors, except pin 13 so the logic is inverted
          if (digitalInputMapping[i] != 13)
          {
            noteOn(0, 0x00 + i, 0x7F); // Channel 1, middle C, maximum velocity
          }
          else
          {
            noteOff(0, 0x00 + i); // Channel 1, middle C
          }
        }
        // Moved from LOW to HIGH (button released)
        else
        {
          // All the digital inputs use pullup resistors, except pin 13 so the logic is inverted
          if (digitalInputMapping[i] != 13)
          {
            noteOff(0, 0x00 + i); // Channel 1, middle C
          }
          else
          {
            noteOn(0, 0x00 + i, 0x7F); // Channel 1, middle C, maximum velocity
          }
        }
      #ifdef DEBOUNCE
      }
      #endif
    }
  }
  
  /*
   * Analogue input logic:
   * The Arduino uses a 10-bit (0-1023) analogue to digital converter (ADC) on each of its analogue inputs.
   * The ADC isn't very high resolution, so if a pot is in a position such that the output voltage is 'between'
   * what it can detect (say 2.505V or about 512.5 on a scale of 0-1023) then the value read will constantly
   * fluctuate between two integers (in this case 512 and 513).
   *
   * If we're simply looking for a change in the analogue input value like in the digital case above, then
   * there will be cases where the value is always changing, even though the physical input isn't being moved.
   * This will in turn send out a constant stream of MIDI messages to the connected software which may be problematic.
   *
   * To combat this, we require that the analogue input value must change by a certain threshold amount before
   * we register that it is actually changing. This is good in avoiding a constantly fluctuating value, but has
   * the negative effect of a reduced input resolution. For example if the threshold amount was 2 and we slowly moved
   * a slider through it's full range, we would only detect every second value as a change, in effect reducing the
   * already small 7-bit MIDI value to a 6-bit MIDI value.
   *
   * To get around this problem but still use the threshold logic, a timer is used. Initially the analogue input
   * must exceed the threshold to be detected as an input. Once this occurs, we then read every value coming from the
   * analogue input (not just those exceeding a threshold) giving us full 7-bit resolution. At the same time the
   * timer is started. This timer is used to keep track of whether an input hasn't been moved for a certain time
   * period. If it has been moved, the timer is restarted. If no movement occurs the timer is just left to run. When
   * the timer expires the analogue input is assumed to be no longer moving. Subsequent movements must exceed the
   * threshold amount.
   */
  for (i = 0; i <=7; i++)
  {
    // multiplexor control
    r0 = i & 0x01;
    r1 = (i>>1) & 0x01;
    r2 = (i>>2) & 0x01;

    digitalWrite(2, r0);
    digitalWrite(3, r1);
    digitalWrite(4, r2);
  
    // Read the analogue input pin 0, dividing it by 8 so the 10-bit ADC value (0-1023) is converted to a 7-bit MIDI value (0-127).
    tempAnalogueInput = analogRead(0) / 8;
    
    #ifdef ANALOGUE_FILTER
    // Take the absolute value of the difference between the curent and new values 
    analogueDiff = abs(tempAnalogueInput - analogueInputs[i]);
    // Only continue if the threshold was exceeded, or the input was already changing
    if ((analogueDiff > 0 && analogueInputChanging == true) || analogueDiff >= FILTER_AMOUNT)
    {
    #else
    if (analogueInputs[i] != tempAnalogueInput)
    {
    #endif
      // If the the analogue input wasn't changing, we need to start the timer again
      if (analogueInputChanging == false)
      {
        Timer1.start();
      }
      // The analogue input was moving, so restart the timer. Only restart it if we're sure the input isn't 'between' a value
      // ie. It's moved more than FILTER_AMOUNT
      else if (analogueDiff >= FILTER_AMOUNT)
      {
        Timer1.restart();
      }
      
      // The analogue input is moving
      analogueInputChanging = true;
      
      // Record the new analogue value
      analogueInputs[i] = tempAnalogueInput;
      
      // Send the analogue value out on the general MIDI CC (see definitions at beginning of this file)
      controlChange(0, MIDI_CC_GENERAL1 + i, analogueInputs[i]);
    }
  }
}

// Send a MIDI note on message
void noteOn(int channel, int pitch, int velocity)
{
  // 0x90 is the first of 16 note on channels
  channel += 0x90;
  
  // Ensure we're between channels 1 and 16 for a note on message
  if (channel >= 0x90 && channel <= 0x9F)
  {
    #ifdef DEBUG
      Serial.print("Button pressed: ");
      Serial.println(pitch);
    #else
      Serial.print(channel, BYTE);
      Serial.print(pitch, BYTE);
      Serial.print(velocity, BYTE);
    #endif
  }
}

// Send a MIDI note off message
void noteOff(int channel, int pitch)
{
  // 0x80 is the first of 16 note off channels
  channel += 0x80;
  
  // Ensure we're between channels 1 and 16 for a note off message
  if (channel >= 0x80 && channel <= 0x8F)
  {
    #ifdef DEBUG
      Serial.print("Button released: ");
      Serial.println(pitch);
    #else 
      Serial.print(channel, BYTE);
      Serial.print(pitch, BYTE);
      Serial.print(0x00, BYTE);
    #endif
  }
}

// Send a MIDI control change message
void controlChange(int channel, int control, int value)
{
  // 0xB0 is the first of 16 control change channels
  channel += 0xB0;
  
  // Ensure we're between channels 1 and 16 for a CC message
  if (channel >= 0xB0 && channel <= 0xBF)
  {
    #ifdef DEBUG
      Serial.print(control - MIDI_CC_GENERAL1);
      Serial.print(": ");
      Serial.println(value);
    #else
      Serial.print(channel, BYTE);
      Serial.print(control, BYTE);
      Serial.print(value, BYTE);
    #endif
  }
}

// The timer has expired
void analogueInputStopped()
{
  // Stop the timer so it doesn't repeatedly call this function.
  Timer1.stop();
  // The analogue input is no longer moving
  analogueInputChanging = false;
}

Если опустить детали, то работает это примерно так: При повороте ручки потенциометра меняется напряжение на его среднем выводе ( от 0 до 5 В, что соответствует его крайним положениям), напряжение оцифровывается АЦП и мы получаем байт который преобразуем в формат MIDI сообщения и шлем в последовательный порт, который есть у микроконтроллера для связи с другими цифровыми устройствами. На плате ардуино распаян USB-UART чип FT232 который поднимает виртуальный COM порт на компе. Дальше драйвер древнего синта Rоland который как нельзя кстати создан для работы через COM порт.

И вуаля. Единственная загвоздка это то, что стандартная скорость обмена в MIDI протоколе не стандартна для COM порта, но это быстро пофиксили обитатели форума ардуино, хакнув драйвер FT232.
Необходимо отредактировать файл FTDIPORT.INF
; FTDIPORT.INF
; Copyright (c) 2000-2006 FTDI Ltd.
;
; USB serial port driver installation for Windows 2000 and XP.
;

[Version]
Signature="$Windows NT$"
DriverPackageType=PlugAndPlay
DriverPackageDisplayName=%DESC%
Class=Ports
ClassGUID={4d36e978-e325-11ce-bfc1-08002be10318}
Provider=%FTDI%
CatalogFile=ftdiport.cat
DriverVer=05/19/2006,2.00.00

[SourceDisksNames]
1=%DriversDisk%,,,

[SourceDisksFiles]
ftser2k.sys=1
ftserui2.dll=1
FTLang.Dll = 1
ftcserco.dll = 1

[DestinationDirs]
FtdiPort.NT.Copy=10,system32\drivers
FtdiPort.NT.CopyUI=10,system32
FtdiPort2232.NT.CopyCoInst=10,system32

[ControlFlags]
ExcludeFromSelect=*

[Manufacturer]
%FTDI%=FtdiHw

[FtdiHw]
%VID_0403&PID_6001.DeviceDesc%=FtdiPort232,FTDIBUS\COMPORT&VID_0403&PID_6001
%VID_0403&PID_6010.DeviceDesc%=FtdiPort2232,FTDIBUS\COMPORT&VID_0403&PID_6010

[FtdiPort.NT.AddService]
DisplayName    = %SvcDesc%
ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER
StartType      = 3                  ; SERVICE_DEMAND_START
ErrorControl   = 1                  ; SERVICE_ERROR_NORMAL
ServiceBinary  = %10%\system32\drivers\ftser2k.sys
LoadOrderGroup = Base

; -------------- Serenum Driver install section
[SerEnum_AddService]
DisplayName    = %SerEnum.SvcDesc%
ServiceType    = 1               ; SERVICE_KERNEL_DRIVER
StartType      = 3               ; SERVICE_DEMAND_START
ErrorControl   = 1               ; SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\serenum.sys
LoadOrderGroup = PNP Filter

[FtdiPort.NT.AddReg]
HKR,,EnumPropPages32,,"ftserui2.dll,SerialPortPropPageProvider"

[FtdiPort.NT.Copy]
ftser2k.sys
;serenum.sys

[FtdiPort.NT.CopyUI]
ftserui2.dll
FTLang.dll

[FtdiPort232.NT]
CopyFiles=FtdiPort.NT.Copy,FtdiPort.NT.CopyUI
AddReg=FtdiPort.NT.AddReg

[FtdiPort232.NT.HW]
AddReg=FtdiPort232.NT.HW.AddReg

[FtdiPort232.NT.Services]
AddService = FTSER2K, 0x00000002, FtdiPort.NT.AddService
AddService = Serenum,,SerEnum_AddService
DelService = FTSERIAL

[FtdiPort232.NT.HW.AddReg]
HKR,,"UpperFilters",0x00010000,"serenum"
;HKR,,"ConfigData",1,01,00,3F,3F,10,27,88,13,C4,09,E2,04,71,02,38,41,9c,80,4E,C0,34,00,1A,00,0D,00,06,40,03,80,00,00,d0,80
;HKR,,"ConfigData",1,11,00,3F,3F,10,27,00,00,88,13,00,00,C4,09,00,00,E2,04,00,00,71,02,00,00,38,41,00,00,9C,80,00,00,4E,C0,00,00,34,00,00,00,1A,00,00,00,0D,00,00,00,06,40,00,00,03,80,00,00,00,00,00,00,D0,80,00,00
HKR,,"ConfigData",1,11,00,3F,3F,10,27,00,00,88,13,00,00,C4,09,00,00,E2,04,00,00,71,02,00,00,38,41,00,00,9C,80,00,00,60,00,00,00,34,00,00,00,1A,00,00,00,0D,00,00,00,06,40,00,00,03,80,00,00,00,00,00,00,D0,80,00,00
HKR,,"MinReadTimeout",0x00010001,0
HKR,,"MinWriteTimeout",0x00010001,0
HKR,,"LatencyTimer",0x00010001,16

; -------
; FT2232C
; -------

[FtdiPort2232.NT]
CopyFiles=FtdiPort.NT.Copy,FtdiPort.NT.CopyUI
AddReg=FtdiPort.NT.AddReg

[FtdiPort2232.NT.HW]
AddReg=FtdiPort232.NT.HW.AddReg

[FtdiPort2232.NT.CoInstallers]
AddReg=FtdiPort2232.NT.CoInstallers.AddReg
CopyFiles=FtdiPort2232.NT.CopyCoInst

[FtdiPort2232.NT.Services]
AddService = FTSER2K, 0x00000002, FtdiPort.NT.AddService
AddService = Serenum,,SerEnum_AddService
DelService = FTSERIAL

[FtdiPort2232.NT.CoInstallers.AddReg]
HKR,,CoInstallers32,0x00010000,"ftcserco.Dll,FTCSERCoInstaller"

[FtdiPort2232.NT.CopyCoInst]
ftcserco.dll

;---------------------------------------------------------------;

[Strings]
FTDI="FTDI"
DESC="CDM Driver Package"
DriversDisk="FTDI USB Drivers Disk"
PortsClassName = "Ports (COM & LPT)"
VID_0403&PID_6001.DeviceDesc="USB Serial Port"
VID_0403&PID_6010.DeviceDesc="USB Serial Port"
SvcDesc="USB Serial Port Driver"
SerEnum.SvcDesc="Serenum Filter Driver"



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

Вот небольшое видео в общих чертах демонстрирующее работу контроллера:
  • +5
  • 29 мая 2012, 19:21
  • 2nz

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

RSS свернуть / развернуть
+
0
Отличная работа, классное видео!
Отредактировал ссылки(не были видны).
avatar

Zoltberg

  • 30 мая 2012, 17:25
+
0
Спасибо)
avatar

2nz

  • 30 мая 2012, 21:45
+
0
схему мультиплексора бы, поподробней
avatar

driyko

  • 21 сентября 2013, 18:25
+
0
Необходимо отредактировать файл FTDIPORT.INF

где его отредактировать? в системной папке? «C:\Windows\System32\DriverStore\FileRepository\ftdiport.inf_amd64_neutral_9b2b9fd5d576957d\FTDIPORT.INF», он пишет что прав нету на редактирование а также на замену. Как сделать?? win7 64bit
avatar

Planer

  • 26 сентября 2014, 15:37
+
0
а я например хочу более широкий функционал, пару энкодеров добавить, поболее переменников, ещё есть мысль что бы принимала плата миди и зажигала нужные светодиоды, кто подскажет каким образом?
avatar

tsugi

  • 19 января 2015, 11:42
+
0
да и ещё, в этой сборке команды сразу посылаются? без промежуточных программ?
avatar

tsugi

  • 19 января 2015, 11:43
+
0
Я использовал роландовский COM драйвер и в тексте это указано. Где и как я его нашел уже и не вспомнить.
avatar

2nz

  • 19 января 2015, 11:57
+
+1
Без проблем. Прикручивай что хочешь, хоть энкодеры, хоть любые датчики. Мультиплексируй переменники. По реализации этот проект очень старый. Возможно эта библиотека может облегчить написание своей версии:
avatar

2nz

  • 19 января 2015, 12:24
+
0
https://github.com/FortySevenEffects/arduino_midi_library/
avatar

2nz

  • 19 января 2015, 12:26
+
0
а не поможете с кодом опроса 2х мультиплексоров 74HC4051? я только начал, поэтому для меня сложно пока додумать самому)))
avatar

tsugi

  • 23 января 2015, 11:39
+
0
Здравствуйте. Интересует изготовление контроллера под заказ. если возьметесь — напишите мне на почту m26@inbox.ru
avatar

qwe

  • 2 февраля 2016, 13:56
+
0
Не компилируется в cреде arduino 1.6.2
avatar

milkos

  • 21 марта 2016, 05:25

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.