고급 예제

다양한 도구들을 가지고 마음껏 응용해보세요.

아두이노와 flash 연동하기

2016-01-05 13:05:55

개요

 

flash란? 

 

플래시란 어도비 시스템즈사의 상호 작용적인 벡터 기반의 웹사이트를 제작할 수 있는 웹 제작 도구이며 소프트웨어 플랫폼입니다.

플래시를 이용해 웹사이트의 배너, 위젯 등을 제작 가능하며, 한 때 유행했었던 다양한 flash game 역시 플래시로 제작된 것 입니다.

 

 

HTML5가 웹 표준으로 전 세계 차원의 지지를 받고, 애플, 페이스북 등 다수의 기업들이 플래시의 보안상 취약점을 지적하면서 플래시의 점유율은 감소하고 있는 추세지만,

아직도 많은 웹 페이지에서 플래시가 사용되는 것을 볼 수 있습니다. 

 

플래시가 웹에서만 사용되는 것은 아닙니다.

아두이노와 플래시가 가지고 있는 장점을 잘 활용한다면, 아두이노와 플래시의 연동을 통해 다양한 미디어 아트의 도구로 사용할 수 있습니다.

 

플래시는 그래픽 작업이 용이한 프로그램이므로 아두이노에서 전달 받은 다양한 센서 데이터들을 바탕으로 플래시에서 그래픽적으로 표현한다면 멋진 인터렉티브 컨텐츠를 만들 수 있습니다.

이번 튜토리얼에서는 asglue를 다운받아 아두이노와 플래시를 연동하는 방법을 알아보도록 하겠습니다.

 

 

 

 

설치 및 실행

 

StandardFirmata 업로드 - 코드벤더 IDE

/*
  Firmata is a generic protocol for communicating with microcontrollers
  from software on a host computer. It is intended to work with
  any host computer software package.

  To download a host software package, please clink on the following link
  to open the download page in your default browser.

  https://github.com/firmata/arduino#firmata-client-libraries

  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
  Copyright (C) 2009-2015 Jeff Hoefs.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.

  Last updated by Jeff Hoefs: April 11, 2015
*/

#include <Servo.h>
#include <Wire.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 MAX_QUERIES                 8
#define REGISTER_NOT_SPECIFIED      -1

// the minimum interval for sampling analog input
#define MINIMUM_SAMPLING_INTERVAL 10


/*==============================================================================
 * GLOBAL VARIABLES
 *============================================================================*/

/* 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 pinConfig[TOTAL_PINS];         // configuration of every pin
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
int pinState[TOTAL_PINS];           // any value that has been written

/* 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;
};

/* for i2c read continuous more */
i2c_device_info query[MAX_QUERIES];

byte i2cRxData[32];
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;

