找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 932|回复: 0
打印 上一主题 下一主题
收起左侧

【零知小项目】Firmata与Processing实现音乐LED炫酷灯光效果

[复制链接]
跳转到指定楼层
楼主
在这里使用零知标准板和Processing通过Firmata通信,实现了音乐LED炫酷的效果。
1、硬件
  • 零知标准板
  • RGB彩色LED 3个
  • 电阻-220Ω-9个

硬件连接







2、软件
软件方面需要零知-标准板程序和Processing程序,它们之间通过Firmata通信;
(1)零知-标准板
安装Firmata的库后,打开示例StandardFirmata程序,如下操作:
1、安装Firmata库:(具体操作请至零知官网查看原帖)
或者复制如下代码:
  1. #include <Servo.h>
  2. #include <SoftWire.h>
  3. #include <Firmata.h>

  4. #define I2C_WRITE                   B00000000
  5. #define I2C_READ                    B00001000
  6. #define I2C_READ_CONTINUOUSLY       B00010000
  7. #define I2C_STOP_READING            B00011000
  8. #define I2C_READ_WRITE_MODE_MASK    B00011000
  9. #define I2C_10BIT_ADDRESS_MODE_MASK B00100000
  10. #define I2C_END_TX_MASK             B01000000
  11. #define I2C_STOP_TX                 1
  12. #define I2C_RESTART_TX              0
  13. #define I2C_MAX_QUERIES             8
  14. #define I2C_REGISTER_NOT_SPECIFIED  -1

  15. // the minimum interval for sampling analog input
  16. #define MINIMUM_SAMPLING_INTERVAL   1


  17. /*==============================================================================
  18. * GLOBAL VARIABLES
  19. *============================================================================*/

  20. #ifdef FIRMATA_SERIAL_FEATURE
  21. SerialFirmata serialFeature;
  22. #endif

  23. /* analog inputs */
  24. int analogInputsToReport = 0; // bitwise array to store pin reporting

  25. /* digital input ports */
  26. byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence
  27. byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent

  28. /* pins configuration */
  29. byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else

  30. /* timer variables */
  31. unsigned long currentMillis;        // store the current value from millis()
  32. unsigned long previousMillis;       // for comparison with currentMillis
  33. unsigned int samplingInterval = 19; // how often to run the main loop (in ms)

  34. /* i2c data */
  35. struct i2c_device_info {
  36.   byte addr;
  37.   int reg;
  38.   byte bytes;
  39.   byte stopTX;
  40. };

  41. /* for i2c read continuous more */
  42. i2c_device_info query[I2C_MAX_QUERIES];

  43. byte i2cRxData[64];
  44. boolean isI2CEnabled = false;
  45. signed char queryIndex = -1;
  46. // default delay time between i2c read request and Wire.requestFrom()
  47. unsigned int i2cReadDelayTime = 0;

  48. Servo servos[MAX_SERVOS];
  49. byte servoPinMap[TOTAL_PINS];
  50. byte detachedServos[MAX_SERVOS];
  51. byte detachedServoCount = 0;
  52. byte servoCount = 0;

  53. boolean isResetting = false;

  54. // Forward declare a few functions to avoid compiler errors with older versions
  55. // of the Arduino IDE.
  56. void setPinModeCallback(byte, int);
  57. void reportAnalogCallback(byte analogPin, int value);
  58. void sysexCallback(byte, byte, byte*);

  59. /* utility functions */
  60. void wireWrite(byte data)
  61. {
  62. #if ARDUINO >= 100
  63.   Wire.write((byte)data);
  64. #else
  65.   Wire.send(data);
  66. #endif
  67. }

  68. byte wireRead(void)
  69. {
  70. #if ARDUINO >= 100
  71.   return Wire.read();
  72. #else
  73.   return Wire.receive();
  74. #endif
  75. }

  76. /*==============================================================================
  77. * FUNCTIONS
  78. *============================================================================*/

  79. void attachServo(byte pin, int minPulse, int maxPulse)
  80. {
  81.   if (servoCount < MAX_SERVOS) {
  82.     // reuse indexes of detached servos until all have been reallocated
  83.     if (detachedServoCount > 0) {
  84.       servoPinMap[pin] = detachedServos[detachedServoCount - 1];
  85.       if (detachedServoCount > 0) detachedServoCount--;
  86.     } else {
  87.       servoPinMap[pin] = servoCount;
  88.       servoCount++;
  89.     }
  90.     if (minPulse > 0 && maxPulse > 0) {
  91.       servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
  92.     } else {
  93.       servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
  94.     }
  95.   } else {
  96.     Firmata.sendString("Max servos attached");
  97.   }
  98. }

  99. void detachServo(byte pin)
  100. {
  101.   servos[servoPinMap[pin]].detach();
  102.   // if we're detaching the last servo, decrement the count
  103.   // otherwise store the index of the detached servo
  104.   if (servoPinMap[pin] == servoCount && servoCount > 0) {
  105.     servoCount--;
  106.   } else if (servoCount > 0) {
  107.     // keep track of detached servos because we want to reuse their indexes
  108.     // before incrementing the count of attached servos
  109.     detachedServoCount++;
  110.     detachedServos[detachedServoCount - 1] = servoPinMap[pin];
  111.   }

  112.   servoPinMap[pin] = 255;
  113. }

  114. void enableI2CPins()
  115. {
  116.   byte i;
  117.   // is there a faster way to do this? would probaby require importing
  118.   // Arduino.h to get SCL and SDA pins
  119.   for (i = 0; i < TOTAL_PINS; i++) {
  120.     if (IS_PIN_I2C(i)) {
  121.       // mark pins as i2c so they are ignore in non i2c data requests
  122.       setPinModeCallback(i, PIN_MODE_I2C);
  123.     }
  124.   }

  125.   isI2CEnabled = true;

  126.   Wire.begin();
  127. }

  128. /* disable the i2c pins so they can be used for other functions */
  129. void disableI2CPins() {
  130.   isI2CEnabled = false;
  131.   // disable read continuous mode for all devices
  132.   queryIndex = -1;
  133. }

  134. void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) {
  135.   // allow I2C requests that don't require a register read
  136.   // for example, some devices using an interrupt pin to signify new data available
  137.   // do not always require the register read so upon interrupt you call Wire.requestFrom()
  138.   if (theRegister != I2C_REGISTER_NOT_SPECIFIED) {
  139.     Wire.beginTransmission(address);
  140.     wireWrite((byte)theRegister);
  141.     Wire.endTransmission(stopTX); // default = true
  142.     // do not set a value of 0
  143.     if (i2cReadDelayTime > 0) {
  144.       // delay is necessary for some devices such as WiiNunchuck
  145.       delayMicroseconds(i2cReadDelayTime);
  146.     }
  147.   } else {
  148.     theRegister = 0;  // fill the register with a dummy value
  149.   }

  150.   Wire.requestFrom(address, numBytes);  // all bytes are returned in requestFrom

  151.   // check to be sure correct number of bytes were returned by slave
  152.   if (numBytes < Wire.available()) {
  153.     Firmata.sendString("I2C: Too many bytes received");
  154.   } else if (numBytes > Wire.available()) {
  155.     Firmata.sendString("I2C: Too few bytes received");
  156.   }

  157.   i2cRxData[0] = address;
  158.   i2cRxData[1] = theRegister;

  159.   for (int i = 0; i < numBytes && Wire.available(); i++) {
  160.     i2cRxData[2 + i] = wireRead();
  161.   }

  162.   // send slave address, register and received bytes
  163.   Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData);
  164. }

  165. void outputPort(byte portNumber, byte portValue, byte forceSend)
  166. {
  167.   // pins not configured as INPUT are cleared to zeros
  168.   portValue = portValue & portConfigInputs[portNumber];
  169.   // only send if the value is different than previously sent
  170.   if (forceSend || previousPINs[portNumber] != portValue) {
  171.     Firmata.sendDigitalPort(portNumber, portValue);
  172.     previousPINs[portNumber] = portValue;
  173.   }
  174. }

  175. /* -----------------------------------------------------------------------------
  176. * check all the active digital inputs for change of state, then add any events
  177. * to the Serial output queue using Serial.print() */
  178. void checkDigitalInputs(void)
  179. {
  180.   /* Using non-looping code allows constants to be given to readPort().
  181.    * The compiler will apply substantial optimizations if the inputs
  182.    * to readPort() are compile-time constants. */
  183.   if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
  184.   if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
  185.   if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
  186.   if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
  187.   if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
  188.   if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
  189.   if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
  190.   if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
  191.   if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
  192.   if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
  193.   if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
  194.   if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
  195.   if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
  196.   if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
  197.   if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
  198.   if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
  199. }

  200. // -----------------------------------------------------------------------------
  201. /* sets the pin mode to the correct state and sets the relevant bits in the
  202. * two bit-arrays that track Digital I/O and PWM status
  203. */
  204. void setPinModeCallback(byte pin, int mode)
  205. {
  206.   if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE)
  207.     return;

  208.   if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) {
  209.     // disable i2c so pins can be used for other functions
  210.     // the following if statements should reconfigure the pins properly
  211.     disableI2CPins();
  212.   }
  213.   if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) {
  214.     if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
  215.       detachServo(pin);
  216.     }
  217.   }
  218.   if (IS_PIN_ANALOG(pin)) {
  219.     reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting
  220.   }
  221.   if (IS_PIN_DIGITAL(pin)) {
  222.     if (mode == PIN_MODE_INPUT || mode == PIN_MODE_PULLUP) {
  223.       portConfigInputs[pin / 8] |= (1 << (pin & 7));
  224.     } else {
  225.       portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
  226.     }
  227.   }
  228.   Firmata.setPinState(pin, 0);
  229.   switch (mode) {
  230.     case PIN_MODE_ANALOG:
  231.       if (IS_PIN_ANALOG(pin)) {
  232.         if (IS_PIN_DIGITAL(pin)) {
  233.           pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
  234. #if ARDUINO <= 100
  235.           // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
  236.           digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
  237. #endif
  238.         }
  239.         Firmata.setPinMode(pin, PIN_MODE_ANALOG);
  240.       }
  241.       break;
  242.     case PIN_MODE_INPUT:
  243.       if (IS_PIN_DIGITAL(pin)) {
  244.         pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
  245. #if ARDUINO <= 100
  246.         // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
  247.         digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
  248. #endif
  249.         Firmata.setPinMode(pin, PIN_MODE_INPUT);
  250.       }
  251.       break;
  252.     case PIN_MODE_PULLUP:
  253.       if (IS_PIN_DIGITAL(pin)) {
  254.         pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
  255.         Firmata.setPinMode(pin, PIN_MODE_PULLUP);
  256.         Firmata.setPinState(pin, 1);
  257.       }
  258.       break;
  259.     case PIN_MODE_OUTPUT:
  260.       if (IS_PIN_DIGITAL(pin)) {
  261.         if (Firmata.getPinMode(pin) == PIN_MODE_PWM) {
  262.           // Disable PWM if pin mode was previously set to PWM.
  263.           digitalWrite(PIN_TO_DIGITAL(pin), LOW);
  264.         }
  265.         pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
  266.         Firmata.setPinMode(pin, PIN_MODE_OUTPUT);
  267.       }
  268.       break;
  269.     case PIN_MODE_PWM:
  270.       if (IS_PIN_PWM(pin)) {
  271.         pinMode(PIN_TO_PWM(pin), OUTPUT);
  272.         analogWrite(PIN_TO_PWM(pin), 0);
  273.         Firmata.setPinMode(pin, PIN_MODE_PWM);
  274.       }
  275.       break;
  276.     case PIN_MODE_SERVO:
  277.       if (IS_PIN_DIGITAL(pin)) {
  278.         Firmata.setPinMode(pin, PIN_MODE_SERVO);
  279.         if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) {
  280.           // pass -1 for min and max pulse values to use default values set
  281.           // by Servo library
  282.           attachServo(pin, -1, -1);
  283.         }
  284.       }
  285.       break;
  286.     case PIN_MODE_I2C:
  287.       if (IS_PIN_I2C(pin)) {
  288.         // mark the pin as i2c
  289.         // the user must call I2C_CONFIG to enable I2C for a device
  290.         Firmata.setPinMode(pin, PIN_MODE_I2C);
  291.       }
  292.       break;
  293.     case PIN_MODE_SERIAL:
  294. #ifdef FIRMATA_SERIAL_FEATURE
  295.       serialFeature.handlePinMode(pin, PIN_MODE_SERIAL);
  296. #endif
  297.       break;
  298.     default:
  299.       Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
  300.   }
  301.   // TODO: save status to EEPROM here, if changed
  302. }

  303. /*
  304. * Sets the value of an individual pin. Useful if you want to set a pin value but
  305. * are not tracking the digital port state.
  306. * Can only be used on pins configured as OUTPUT.
  307. * Cannot be used to enable pull-ups on Digital INPUT pins.
  308. */
  309. void setPinValueCallback(byte pin, int value)
  310. {
  311.   if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
  312.     if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT) {
  313.       Firmata.setPinState(pin, value);
  314.       digitalWrite(PIN_TO_DIGITAL(pin), value);
  315.     }
  316.   }
  317. }

  318. void analogWriteCallback(byte pin, int value)
  319. {
  320.   if (pin < TOTAL_PINS) {
  321.     switch (Firmata.getPinMode(pin)) {
  322.       case PIN_MODE_SERVO:
  323.         if (IS_PIN_DIGITAL(pin))
  324.           servos[servoPinMap[pin]].write(value);
  325.         Firmata.setPinState(pin, value);
  326.         break;
  327.       case PIN_MODE_PWM:
  328.         if (IS_PIN_PWM(pin))
  329.           analogWrite(PIN_TO_PWM(pin), value);
  330.         Firmata.setPinState(pin, value);
  331.         break;
  332.     }
  333.   }
  334. }

  335. void digitalWriteCallback(byte port, int value)
  336. {
  337.   byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0;

  338.   if (port < TOTAL_PORTS) {
  339.     // create a mask of the pins on this port that are writable.
  340.     lastPin = port * 8 + 8;
  341.     if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
  342.     for (pin = port * 8; pin < lastPin; pin++) {
  343.       // do not disturb non-digital pins (eg, Rx & Tx)
  344.       if (IS_PIN_DIGITAL(pin)) {
  345.         // do not touch pins in PWM, ANALOG, SERVO or other modes
  346.         if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT || Firmata.getPinMode(pin) == PIN_MODE_INPUT) {
  347.           pinValue = ((byte)value & mask) ? 1 : 0;
  348.           if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT) {
  349.             pinWriteMask |= mask;
  350.           } else if (Firmata.getPinMode(pin) == PIN_MODE_INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
  351.             // only handle INPUT here for backwards compatibility
  352. #if ARDUINO > 100
  353.             pinMode(pin, INPUT_PULLUP);
  354. #else
  355.             // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier
  356.             pinWriteMask |= mask;
  357. #endif
  358.           }
  359.           Firmata.setPinState(pin, pinValue);
  360.         }
  361.       }
  362.       mask = mask << 1;
  363.     }
  364.     writePort(port, (byte)value, pinWriteMask);
  365.   }
  366. }


  367. // -----------------------------------------------------------------------------
  368. /* sets bits in a bit array (int) to toggle the reporting of the analogIns
  369. */
  370. //void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
  371. //}
  372. void reportAnalogCallback(byte analogPin, int value)
  373. {
  374.   if (analogPin < TOTAL_ANALOG_PINS) {
  375.     if (value == 0) {
  376.       analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
  377.     } else {
  378.       analogInputsToReport = analogInputsToReport | (1 << analogPin);
  379.       // prevent during system reset or all analog pin values will be reported
  380.       // which may report noise for unconnected analog pins
  381.       if (!isResetting) {
  382.         // Send pin value immediately. This is helpful when connected via
  383.         // ethernet, wi-fi or bluetooth so pin states can be known upon
  384.         // reconnecting.
  385.         Firmata.sendAnalog(analogPin, analogRead(analogPin));
  386.       }
  387.     }
  388.   }
  389.   // TODO: save status to EEPROM here, if changed
  390. }

  391. void reportDigitalCallback(byte port, int value)
  392. {
  393.   if (port < TOTAL_PORTS) {
  394.     reportPINs[port] = (byte)value;
  395.     // Send port value immediately. This is helpful when connected via
  396.     // ethernet, wi-fi or bluetooth so pin states can be known upon
  397.     // reconnecting.
  398.     if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
  399.   }
  400.   // do not disable analog reporting on these 8 pins, to allow some
  401.   // pins used for digital, others analog.  Instead, allow both types
  402.   // of reporting to be enabled, but check if the pin is configured
  403.   // as analog when sampling the analog inputs.  Likewise, while
  404.   // scanning digital pins, portConfigInputs will mask off values from any
  405.   // pins configured as analog
  406. }

  407. /*==============================================================================
  408. * SYSEX-BASED commands
  409. *============================================================================*/

  410. void sysexCallback(byte command, byte argc, byte *argv)
  411. {
  412.   byte mode;
  413.   byte stopTX;
  414.   byte slaveAddress;
  415.   byte data;
  416.   int slaveRegister;
  417.   unsigned int delayTime;

  418.   switch (command) {
  419.     case I2C_REQUEST:
  420.       mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
  421.       if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) {
  422.         Firmata.sendString("10-bit addressing not supported");
  423.         return;
  424.       }
  425.       else {
  426.         slaveAddress = argv[0];
  427.       }

  428.       // need to invert the logic here since 0 will be default for client
  429.       // libraries that have not updated to add support for restart tx
  430.       if (argv[1] & I2C_END_TX_MASK) {
  431.         stopTX = I2C_RESTART_TX;
  432.       }
  433.       else {
  434.         stopTX = I2C_STOP_TX; // default
  435.       }

  436.       switch (mode) {
  437.         case I2C_WRITE:
  438.           Wire.beginTransmission(slaveAddress);
  439.           for (byte i = 2; i < argc; i += 2) {
  440.             data = argv[i] + (argv[i + 1] << 7);
  441.             wireWrite(data);
  442.           }
  443.           Wire.endTransmission();
  444.           delayMicroseconds(70);
  445.           break;
  446.         case I2C_READ:
  447.           if (argc == 6) {
  448.             // a slave register is specified
  449.             slaveRegister = argv[2] + (argv[3] << 7);
  450.             data = argv[4] + (argv[5] << 7);  // bytes to read
  451.           }
  452.           else {
  453.             // a slave register is NOT specified
  454.             slaveRegister = I2C_REGISTER_NOT_SPECIFIED;
  455.             data = argv[2] + (argv[3] << 7);  // bytes to read
  456.           }
  457.           readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX);
  458.           break;
  459.         case I2C_READ_CONTINUOUSLY:
  460.           if ((queryIndex + 1) >= I2C_MAX_QUERIES) {
  461.             // too many queries, just ignore
  462.             Firmata.sendString("too many queries");
  463.             break;
  464.           }
  465.           if (argc == 6) {
  466.             // a slave register is specified
  467.             slaveRegister = argv[2] + (argv[3] << 7);
  468.             data = argv[4] + (argv[5] << 7);  // bytes to read
  469.           }
  470.           else {
  471.             // a slave register is NOT specified
  472.             slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED;
  473.             data = argv[2] + (argv[3] << 7);  // bytes to read
  474.           }
  475.           queryIndex++;
  476.           query[queryIndex].addr = slaveAddress;
  477.           query[queryIndex].reg = slaveRegister;
  478.           query[queryIndex].bytes = data;
  479.           query[queryIndex].stopTX = stopTX;
  480.           break;
  481.         case I2C_STOP_READING:
  482.           byte queryIndexToSkip;
  483.           // if read continuous mode is enabled for only 1 i2c device, disable
  484.           // read continuous reporting for that device
  485.           if (queryIndex <= 0) {
  486.             queryIndex = -1;
  487.           } else {
  488.             queryIndexToSkip = 0;
  489.             // if read continuous mode is enabled for multiple devices,
  490.             // determine which device to stop reading and remove it's data from
  491.             // the array, shifiting other array data to fill the space
  492.             for (byte i = 0; i < queryIndex + 1; i++) {
  493.               if (query[i].addr == slaveAddress) {
  494.                 queryIndexToSkip = i;
  495.                 break;
  496.               }
  497.             }

  498.             for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) {
  499.               if (i < I2C_MAX_QUERIES) {
  500.                 query[i].addr = query[i + 1].addr;
  501.                 query[i].reg = query[i + 1].reg;
  502.                 query[i].bytes = query[i + 1].bytes;
  503.                 query[i].stopTX = query[i + 1].stopTX;
  504.               }
  505.             }
  506.             queryIndex--;
  507.           }
  508.           break;
  509.         default:
  510.           break;
  511.       }
  512.       break;
  513.     case I2C_CONFIG:
  514.       delayTime = (argv[0] + (argv[1] << 7));

  515.       if (argc > 1 && delayTime > 0) {
  516.         i2cReadDelayTime = delayTime;
  517.       }

  518.       if (!isI2CEnabled) {
  519.         enableI2CPins();
  520.       }

  521.       break;
  522.     case SERVO_CONFIG:
  523.       if (argc > 4) {
  524.         // these vars are here for clarity, they'll optimized away by the compiler
  525.         byte pin = argv[0];
  526.         int minPulse = argv[1] + (argv[2] << 7);
  527.         int maxPulse = argv[3] + (argv[4] << 7);

  528.         if (IS_PIN_DIGITAL(pin)) {
  529.           if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
  530.             detachServo(pin);
  531.           }
  532.           attachServo(pin, minPulse, maxPulse);
  533.           setPinModeCallback(pin, PIN_MODE_SERVO);
  534.         }
  535.       }
  536.       break;
  537.     case SAMPLING_INTERVAL:
  538.       if (argc > 1) {
  539.         samplingInterval = argv[0] + (argv[1] << 7);
  540.         if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
  541.           samplingInterval = MINIMUM_SAMPLING_INTERVAL;
  542.         }
  543.       } else {
  544.         //Firmata.sendString("Not enough data");
  545.       }
  546.       break;
  547.     case EXTENDED_ANALOG:
  548.       if (argc > 1) {
  549.         int val = argv[1];
  550.         if (argc > 2) val |= (argv[2] << 7);
  551.         if (argc > 3) val |= (argv[3] << 14);
  552.         analogWriteCallback(argv[0], val);
  553.       }
  554.       break;
  555.     case CAPABILITY_QUERY:
  556.       Firmata.write(START_SYSEX);
  557.       Firmata.write(CAPABILITY_RESPONSE);
  558.       for (byte pin = 0; pin < TOTAL_PINS; pin++) {
  559.         if (IS_PIN_DIGITAL(pin)) {
  560.           Firmata.write(PIN_MODE_INPUT);
  561.           Firmata.write(1);
  562.           Firmata.write((byte)PIN_MODE_PULLUP);
  563.           Firmata.write(1);
  564.           Firmata.write(PIN_MODE_OUTPUT);
  565.           Firmata.write(1);
  566.         }
  567.         if (IS_PIN_ANALOG(pin)) {
  568.           Firmata.write(PIN_MODE_ANALOG);
  569.           Firmata.write(10); // 10 = 10-bit resolution
  570.         }
  571.         if (IS_PIN_PWM(pin)) {
  572.           Firmata.write(PIN_MODE_PWM);
  573.           Firmata.write(DEFAULT_PWM_RESOLUTION);
  574.         }
  575.         if (IS_PIN_DIGITAL(pin)) {
  576.           Firmata.write(PIN_MODE_SERVO);
  577.           Firmata.write(14);
  578.         }
  579.         if (IS_PIN_I2C(pin)) {
  580.           Firmata.write(PIN_MODE_I2C);
  581.           Firmata.write(1);  // TODO: could assign a number to map to SCL or SDA
  582.         }
  583. #ifdef FIRMATA_SERIAL_FEATURE
  584.         serialFeature.handleCapability(pin);
  585. #endif
  586.         Firmata.write(127);
  587.       }
  588.       Firmata.write(END_SYSEX);
  589.       break;
  590.     case PIN_STATE_QUERY:
  591.       if (argc > 0) {
  592.         byte pin = argv[0];
  593.         Firmata.write(START_SYSEX);
  594.         Firmata.write(PIN_STATE_RESPONSE);
  595.         Firmata.write(pin);
  596.         if (pin < TOTAL_PINS) {
  597.           Firmata.write(Firmata.getPinMode(pin));
  598.           Firmata.write((byte)Firmata.getPinState(pin) & 0x7F);
  599.           if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F);
  600.           if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F);
  601.         }
  602.         Firmata.write(END_SYSEX);
  603.       }
  604.       break;
  605.     case ANALOG_MAPPING_QUERY:
  606.       Firmata.write(START_SYSEX);
  607.       Firmata.write(ANALOG_MAPPING_RESPONSE);
  608.       for (byte pin = 0; pin < TOTAL_PINS; pin++) {
  609.         Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
  610.       }
  611.       Firmata.write(END_SYSEX);
  612.       break;

  613.     case SERIAL_MESSAGE:
  614. #ifdef FIRMATA_SERIAL_FEATURE
  615.       serialFeature.handleSysex(command, argc, argv);
  616. #endif
  617.       break;
  618.   }
  619. }

  620. /*==============================================================================
  621. * SETUP()
  622. *============================================================================*/

  623. void systemResetCallback()
  624. {
  625.   isResetting = true;

  626.   // initialize a defalt state
  627.   // TODO: option to load config from EEPROM instead of default

  628. #ifdef FIRMATA_SERIAL_FEATURE
  629.   serialFeature.reset();
  630. #endif

  631.   if (isI2CEnabled) {
  632.     disableI2CPins();
  633.   }

  634.   for (byte i = 0; i < TOTAL_PORTS; i++) {
  635.     reportPINs[i] = false;    // by default, reporting off
  636.     portConfigInputs[i] = 0;  // until activated
  637.     previousPINs[i] = 0;
  638.   }

  639.   for (byte i = 0; i < TOTAL_PINS; i++) {
  640.     // pins with analog capability default to analog input
  641.     // otherwise, pins default to digital output
  642.     if (IS_PIN_ANALOG(i)) {
  643.       // turns off pullup, configures everything
  644.       setPinModeCallback(i, PIN_MODE_ANALOG);
  645.     } else if (IS_PIN_DIGITAL(i)) {
  646.       // sets the output to 0, configures portConfigInputs
  647.       setPinModeCallback(i, PIN_MODE_OUTPUT);
  648.     }

  649.     servoPinMap[i] = 255;
  650.   }
  651.   // by default, do not report any analog inputs
  652.   analogInputsToReport = 0;

  653.   detachedServoCount = 0;
  654.   servoCount = 0;

  655.   /* send digital inputs to set the initial state on the host computer,
  656.    * since once in the loop(), this firmware will only send on change */
  657.   /*
  658.   TODO: this can never execute, since no pins default to digital input
  659.         but it will be needed when/if we support EEPROM stored config
  660.   for (byte i=0; i < TOTAL_PORTS; i++) {
  661.     outputPort(i, readPort(i, portConfigInputs[i]), true);
  662.   }
  663.   */
  664.   isResetting = false;
  665. }

  666. void setup()
  667. {
  668.   Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);

  669.   Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
  670.   Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
  671.   Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
  672.   Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
  673.   Firmata.attach(SET_PIN_MODE, setPinModeCallback);
  674.   Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback);
  675.   Firmata.attach(START_SYSEX, sysexCallback);
  676.   Firmata.attach(SYSTEM_RESET, systemResetCallback);

  677.   // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega,
  678.   // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this:
  679.   // Serial1.begin(57600);
  680.   // Firmata.begin(Serial1);
  681.   // However do not do this if you are using SERIAL_MESSAGE

  682.   Firmata.begin(57600);
  683.   while (!Serial) {
  684.     ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101
  685.   }

  686.   systemResetCallback();  // reset to default config
  687. }

  688. /*==============================================================================
  689. * LOOP()
  690. *============================================================================*/
  691. void loop()
  692. {
  693.   byte pin, analogPin;

  694.   /* DIGITALREAD - as fast as possible, check for changes and output them to the
  695.    * FTDI buffer using Serial.print()  */
  696.   checkDigitalInputs();

  697.   /* STREAMREAD - processing incoming messagse as soon as possible, while still
  698.    * checking digital inputs.  */
  699.   while (Firmata.available())
  700.     Firmata.processInput();

  701.   // TODO - ensure that Stream buffer doesn't go over 60 bytes

  702.   currentMillis = millis();
  703.   if (currentMillis - previousMillis > samplingInterval) {
  704.     previousMillis += samplingInterval;
  705.     /* ANALOGREAD - do all analogReads() at the configured sampling interval */
  706.     for (pin = 0; pin < TOTAL_PINS; pin++) {
  707.       if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) {
  708.         analogPin = PIN_TO_ANALOG(pin);
  709.         if (analogInputsToReport & (1 << analogPin)) {
  710.           Firmata.sendAnalog(analogPin, analogRead(analogPin));
  711.         }
  712.       }
  713.     }
  714.     // report i2c data for all device with read continuous mode enabled
  715.     if (queryIndex > -1) {
  716.       for (byte i = 0; i < queryIndex + 1; i++) {
  717.         readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX);
  718.       }
  719.     }
  720.   }

  721. #ifdef FIRMATA_SERIAL_FEATURE
  722.   serialFeature.update();
  723. #endif
  724. }
