// 4 LED strips controlled by JeeNode and 2 MOSFET Plugs. // code based on Jean-Claude Wipplers rgbAjust.pde // see http://news.jeelabs.org/2010/06/15/remote-rgb-strip-control/ #include #include #include #define DEBUG 0 #define NVALUES 4 // can be adjusted from 1..8 (must also adjust "masks") static byte settings[NVALUES]; // 0 = red, 1 = green, 2 = blue, 3 = white static byte slots[256]; // time slots, toggles whenever a bit is set char cbuffer[40] = ""; // receive buffer PString buffer(cbuffer, sizeof(cbuffer)); NewSoftSerial XBSerial = NewSoftSerial(7, 5); // XBee // which setting affects which I/O pin: // bits 0..3 = AIO1 .. AIO4 // bits 4..7 = DIO1 .. DIO4 static const byte masks[NVALUES] = {0x20, 0x02, 0x10, 0x01 }; static void setupIO() { for (byte i = 0; i < NVALUES; ++i) { PORTC &= ~ (masks[i] & 0x0F); // turn AIO pin off DDRC |= masks[i] & 0x0F; // make pin an output PORTD &= ~ (masks[i] & 0xF0); // turn DIO pin off DDRD |= masks[i] & 0xF0; // make pin an output } } static void prepareSlots() { #if DEBUG Serial.print("settings "); for (byte i = 0; i < NVALUES; ++i) { Serial.print(' '); Serial.print(settings[i], DEC); } Serial.println(); #endif // set a few bits, i.e. at the time when we need to toggle the output pin memset(slots, 0, sizeof slots); // note: a 0 setting toggles the same bit twice, so it won't ever turn on for (byte i = 0; i < NVALUES; ++i) { byte level = settings[i]; // get the requested PWM level byte mask = masks[i]; // map setting to corresponding I/O pin slots[0] ^= mask; // toggle on at the start of the loop slots[level] ^= mask; // toggle off at the proper time } // Special case: run LED at full brightness for level 255 - this is done // by turning the LED on at the start of each scan and never toggling it. // This is done in loop() below, but we must prevent toggling in this case. slots[0] ^= slots[255]; } static void loadSettings() { for (byte i = 0; i < NVALUES; ++i) settings[i] = EEPROM.read(i); prepareSlots(); } static void saveSettings() { for (byte i = 0; i < NVALUES; ++i) EEPROM.write(i, settings[i]); prepareSlots(); } void HandleCommand() { #if DEBUG Serial.println("\n[HandleCommand]"); #endif // copy buffer to settings and save. memcpy(settings, buffer, 4); saveSettings(); // clear buffer buffer.begin(); } void setup () { setupIO(); loadSettings(); #if DEBUG Serial.begin(9600); Serial.println("\n[TVLED]"); #endif XBSerial.begin(9600); // set up XBee at 9600 bps delay(5); } void loop () { // process incoming data if (XBSerial.available()) { byte c = XBSerial.read(); buffer.print(c,BYTE); #if DEBUG Serial.print("rx="); Serial.println(c, BYTE); #endif // we need 4 bytes, 1 for eacht segment. if (buffer.length()==4) { #if DEBUG Serial.print("buffer="); Serial.println(buffer); #endif HandleCommand(); }; }; // handle the special case: full-on never toggles the LED // FIXME: this needs to be refined if not all pins are allocated to LED PWM PORTC = (PORTC & 0xF0) | (slots[255] & 0x0F); PORTD = (PORTC & 0x0F) | (slots[255] & 0xF0); // here, the LED state is known: all LEDs with levels < 255 are off for (byte i = 0; i < 255; ++i) { PINC = slots[i] & 0x0F; // toggle AIO pins for time slot i PIND = slots[i] & 0xF0; // toggle DIO pins for time slot i delayMicroseconds(31); } }