/* 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 readAndReportData(byte address, int theRegister, byte numBytes) {
	// 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 != REGISTER_NOT_SPECIFIED) {
		Wire.beginTransmission(address);
		wireWrite((byte)theRegister);
		Wire.endTransmission();
		// 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 (pinConfig[pin] == I2C && isI2CEnabled && 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 != SERVO) {
		if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
			detachServo(pin);
		}
	}
	if (IS_PIN_ANALOG(pin)) {
		reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
	}
	if (IS_PIN_DIGITAL(pin)) {
		if (mode == INPUT) {
			portConfigInputs[pin / 8] |= (1 << (pin & 7));
		} else {
			portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
		}
  	}
  	
	pinState[pin] = 0;
	switch (mode) {
	case ANALOG:
		if (IS_PIN_ANALOG(pin)) {
			if (IS_PIN_DIGITAL(pin)) {
				pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
				digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
			}
			pinConfig[pin] = ANALOG;
		}
		break;
	case INPUT:
		if (IS_PIN_DIGITAL(pin)) {
			pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
			digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
			pinConfig[pin] = INPUT;
		}
		break;
	case OUTPUT:
		if (IS_PIN_DIGITAL(pin)) {
			digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM
			pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
			pinConfig[pin] = OUTPUT;
		}
		break;
	case PWM:
		if (IS_PIN_PWM(pin)) {
			pinMode(PIN_TO_PWM(pin), OUTPUT);
			analogWrite(PIN_TO_PWM(pin), 0);
			pinConfig[pin] = PWM;
		}
		break;
	case SERVO:
		if (IS_PIN_DIGITAL(pin)) {
			pinConfig[pin] = 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 I2C:
		if (IS_PIN_I2C(pin)) {
			// mark the pin as i2c
			// the user must call I2C_CONFIG to enable I2C for a device
			pinConfig[pin] = I2C;
		}
		break;
	default:
		Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
	}
	// TODO: save status to EEPROM here, if changed
}

void analogWriteCallback(byte pin, int value) {
	if (pin < TOTAL_PINS) {
		switch (pinConfig[pin]) {
		case SERVO:
			if (IS_PIN_DIGITAL(pin)) {
				servos[servoPinMap[pin]].write(value);
			}
			pinState[pin] = value;
			break;
		case PWM:
			if (IS_PIN_PWM(pin)) {
				analogWrite(PIN_TO_PWM(pin), value);	
			}
			pinState[pin] = value;
			break;
		}
	}
}

void digitalWriteCallback(byte port, int value) {
	byte pin, lastPin, 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)) {
				// only write to OUTPUT and INPUT (enables pullup)
				// do not touch pins in PWM, ANALOG, SERVO or other modes
				if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) {
					pinWriteMask |= mask;
					pinState[pin] = ((byte)value & mask) ? 1 : 0;
				}
			}
			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 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];
		}
	
		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 = REGISTER_NOT_SPECIFIED;
				data = argv[2] + (argv[3] << 7);  // bytes to read
			}
			readAndReportData(slaveAddress, (int)slaveRegister, data);
			break;
		case I2C_READ_CONTINUOUSLY:
			if ((queryIndex + 1) >= 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)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;
			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 {
				// 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 < MAX_QUERIES) {
						query[i].addr = query[i + 1].addr;
						query[i].reg = query[i + 1].reg;
						query[i].bytes = query[i + 1].bytes;
					}
				}
				queryIndex--;
			}
			break;
		default:
			break;
		}
		break;
	case I2C_CONFIG:
		delayTime = (argv[0] + (argv[1] << 7));
		if (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, 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:
		Serial.write(START_SYSEX);
		Serial.write(CAPABILITY_RESPONSE);
		for (byte pin = 0; pin < TOTAL_PINS; pin++) {
			if (IS_PIN_DIGITAL(pin)) {
				Serial.write((byte)INPUT);
				Serial.write(1);
				Serial.write((byte)OUTPUT);
				Serial.write(1);
			}
			if (IS_PIN_ANALOG(pin)) {
				Serial.write(ANALOG);
				Serial.write(10); // 10 = 10-bit resolution
			}
			if (IS_PIN_PWM(pin)) {
				Serial.write(PWM);
				Serial.write(8); // 8 = 8-bit resolution
			}
			if (IS_PIN_DIGITAL(pin)) {
				Serial.write(SERVO);
				Serial.write(14);
			}
			if (IS_PIN_I2C(pin)) {
				Serial.write(I2C);
				Serial.write(1);  // TODO: could assign a number to map to SCL or SDA
			}
			Serial.write(127);
		}
		Serial.write(END_SYSEX);
		break;
	case PIN_STATE_QUERY:
		if (argc > 0) {
			byte pin = argv[0];
			Serial.write(START_SYSEX);
			Serial.write(PIN_STATE_RESPONSE);
			Serial.write(pin);
			if (pin < TOTAL_PINS) {
				Serial.write((byte)pinConfig[pin]);
				Serial.write((byte)pinState[pin] & 0x7F);
				if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F);
				if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F);
			}
			Serial.write(END_SYSEX);
		}
		break;
	case ANALOG_MAPPING_QUERY:
		Serial.write(START_SYSEX);
		Serial.write(ANALOG_MAPPING_RESPONSE);
		for (byte pin = 0; pin < TOTAL_PINS; pin++) {
			Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
		}
		Serial.write(END_SYSEX);
		break;
	}
}

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, 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;
}

/*==============================================================================
 * SETUP()
 *============================================================================*/

void systemResetCallback() {
	isResetting = true;
	
	// initialize a defalt state
	// TODO: option to load config from EEPROM instead of default
	
	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, ANALOG);
		} else {
			// sets the output to 0, configures portConfigInputs
			setPinModeCallback(i, 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_MAJOR_VERSION, FIRMATA_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(START_SYSEX, sysexCallback);
	Firmata.attach(SYSTEM_RESET, systemResetCallback);
	
	Firmata.begin(57600);
	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) && pinConfig[pin] == 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);
			}
		}
	}
}

 

 

 

StandardFirmata 업로드 - 아두이노 IDE

 

플래시와 아두이노를 연동하기 위해서는 오렌지 보드에 StandardFirmata를 업로드 시켜줘야 합니다.

[파일] - [예제] - [Firmata] - [StandardFimata]를 오렌지 보드에 업로드 시켜줍니다.

필자의 경우 COM6 포트를 사용합니다. 플래시와 아두이노 연동 시 사용할 프록시서버의 설정에 포트 넘버가 필요하니 잘 기억해두셔야 합니다. 

 

 

 

 

Flash 다운로드

 

안타깝게도 adobe flash는 소프트웨어입니다. 

필자의 경우 30일 시험 버전을 다운로드 받아 테스트를 진행하였습니다.

아래 링크를 통해 flash professional을 다운 받으시면 됩니다.

다운로드 링크 : https://creative.adobe.com/products/download/flash

 

링크를 통해 기본적인 입력 사항을 기입 후 CreativeCloudSet-Up.exe 파일을 통해 CreativeCloud를 설치하신 후 