复制代码

然后验证程序并上传到零知-标准板。

(2)Processing程序
Processing程序主要使用Firmata库和Minim库,然后把音乐通过FFT计算并转换为PWM值,这个值再通过Firmata Arduino设置对应LED的引脚PWM值,就能显示各种颜色。
  1. import ddf.minim.*;  
  2. import ddf.minim.analysis.*;
  3. import processing.serial.*;
  4. import cc.arduino.*;

  5. Arduino arduino;
  6.    
  7. Minim minim;  
  8. AudioPlayer song;
  9. FFT fft;

  10. int redPin1 = 0;
  11. int greenPin1 = 1;
  12. int bluePin1 = 2;

  13. int redPin2 = 3;
  14. int greenPin2 = 5;
  15. int bluePin2 = 6;

  16. int redPin3 = 9;
  17. int greenPin3 = 11;
  18. int bluePin3 = 12;

  19. int LED_PINS[] = {redPin1,greenPin1,bluePin1,redPin2,greenPin2,bluePin2,redPin3,greenPin3,bluePin3};

  20. int color_id = 0;

  21. int common_cathode = 0;

  22. void setup() {
  23.     size(800, 600);
  24.      
  25.     arduino = new Arduino(this, "COM7", 57600);
  26.     for (int i = 0; i <= 8; i++) arduino.pinMode(LED_PINS[i], Arduino.PWM);
  27.     for (int i = 0; i <= 8; i++) arduino.analogWrite(LED_PINS[i],255);

  28.     minim = new Minim(this);  
  29.     song = minim.loadFile("badapple.mp3");
  30.     song.play();
  31.     fft = new FFT(song.bufferSize(), song.sampleRate());   
  32. }
  33.   
  34. void draw() {   
  35.     background(#151515);

  36.     fft.forward(song.mix);

  37.     strokeWeight(1.3);
  38.     stroke(#FFF700);

  39.     // frequency
  40.     pushMatrix();
  41.       translate(250, 0);   
  42.       for(int i = 0; i < 0+fft.specSize(); i++) {
  43.         line(i, height*4/5, i, height*4/5 - fft.getBand(i)*4);
  44.         if(i%100==0) text(fft.getBand(i), i, height*4/5+20);
  45.         if(i==200) {
  46.           if(fft.getBand(i)>2) {
  47.             setColor1(255,255,0);
  48.             setColor3(255,255,0);
  49.           }
  50.           else if(fft.getBand(i)>1) {
  51.             setColor1(255,0,255);
  52.             setColor3(255,0,255);
  53.           } else {
  54.             setColor1(255,255,255);
  55.             setColor3(255,255,255);
  56.           }
  57.         }
  58.         if(i==50) {
  59.           if(fft.getBand(i)>5) {
  60.             color_id = (color_id+1)%4;
  61.           } else if(fft.getBand(i)>3) {
  62.             if(color_id==0) setColor2(0,255,0);
  63.             else if(color_id==1) setColor2(0,255,255);
  64.             else if(color_id==2) setColor2(0,0,255);
  65.             else setColor2(255,0,0);
  66.           }
  67.           else {
  68.             setColor2(255,255,255);
  69.           }
  70.         }
  71.       }  
  72.     popMatrix();
  73.      
  74.     stroke(#FF0000);
  75.    
  76.     //waveform
  77.     for(int i = 250; i < song.left.size() - 1; i++) {
  78.       line(i, 50 + song.left.get(i)*50, i+1, 50 + song.left.get(i+1)*50);
  79.       line(i, 150 + song.right.get(i)*50, i+1, 150 + song.right.get(i+1)*50);
  80.       line(i, 250 + song.mix.get(i)*50, i+1, 250 + song.mix.get(i+1)*50);
  81.     }
  82.    
  83.     noStroke();
  84.     fill(#111111);
  85.     rect(0, 0, 250, height);
  86.    
  87.     textSize(24);
  88.     fill(#046700);
  89.     text("left amplitude", 10, 50);
  90.     text("right amplitude", 10, 150);
  91.     text("mixed amplitude", 10, 250);
  92.     text("frequency", 10, height*4/5);
  93. }

  94. void stop()
  95. {
  96.     for (int i = 0; i <= 13; i++) arduino.digitalWrite(i,arduino.HIGH);
  97.     song.close();  
  98.     minim.stop();
  99.     super.stop();
  100. }
  101. void setColor1(int red, int green, int blue)
  102. {
  103.   if(common_cathode==1) {
  104.     red = 255-red;
  105.     green = 255-green;
  106.     blue = 255-blue;
  107.   }
  108.   arduino.analogWrite(redPin1, red);
  109.   arduino.analogWrite(greenPin1, green);
  110.   arduino.analogWrite(bluePin1, blue);  
  111. }
  112. void setColor2(int red, int green, int blue)
  113. {
  114.   if(common_cathode==1) {
  115.     red = 255-red;
  116.     green = 255-green;
  117.     blue = 255-blue;
  118.   }
  119.   arduino.analogWrite(redPin2, red);
  120.   arduino.analogWrite(greenPin2, green);
  121.   arduino.analogWrite(bluePin2, blue);  
  122. }
  123. void setColor3(int red, int green, int blue)
  124. {
  125.   if(common_cathode==1) {
  126.     red = 255-red;
  127.     green = 255-green;
  128.     blue = 255-blue;
  129.   }
  130.   arduino.analogWrite(redPin3, red);
  131.   arduino.analogWrite(greenPin3, green);
  132.   arduino.analogWrite(bluePin3, blue);  
  133. }
复制代码

这里需要注意的是,需要在Processing程序里面更改你的板子对应COM口,和你需要播放的音乐名(和sketch同一级目录)。
完整程序如下:
请至零知官网免费查看原帖

3、测试验证
在我们连接好零知板与LED等的连线并上传好程序后,我们再打开Processing程序并运行,就可以看到播放音乐的时候炫酷的LED灯光效果了。

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表