root / RF12 / examples / rgbRemote / rgbRemote.pde
History | View | Annotate | Download (4.3 KB)
| 1 | //>>> The latest version of this code can be found at https://github.com/jcw/ !! |
|---|---|
| 2 | |
| 3 | // Control some LED strips, using settings received by wireless |
| 4 | // 2010-10-01 <jcw@equi4.com> http://opensource.org/licenses/mit-license.php |
| 5 | // $Id: rgbRemote.pde 7763 2011-12-11 01:28:16Z jcw $ |
| 6 | |
| 7 | // see http://jeelabs.org/2010/06/15/remote-rgb-strip-control/ |
| 8 | // and http://jeelabs.org/2010/10/03/software-pwm-at-1-khz/ |
| 9 | // |
| 10 | // 2010-06-12: delayed init of RF12 driver, to make LED startup a bit quicker |
| 11 | // 2010-09-08: adapted for 2x rgb with 0..100% intensity control |
| 12 | // 2010-10-01: back to 255 intensity levels, but with new TCT0-based trick |
| 13 | // |
| 14 | // example settings: |
| 15 | // |
| 16 | // off all 255,255,255,0,255,255,255,0,30s |
| 17 | // min all 255,255,255,1,255,255,255,1,30s |
| 18 | // max all 255,255,255,255,255,255,255,255,30s |
| 19 | // max cold 255,115,38,255,255,115,38,255,30s |
| 20 | // max medium 255,100,13,255,255,100,13,255,30s |
| 21 | // |
| 22 | // calm warm 255,90,8,25,255,90,8,25,30s |
| 23 | // max warm 255,90,8,255,255,90,8,255,30s |
| 24 | // |
| 25 | // TODO: save changes to EEPROM using interrupts, i.e. in the background |
| 26 | // TODO: staggered turn-on, to reduce the inrush current of time slot zero |
| 27 | |
| 28 | #include <Ports.h> |
| 29 | #include <RF12.h> |
| 30 | #include <EEPROM.h> |
| 31 | |
| 32 | #define DEBUG 0 |
| 33 | |
| 34 | #define BAND RF12_868MHZ // wireless frequency band |
| 35 | #define GROUP 5 // wireless net group |
| 36 | #define NODEID 30 // node id on wireless to which this sketch responds |
| 37 | #define NVALUES 8 // can be adjusted from 1..8 (must also adjust "masks") |
| 38 | |
| 39 | static byte settings[NVALUES]; // 0 = red, 1 = green, 2 = blue, 3 = white |
| 40 | static byte slots[256]; // time slots, toggles whenever a bit is set |
| 41 | |
| 42 | MilliTimer timer; |
| 43 | |
| 44 | // which setting affects which I/O pin: |
| 45 | // bits 0..3 = AIO1 .. AIO4 |
| 46 | // bits 4..7 = DIO1 .. DIO4 |
| 47 | static const byte masks[NVALUES] = {
|
| 48 | 0x20, 0x02, 0x80, 0x00, 0x08, 0x10, 0x01, 0x00 |
| 49 | }; |
| 50 | |
| 51 | static void setupIO() {
|
| 52 | for (byte i = 0; i < NVALUES; ++i) {
|
| 53 | PORTC &= ~ (masks[i] & 0x0F); // turn AIO pin off |
| 54 | DDRC |= masks[i] & 0x0F; // make pin an output |
| 55 | PORTD &= ~ (masks[i] & 0xF0); // turn DIO pin off |
| 56 | DDRD |= masks[i] & 0xF0; // make pin an output |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | static void prepareSlots() {
|
| 61 | #if DEBUG |
| 62 | Serial.print("RGB values:");
|
| 63 | for (byte i = 0; i < NVALUES; ++i) {
|
| 64 | Serial.print(' ');
|
| 65 | Serial.print(settings[i], DEC); |
| 66 | } |
| 67 | Serial.println(); |
| 68 | #endif |
| 69 | |
| 70 | // use 4th value as intensity control over RGB values |
| 71 | settings[0] = (settings[0] * settings[3] + 127) / 255; |
| 72 | settings[1] = (settings[1] * settings[3] + 127) / 255; |
| 73 | settings[2] = (settings[2] * settings[3] + 127) / 255; |
| 74 | // also for the second RGB group |
| 75 | settings[4] = (settings[4] * settings[7] + 127) / 255; |
| 76 | settings[5] = (settings[5] * settings[7] + 127) / 255; |
| 77 | settings[6] = (settings[6] * settings[7] + 127) / 255; |
| 78 | |
| 79 | // fill the slots arrray with on-bits, as implied by the intensity values |
| 80 | memset(slots, 0, sizeof slots); |
| 81 | for (byte i = 0; i < NVALUES; ++i) {
|
| 82 | // get the requested PWM level |
| 83 | word intensity = settings[i]; |
| 84 | // don't use intensities 1 and 254, as they would toggle within 4 us |
| 85 | // convert 0..255 values to 0 = off, 2..254 = dimmed, 256 = on |
| 86 | if (intensity > 0) ++intensity; // change 1..255 to 2..256 |
| 87 | if (intensity == 255) ++intensity; // change (original) 254 to 256 |
| 88 | // fill in the 1's |
| 89 | byte mask = masks[i]; // map setting to corresponding I/O pin |
| 90 | for (word i = 0; i < intensity; ++i) |
| 91 | slots[i] |= mask; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | static void loadSettings() {
|
| 96 | for (byte i = 0; i < NVALUES; ++i) |
| 97 | settings[i] = EEPROM.read(i); |
| 98 | prepareSlots(); |
| 99 | } |
| 100 | |
| 101 | static void saveSettings() {
|
| 102 | for (byte i = 0; i < NVALUES; ++i) |
| 103 | EEPROM.write(i, settings[i]); |
| 104 | prepareSlots(); |
| 105 | } |
| 106 | |
| 107 | static void showSettings() {
|
| 108 | } |
| 109 | |
| 110 | void setup () {
|
| 111 | #if DEBUG |
| 112 | Serial.begin(57600); |
| 113 | Serial.println("\n[rgbRemote]");
|
| 114 | #endif |
| 115 | setupIO(); |
| 116 | loadSettings(); |
| 117 | rf12_initialize(NODEID, BAND, GROUP); |
| 118 | } |
| 119 | |
| 120 | void loop() {
|
| 121 | if (timer.poll(100) && rf12_recvDone() |
| 122 | && rf12_hdr == (RF12_HDR_DST | NODEID) |
| 123 | && rf12_crc == 0 && rf12_len == NVALUES) {
|
| 124 | // turn LEDs off before making changes (saving takes time!) |
| 125 | PORTC &= 0xF0; |
| 126 | PORTD &= 0x0F; |
| 127 | memcpy(settings, (void*) rf12_data, rf12_len); |
| 128 | saveSettings(); |
| 129 | } |
| 130 | byte bits = slots[TCNT0]; |
| 131 | PORTC = (PORTC & 0xF0) | (bits & 0x0F); |
| 132 | PORTD = (PORTD & 0x0F) | (bits & 0xF0); |
| 133 | } |