在这里使用零知标准板和Processing通过Firmata通信,实现了音乐LED炫酷的效果。
1、硬件- 零知标准板
- RGB彩色LED 3个
- 电阻-220Ω-9个
硬件连接
2、软件
软件方面需要零知-标准板程序和Processing程序,它们之间通过Firmata通信;
(1)零知-标准板
安装Firmata的库后,打开示例StandardFirmata程序,如下操作:
1、安装Firmata库:(具体操作请至零知官网查看原帖)
或者复制如下代码:
- #include <Servo.h>
- #include <SoftWire.h>
- #include <Firmata.h>
-
- #define I2C_WRITE B00000000
- #define I2C_READ B00001000
- #define I2C_READ_CONTINUOUSLY B00010000
- #define I2C_STOP_READING B00011000
- #define I2C_READ_WRITE_MODE_MASK B00011000
- #define I2C_10BIT_ADDRESS_MODE_MASK B00100000
- #define I2C_END_TX_MASK B01000000
- #define I2C_STOP_TX 1
- #define I2C_RESTART_TX 0
- #define I2C_MAX_QUERIES 8
- #define I2C_REGISTER_NOT_SPECIFIED -1
-
- // the minimum interval for sampling analog input
- #define MINIMUM_SAMPLING_INTERVAL 1
-
-
- /*==============================================================================
- * GLOBAL VARIABLES
- *============================================================================*/
-
- #ifdef FIRMATA_SERIAL_FEATURE
- SerialFirmata serialFeature;
- #endif
-
- /* analog inputs */
- int analogInputsToReport = 0; // bitwise array to store pin reporting
-
- /* digital input ports */
- byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence
- byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent
-
- /* pins configuration */
- byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
-
- /* timer variables */
- unsigned long currentMillis; // store the current value from millis()
- unsigned long previousMillis; // for comparison with currentMillis
- unsigned int samplingInterval = 19; // how often to run the main loop (in ms)
-
- /* i2c data */
- struct i2c_device_info {
- byte addr;
- int reg;
- byte bytes;
- byte stopTX;
- };
-
- /* for i2c read continuous more */
- i2c_device_info query[I2C_MAX_QUERIES];
-
- byte i2cRxData[64];
- boolean isI2CEnabled = false;
- signed char queryIndex = -1;
- // default delay time between i2c read request and Wire.requestFrom()
- unsigned int i2cReadDelayTime = 0;
-
- Servo servos[MAX_SERVOS];
- byte servoPinMap[TOTAL_PINS];
- byte detachedServos[MAX_SERVOS];
- byte detachedServoCount = 0;
- byte servoCount = 0;
-
- boolean isResetting = false;
-
- // Forward declare a few functions to avoid compiler errors with older versions
- // of the Arduino IDE.
- void setPinModeCallback(byte, int);
- void reportAnalogCallback(byte analogPin, int value);
- void sysexCallback(byte, byte, byte*);
-
- /* utility functions */
- void wireWrite(byte data)
- {
- #if ARDUINO >= 100
- Wire.write((byte)data);
- #else
- Wire.send(data);
- #endif
- }
-
- byte wireRead(void)
- {
- #if ARDUINO >= 100
- return Wire.read();
- #else
- return Wire.receive();
- #endif
- }
-
- /*==============================================================================
- * FUNCTIONS
- *============================================================================*/
-
- void attachServo(byte pin, int minPulse, int maxPulse)
- {
- if (servoCount < MAX_SERVOS) {
- // reuse indexes of detached servos until all have been reallocated
- if (detachedServoCount > 0) {
- servoPinMap[pin] = detachedServos[detachedServoCount - 1];
- if (detachedServoCount > 0) detachedServoCount--;
- } else {
- servoPinMap[pin] = servoCount;
- servoCount++;
- }
- if (minPulse > 0 && maxPulse > 0) {
- servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
- } else {
- servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
- }
- } else {
- Firmata.sendString("Max servos attached");
- }
- }
-
- void detachServo(byte pin)
- {
- servos[servoPinMap[pin]].detach();
- // if we're detaching the last servo, decrement the count
- // otherwise store the index of the detached servo
- if (servoPinMap[pin] == servoCount && servoCount > 0) {
- servoCount--;
- } else if (servoCount > 0) {
- // keep track of detached servos because we want to reuse their indexes
- // before incrementing the count of attached servos
- detachedServoCount++;
- detachedServos[detachedServoCount - 1] = servoPinMap[pin];
- }
-
- servoPinMap[pin] = 255;
- }
-
- void enableI2CPins()
- {
- byte i;
- // is there a faster way to do this? would probaby require importing
- // Arduino.h to get SCL and SDA pins
- for (i = 0; i < TOTAL_PINS; i++) {
- if (IS_PIN_I2C(i)) {
- // mark pins as i2c so they are ignore in non i2c data requests
- setPinModeCallback(i, PIN_MODE_I2C);
- }
- }
-
- isI2CEnabled = true;
-
- Wire.begin();
- }
-
- /* disable the i2c pins so they can be used for other functions */
- void disableI2CPins() {
- isI2CEnabled = false;
- // disable read continuous mode for all devices
- queryIndex = -1;
- }
-
- void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) {
- // allow I2C requests that don't require a register read
- // for example, some devices using an interrupt pin to signify new data available
- // do not always require the register read so upon interrupt you call Wire.requestFrom()
- if (theRegister != I2C_REGISTER_NOT_SPECIFIED) {
- Wire.beginTransmission(address);
- wireWrite((byte)theRegister);
- Wire.endTransmission(stopTX); // default = true
- // do not set a value of 0
- if (i2cReadDelayTime > 0) {
- // delay is necessary for some devices such as WiiNunchuck
- delayMicroseconds(i2cReadDelayTime);
- }
- } else {
- theRegister = 0; // fill the register with a dummy value
- }
-
- Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom
-
- // check to be sure correct number of bytes were returned by slave
- if (numBytes < Wire.available()) {
- Firmata.sendString("I2C: Too many bytes received");
- } else if (numBytes > Wire.available()) {
- Firmata.sendString("I2C: Too few bytes received");
- }
-
- i2cRxData[0] = address;
- i2cRxData[1] = theRegister;
-
- for (int i = 0; i < numBytes && Wire.available(); i++) {
- i2cRxData[2 + i] = wireRead();
- }
-
- // send slave address, register and received bytes
- Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData);
- }
-
- void outputPort(byte portNumber, byte portValue, byte forceSend)
- {
- // pins not configured as INPUT are cleared to zeros
- portValue = portValue & portConfigInputs[portNumber];
- // only send if the value is different than previously sent
- if (forceSend || previousPINs[portNumber] != portValue) {
- Firmata.sendDigitalPort(portNumber, portValue);
- previousPINs[portNumber] = portValue;
- }
- }
-
- /* -----------------------------------------------------------------------------
- * check all the active digital inputs for change of state, then add any events
- * to the Serial output queue using Serial.print() */
- void checkDigitalInputs(void)
- {
- /* Using non-looping code allows constants to be given to readPort().
- * The compiler will apply substantial optimizations if the inputs
- * to readPort() are compile-time constants. */
- if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
- if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
- if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
- if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
- if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
- if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
- if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
- if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
- if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
- if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
- if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
- if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
- if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
- if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
- if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
- if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
- }
-
- // -----------------------------------------------------------------------------
- /* sets the pin mode to the correct state and sets the relevant bits in the
- * two bit-arrays that track Digital I/O and PWM status
- */
- void setPinModeCallback(byte pin, int mode)
- {
- if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE)
- return;
-
- if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) {
- // disable i2c so pins can be used for other functions
- // the following if statements should reconfigure the pins properly
- disableI2CPins();
- }
- if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) {
- if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
- detachServo(pin);
- }
- }
- if (IS_PIN_ANALOG(pin)) {
- reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting
- }
- if (IS_PIN_DIGITAL(pin)) {
- if (mode == PIN_MODE_INPUT || mode == PIN_MODE_PULLUP) {
- portConfigInputs[pin / 8] |= (1 << (pin & 7));
- } else {
- portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
- }
- }
- Firmata.setPinState(pin, 0);
- switch (mode) {
- case PIN_MODE_ANALOG:
- if (IS_PIN_ANALOG(pin)) {
- if (IS_PIN_DIGITAL(pin)) {
- pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
- #if ARDUINO <= 100
- // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
- digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
- #endif
- }
- Firmata.setPinMode(pin, PIN_MODE_ANALOG);
- }
- break;
- case PIN_MODE_INPUT:
- if (IS_PIN_DIGITAL(pin)) {
- pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
- #if ARDUINO <= 100
- // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
- digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
- #endif
- Firmata.setPinMode(pin, PIN_MODE_INPUT);
- }
- break;
- case PIN_MODE_PULLUP:
- if (IS_PIN_DIGITAL(pin)) {
- pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
- Firmata.setPinMode(pin, PIN_MODE_PULLUP);
- Firmata.setPinState(pin, 1);
- }
- break;
- case PIN_MODE_OUTPUT:
- if (IS_PIN_DIGITAL(pin)) {
- if (Firmata.getPinMode(pin) == PIN_MODE_PWM) {
- // Disable PWM if pin mode was previously set to PWM.
- digitalWrite(PIN_TO_DIGITAL(pin), LOW);
- }
- pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
- Firmata.setPinMode(pin, PIN_MODE_OUTPUT);
- }
- break;
- case PIN_MODE_PWM:
- if (IS_PIN_PWM(pin)) {
- pinMode(PIN_TO_PWM(pin), OUTPUT);
- analogWrite(PIN_TO_PWM(pin), 0);
- Firmata.setPinMode(pin, PIN_MODE_PWM);
- }
- break;
- case PIN_MODE_SERVO:
- if (IS_PIN_DIGITAL(pin)) {
- Firmata.setPinMode(pin, PIN_MODE_SERVO);
- if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) {
- // pass -1 for min and max pulse values to use default values set
- // by Servo library
- attachServo(pin, -1, -1);
- }
- }
- break;
- case PIN_MODE_I2C:
- if (IS_PIN_I2C(pin)) {
- // mark the pin as i2c
- // the user must call I2C_CONFIG to enable I2C for a device
- Firmata.setPinMode(pin, PIN_MODE_I2C);
- }
- break;
- case PIN_MODE_SERIAL:
- #ifdef FIRMATA_SERIAL_FEATURE
- serialFeature.handlePinMode(pin, PIN_MODE_SERIAL);
- #endif
- break;
- default:
- Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
- }
- // TODO: save status to EEPROM here, if changed
- }
-
- /*
- * Sets the value of an individual pin. Useful if you want to set a pin value but
- * are not tracking the digital port state.
- * Can only be used on pins configured as OUTPUT.
- * Cannot be used to enable pull-ups on Digital INPUT pins.
- */
- void setPinValueCallback(byte pin, int value)
- {
- if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
- if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT) {
- Firmata.setPinState(pin, value);
- digitalWrite(PIN_TO_DIGITAL(pin), value);
- }
- }
- }
-
- void analogWriteCallback(byte pin, int value)
- {
- if (pin < TOTAL_PINS) {
- switch (Firmata.getPinMode(pin)) {
- case PIN_MODE_SERVO:
- if (IS_PIN_DIGITAL(pin))
- servos[servoPinMap[pin]].write(value);
- Firmata.setPinState(pin, value);
- break;
- case PIN_MODE_PWM:
- if (IS_PIN_PWM(pin))
- analogWrite(PIN_TO_PWM(pin), value);
- Firmata.setPinState(pin, value);
- break;
- }
- }
- }
-
- void digitalWriteCallback(byte port, int value)
- {
- byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0;
-
- if (port < TOTAL_PORTS) {
- // create a mask of the pins on this port that are writable.
- lastPin = port * 8 + 8;
- if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
- for (pin = port * 8; pin < lastPin; pin++) {
- // do not disturb non-digital pins (eg, Rx & Tx)
- if (IS_PIN_DIGITAL(pin)) {
- // do not touch pins in PWM, ANALOG, SERVO or other modes
- if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT || Firmata.getPinMode(pin) == PIN_MODE_INPUT) {
- pinValue = ((byte)value & mask) ? 1 : 0;
- if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT) {
- pinWriteMask |= mask;
- } else if (Firmata.getPinMode(pin) == PIN_MODE_INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
- // only handle INPUT here for backwards compatibility
- #if ARDUINO > 100
- pinMode(pin, INPUT_PULLUP);
- #else
- // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier
- pinWriteMask |= mask;
- #endif
- }
- Firmata.setPinState(pin, pinValue);
- }
- }
- mask = mask << 1;
- }
- writePort(port, (byte)value, pinWriteMask);
- }
- }
-
-
- // -----------------------------------------------------------------------------
- /* sets bits in a bit array (int) to toggle the reporting of the analogIns
- */
- //void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
- //}
- void reportAnalogCallback(byte analogPin, int value)
- {
- if (analogPin < TOTAL_ANALOG_PINS) {
- if (value == 0) {
- analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
- } else {
- analogInputsToReport = analogInputsToReport | (1 << analogPin);
- // prevent during system reset or all analog pin values will be reported
- // which may report noise for unconnected analog pins
- if (!isResetting) {
- // Send pin value immediately. This is helpful when connected via
- // ethernet, wi-fi or bluetooth so pin states can be known upon
- // reconnecting.
- Firmata.sendAnalog(analogPin, analogRead(analogPin));
- }
- }
- }
- // TODO: save status to EEPROM here, if changed
- }
-
- void reportDigitalCallback(byte port, int value)
- {
- if (port < TOTAL_PORTS) {
- reportPINs[port] = (byte)value;
- // Send port value immediately. This is helpful when connected via
- // ethernet, wi-fi or bluetooth so pin states can be known upon
- // reconnecting.
- if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
- }
- // do not disable analog reporting on these 8 pins, to allow some
- // pins used for digital, others analog. Instead, allow both types
- // of reporting to be enabled, but check if the pin is configured
- // as analog when sampling the analog inputs. Likewise, while
- // scanning digital pins, portConfigInputs will mask off values from any
- // pins configured as analog
- }
-
- /*==============================================================================
- * SYSEX-BASED commands
- *============================================================================*/
-
- void sysexCallback(byte command, byte argc, byte *argv)
- {
- byte mode;
- byte stopTX;
- byte slaveAddress;
- byte data;
- int slaveRegister;
- unsigned int delayTime;
-
- switch (command) {
- case I2C_REQUEST:
- mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
- if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) {
- Firmata.sendString("10-bit addressing not supported");
- return;
- }
- else {
- slaveAddress = argv[0];
- }
-
- // need to invert the logic here since 0 will be default for client
- // libraries that have not updated to add support for restart tx
- if (argv[1] & I2C_END_TX_MASK) {
- stopTX = I2C_RESTART_TX;
- }
- else {
- stopTX = I2C_STOP_TX; // default
- }
-
- switch (mode) {
- case I2C_WRITE:
- Wire.beginTransmission(slaveAddress);
- for (byte i = 2; i < argc; i += 2) {
- data = argv[i] + (argv[i + 1] << 7);
- wireWrite(data);
- }
- Wire.endTransmission();
- delayMicroseconds(70);
- break;
- case I2C_READ:
- if (argc == 6) {
- // a slave register is specified
- slaveRegister = argv[2] + (argv[3] << 7);
- data = argv[4] + (argv[5] << 7); // bytes to read
- }
- else {
- // a slave register is NOT specified
- slaveRegister = I2C_REGISTER_NOT_SPECIFIED;
- data = argv[2] + (argv[3] << 7); // bytes to read
- }
- readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX);
- break;
- case I2C_READ_CONTINUOUSLY:
- if ((queryIndex + 1) >= I2C_MAX_QUERIES) {
- // too many queries, just ignore
- Firmata.sendString("too many queries");
- break;
- }
- if (argc == 6) {
- // a slave register is specified
- slaveRegister = argv[2] + (argv[3] << 7);
- data = argv[4] + (argv[5] << 7); // bytes to read
- }
- else {
- // a slave register is NOT specified
- slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED;
- data = argv[2] + (argv[3] << 7); // bytes to read
- }
- queryIndex++;
- query[queryIndex].addr = slaveAddress;
- query[queryIndex].reg = slaveRegister;
- query[queryIndex].bytes = data;
- query[queryIndex].stopTX = stopTX;
- break;
- case I2C_STOP_READING:
- byte queryIndexToSkip;
- // if read continuous mode is enabled for only 1 i2c device, disable
- // read continuous reporting for that device
- if (queryIndex <= 0) {
- queryIndex = -1;
- } else {
- queryIndexToSkip = 0;
- // if read continuous mode is enabled for multiple devices,
- // determine which device to stop reading and remove it's data from
- // the array, shifiting other array data to fill the space
- for (byte i = 0; i < queryIndex + 1; i++) {
- if (query[i].addr == slaveAddress) {
- queryIndexToSkip = i;
- break;
- }
- }
-
- for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) {
- if (i < I2C_MAX_QUERIES) {
- query[i].addr = query[i + 1].addr;
- query[i].reg = query[i + 1].reg;
- query[i].bytes = query[i + 1].bytes;
- query[i].stopTX = query[i + 1].stopTX;
- }
- }
- queryIndex--;
- }
- break;
- default:
- break;
- }
- break;
- case I2C_CONFIG:
- delayTime = (argv[0] + (argv[1] << 7));
-
- if (argc > 1 && delayTime > 0) {
- i2cReadDelayTime = delayTime;
- }
-
- if (!isI2CEnabled) {
- enableI2CPins();
- }
-
- break;
- case SERVO_CONFIG:
- if (argc > 4) {
- // these vars are here for clarity, they'll optimized away by the compiler
- byte pin = argv[0];
- int minPulse = argv[1] + (argv[2] << 7);
- int maxPulse = argv[3] + (argv[4] << 7);
-
- if (IS_PIN_DIGITAL(pin)) {
- if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
- detachServo(pin);
- }
- attachServo(pin, minPulse, maxPulse);
- setPinModeCallback(pin, PIN_MODE_SERVO);
- }
- }
- break;
- case SAMPLING_INTERVAL:
- if (argc > 1) {
- samplingInterval = argv[0] + (argv[1] << 7);
- if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
- samplingInterval = MINIMUM_SAMPLING_INTERVAL;
- }
- } else {
- //Firmata.sendString("Not enough data");
- }
- break;
- case EXTENDED_ANALOG:
- if (argc > 1) {
- int val = argv[1];
- if (argc > 2) val |= (argv[2] << 7);
- if (argc > 3) val |= (argv[3] << 14);
- analogWriteCallback(argv[0], val);
- }
- break;
- case CAPABILITY_QUERY:
- Firmata.write(START_SYSEX);
- Firmata.write(CAPABILITY_RESPONSE);
- for (byte pin = 0; pin < TOTAL_PINS; pin++) {
- if (IS_PIN_DIGITAL(pin)) {
- Firmata.write(PIN_MODE_INPUT);
- Firmata.write(1);
- Firmata.write((byte)PIN_MODE_PULLUP);
- Firmata.write(1);
- Firmata.write(PIN_MODE_OUTPUT);
- Firmata.write(1);
- }
- if (IS_PIN_ANALOG(pin)) {
- Firmata.write(PIN_MODE_ANALOG);
- Firmata.write(10); // 10 = 10-bit resolution
- }
- if (IS_PIN_PWM(pin)) {
- Firmata.write(PIN_MODE_PWM);
- Firmata.write(DEFAULT_PWM_RESOLUTION);
- }
- if (IS_PIN_DIGITAL(pin)) {
- Firmata.write(PIN_MODE_SERVO);
- Firmata.write(14);
- }
- if (IS_PIN_I2C(pin)) {
- Firmata.write(PIN_MODE_I2C);
- Firmata.write(1); // TODO: could assign a number to map to SCL or SDA
- }
- #ifdef FIRMATA_SERIAL_FEATURE
- serialFeature.handleCapability(pin);
- #endif
- Firmata.write(127);
- }
- Firmata.write(END_SYSEX);
- break;
- case PIN_STATE_QUERY:
- if (argc > 0) {
- byte pin = argv[0];
- Firmata.write(START_SYSEX);
- Firmata.write(PIN_STATE_RESPONSE);
- Firmata.write(pin);
- if (pin < TOTAL_PINS) {
- Firmata.write(Firmata.getPinMode(pin));
- Firmata.write((byte)Firmata.getPinState(pin) & 0x7F);
- if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F);
- if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F);
- }
- Firmata.write(END_SYSEX);
- }
- break;
- case ANALOG_MAPPING_QUERY:
- Firmata.write(START_SYSEX);
- Firmata.write(ANALOG_MAPPING_RESPONSE);
- for (byte pin = 0; pin < TOTAL_PINS; pin++) {
- Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
- }
- Firmata.write(END_SYSEX);
- break;
-
- case SERIAL_MESSAGE:
- #ifdef FIRMATA_SERIAL_FEATURE
- serialFeature.handleSysex(command, argc, argv);
- #endif
- break;
- }
- }
-
- /*==============================================================================
- * SETUP()
- *============================================================================*/
-
- void systemResetCallback()
- {
- isResetting = true;
-
- // initialize a defalt state
- // TODO: option to load config from EEPROM instead of default
-
- #ifdef FIRMATA_SERIAL_FEATURE
- serialFeature.reset();
- #endif
-
- if (isI2CEnabled) {
- disableI2CPins();
- }
-
- for (byte i = 0; i < TOTAL_PORTS; i++) {
- reportPINs[i] = false; // by default, reporting off
- portConfigInputs[i] = 0; // until activated
- previousPINs[i] = 0;
- }
-
- for (byte i = 0; i < TOTAL_PINS; i++) {
- // pins with analog capability default to analog input
- // otherwise, pins default to digital output
- if (IS_PIN_ANALOG(i)) {
- // turns off pullup, configures everything
- setPinModeCallback(i, PIN_MODE_ANALOG);
- } else if (IS_PIN_DIGITAL(i)) {
- // sets the output to 0, configures portConfigInputs
- setPinModeCallback(i, PIN_MODE_OUTPUT);
- }
-
- servoPinMap[i] = 255;
- }
- // by default, do not report any analog inputs
- analogInputsToReport = 0;
-
- detachedServoCount = 0;
- servoCount = 0;
-
- /* send digital inputs to set the initial state on the host computer,
- * since once in the loop(), this firmware will only send on change */
- /*
- TODO: this can never execute, since no pins default to digital input
- but it will be needed when/if we support EEPROM stored config
- for (byte i=0; i < TOTAL_PORTS; i++) {
- outputPort(i, readPort(i, portConfigInputs[i]), true);
- }
- */
- isResetting = false;
- }
-
- void setup()
- {
- Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
-
- Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
- Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
- Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
- Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
- Firmata.attach(SET_PIN_MODE, setPinModeCallback);
- Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback);
- Firmata.attach(START_SYSEX, sysexCallback);
- Firmata.attach(SYSTEM_RESET, systemResetCallback);
-
- // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega,
- // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this:
- // Serial1.begin(57600);
- // Firmata.begin(Serial1);
- // However do not do this if you are using SERIAL_MESSAGE
-
- Firmata.begin(57600);
- while (!Serial) {
- ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101
- }
-
- systemResetCallback(); // reset to default config
- }
-
- /*==============================================================================
- * LOOP()
- *============================================================================*/
- void loop()
- {
- byte pin, analogPin;
-
- /* DIGITALREAD - as fast as possible, check for changes and output them to the
- * FTDI buffer using Serial.print() */
- checkDigitalInputs();
-
- /* STREAMREAD - processing incoming messagse as soon as possible, while still
- * checking digital inputs. */
- while (Firmata.available())
- Firmata.processInput();
-
- // TODO - ensure that Stream buffer doesn't go over 60 bytes
-
- currentMillis = millis();
- if (currentMillis - previousMillis > samplingInterval) {
- previousMillis += samplingInterval;
- /* ANALOGREAD - do all analogReads() at the configured sampling interval */
- for (pin = 0; pin < TOTAL_PINS; pin++) {
- if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) {
- analogPin = PIN_TO_ANALOG(pin);
- if (analogInputsToReport & (1 << analogPin)) {
- Firmata.sendAnalog(analogPin, analogRead(analogPin));
- }
- }
- }
- // report i2c data for all device with read continuous mode enabled
- if (queryIndex > -1) {
- for (byte i = 0; i < queryIndex + 1; i++) {
- readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX);
- }
- }
- }
-
- #ifdef FIRMATA_SERIAL_FEATURE
- serialFeature.update();
- #endif
- }
复制代码
然后验证程序并上传到零知-标准板。
(2)Processing程序
Processing程序主要使用Firmata库和Minim库,然后把音乐通过FFT计算并转换为PWM值,这个值再通过Firmata Arduino设置对应LED的引脚PWM值,就能显示各种颜色。
- import ddf.minim.*;
- import ddf.minim.analysis.*;
- import processing.serial.*;
- import cc.arduino.*;
-
- Arduino arduino;
-
- Minim minim;
- AudioPlayer song;
- FFT fft;
-
- int redPin1 = 0;
- int greenPin1 = 1;
- int bluePin1 = 2;
-
- int redPin2 = 3;
- int greenPin2 = 5;
- int bluePin2 = 6;
-
- int redPin3 = 9;
- int greenPin3 = 11;
- int bluePin3 = 12;
-
- int LED_PINS[] = {redPin1,greenPin1,bluePin1,redPin2,greenPin2,bluePin2,redPin3,greenPin3,bluePin3};
-
- int color_id = 0;
-
- int common_cathode = 0;
-
- void setup() {
- size(800, 600);
-
- arduino = new Arduino(this, "COM7", 57600);
- for (int i = 0; i <= 8; i++) arduino.pinMode(LED_PINS[i], Arduino.PWM);
- for (int i = 0; i <= 8; i++) arduino.analogWrite(LED_PINS[i],255);
-
- minim = new Minim(this);
- song = minim.loadFile("badapple.mp3");
- song.play();
- fft = new FFT(song.bufferSize(), song.sampleRate());
- }
-
- void draw() {
- background(#151515);
-
- fft.forward(song.mix);
-
- strokeWeight(1.3);
- stroke(#FFF700);
-
- // frequency
- pushMatrix();
- translate(250, 0);
- for(int i = 0; i < 0+fft.specSize(); i++) {
- line(i, height*4/5, i, height*4/5 - fft.getBand(i)*4);
- if(i%100==0) text(fft.getBand(i), i, height*4/5+20);
- if(i==200) {
- if(fft.getBand(i)>2) {
- setColor1(255,255,0);
- setColor3(255,255,0);
- }
- else if(fft.getBand(i)>1) {
- setColor1(255,0,255);
- setColor3(255,0,255);
- } else {
- setColor1(255,255,255);
- setColor3(255,255,255);
- }
- }
- if(i==50) {
- if(fft.getBand(i)>5) {
- color_id = (color_id+1)%4;
- } else if(fft.getBand(i)>3) {
- if(color_id==0) setColor2(0,255,0);
- else if(color_id==1) setColor2(0,255,255);
- else if(color_id==2) setColor2(0,0,255);
- else setColor2(255,0,0);
- }
- else {
- setColor2(255,255,255);
- }
- }
- }
- popMatrix();
-
- stroke(#FF0000);
-
- //waveform
- for(int i = 250; i < song.left.size() - 1; i++) {
- line(i, 50 + song.left.get(i)*50, i+1, 50 + song.left.get(i+1)*50);
- line(i, 150 + song.right.get(i)*50, i+1, 150 + song.right.get(i+1)*50);
- line(i, 250 + song.mix.get(i)*50, i+1, 250 + song.mix.get(i+1)*50);
- }
-
- noStroke();
- fill(#111111);
- rect(0, 0, 250, height);
-
- textSize(24);
- fill(#046700);
- text("left amplitude", 10, 50);
- text("right amplitude", 10, 150);
- text("mixed amplitude", 10, 250);
- text("frequency", 10, height*4/5);
- }
-
- void stop()
- {
- for (int i = 0; i <= 13; i++) arduino.digitalWrite(i,arduino.HIGH);
- song.close();
- minim.stop();
- super.stop();
- }
- void setColor1(int red, int green, int blue)
- {
- if(common_cathode==1) {
- red = 255-red;
- green = 255-green;
- blue = 255-blue;
- }
- arduino.analogWrite(redPin1, red);
- arduino.analogWrite(greenPin1, green);
- arduino.analogWrite(bluePin1, blue);
- }
- void setColor2(int red, int green, int blue)
- {
- if(common_cathode==1) {
- red = 255-red;
- green = 255-green;
- blue = 255-blue;
- }
- arduino.analogWrite(redPin2, red);
- arduino.analogWrite(greenPin2, green);
- arduino.analogWrite(bluePin2, blue);
- }
- void setColor3(int red, int green, int blue)
- {
- if(common_cathode==1) {
- red = 255-red;
- green = 255-green;
- blue = 255-blue;
- }
- arduino.analogWrite(redPin3, red);
- arduino.analogWrite(greenPin3, green);
- arduino.analogWrite(bluePin3, blue);
- }
复制代码
这里需要注意的是,需要在Processing程序里面更改你的板子对应COM口,和你需要播放的音乐名(和sketch同一级目录)。
完整程序如下:
请至零知官网免费查看原帖
3、测试验证
在我们连接好零知板与LED等的连线并上传好程序后,我们再打开Processing程序并运行,就可以看到播放音乐的时候炫酷的LED灯光效果了。
|