CreaativeCloud에서 flash 설치를 진행하시면 됩니다.

 

 

 

 

 

* 플래시 설치 후 플래시를 실행 시 '컴퓨터에 msvcr120.dll이(가) 없어 프로그램을 시작할 수 없습니다.'라는 경고창이 뜨며 실행이 안될 경우

1. 아래 링크를 통해 재배포 가능 패키지를 다운 받습니다. 

     재배포 가능 패키지 다운로드 링크 : http://www.microsoft.com/ko-KR/download/details.aspx?id=40784

2. 윈도우 32비트의 경우 x86을 설치해주고, 윈도우 64비트의 경우 x64, x86 두 개를 모두 설치해줍니다. 

3. 컴퓨터를 재시작 후 플래시를 실행시킵니다.

 

 

 

as3glue 다운로드 및 실행

 

아두이노와 플래시를 연동하기 위해서는 플래시와 아두이노를 연결시켜줄 프록시 서버, 플래시를 만들기 위한 클라이언트가 필요합니다.

as3glue는 위에 언급한 것들이 패키지로 구성되어 있기 때문에 편리하게 사용이 가능합니다. 

 

1. as3glue를 다운로드

아래 링크를 통해 arduino_as3glue_bundle_v2.0.zip 파일을 다운로드 받아줍니다.

다운로드 링크 : http://as3glue.googlecode.com/files/arduino_as3glue_bundle_v20.zip

 

 

2. 압축 해제

다운로드가 완료되었다면 압축을 풀어줍니다.

 

 

3. serproxy 설정 변경

프록시 서버 설정을 위해 [serproxy] - serproxy.cfg 파일을 열어줍니다.

 

아래 사진에서 표시된 부분을 수정해주어야 합니다. 

디폴트로 comm_port=1 , net_port1=5331로 설정되어 있지만, 필자의 경우 오렌지보드(아두이노)가 COM6으로 열결되어 있기 때문에 아래 사진과 같이 변경을 진행해주었습니다. 

수정을 완료했다면 파일을 저장합니다.

 

 

4. serproxy 실행

serproxy.cfg 파일이 있는 디렉토리에서 Shift - mouse 우클릭을 눌러 현재 디렉토리에서 CMD를 실행해줍니다.

 

CMD 창에 START serproxy를 입력해줍니다. 아래 사진과 같이 정보 출력창이 출력된다면 성공입니다.

실행된 serporxy를 닫지 말고 그대로 유지시켜 줍니다. (아두이노와 플래시 연결 시 서버 정보를 출력해주기 때문)

 

 

5. 플래시 예제 파일 실행

[arduino_as3glue_bundle_v2.0] - [source] - as3glue_standalone_monitor.fla 파일을 실행시켜 줍니다. 

 

플래시 파일이 열린 후 Ctrl + Enter를 눌러 플래시를 활성화 시켜줍니다.

 

아래 사진과 같이 대시 보드가 나타나면 성공입니다.

 

serproxy 창을 확인해보면 아래 사진과 같이 정보가 출력되었음을 확인할 수 있습니다. 

 

 

 

 

 

오렌지보드 - flash 연동 테스트

 

오렌지보드와 플래시가 잘 연동되는지 테스트해보기 위해 오렌지보드의 A0핀에 가변 저항을 연결해주었습니다.

아래 사진을 통해 가변 저항을 조작하면 가변 저항의 값이 플래시를 통해 그래프로 출력되는 것을 확인할 수 있습니다. 

 

플래시를 이용해 아두이노에서 보내는 데이터를 모니터 할 수 도 있지만, 반대로 플래시를 이용해 아두이노를 제어할 수도 있습니다, 

왼쪽에 위치한 pinMode 설정 대시 보드를 이용해 각 핀의 pinMode를 설정할 수 있습니다. 

오렌지보드와 마찬가지로 3,5,6,9,10,11번 핀 설정에만 PWM OUT 설정이 가능합니다.

핀 모드 설정 후 슬라이드(PWM), 토글 버튼(HIGH,LOW)를 이용해 아두이노를 제어할 수 있습니다. 

kocoafabeditor

항상 진취적이고, 새로운 것을 추구하는 코코아팹 에디터입니다!

flash, 아두이노, 기타

임성도 2016-09-18 11:31:40

좋은 정보 정말 감사합니다.

이승현 2016-10-05 01:53:24

cmd 창에서 START serproxy를 입력했을시 성공적으로 연결이 되지 못했는데 이럴경우에는 어떻게 해야 하나요?? 메뉴얼 대로 다 따라하긴 했습니다.ㅠㅠ

이승현 2016-10-05 01:53:30

cmd 창에서 START serproxy를 입력했을시 성공적으로 연결이 되지 못했는데 이럴경우에는 어떻게 해야 하나요?? 메뉴얼 대로 다 따라하긴 했습니다.ㅠㅠ

김준섭 2018-04-01 14:42:43

액션스크립트와 연동은 자세히 어떻게 하나요?