Work in progress, check back later.
long foo; /** * Tiny RGB is a PWM controller firmware for RGB LEDs. By default a * RGB Fader mode is active cycling through random colors. A SoftSerial * Port is made available on pins 2 and 3 @ 9600 baud to control various * runtime parameters such as speed, bounds and fixed color values. * * Author: Paul Rogalinski, http://codewut.de * License: Public Domain * * uses attiny core: http://code.google.com/p/arduino-tiny/ * developed & tested on ATTiny85 with interal 8mhz oscillator, * * fuses: * extended: 0xff * high: 0xd7 * low: 0xe2 * * do not expect arduino timer based functions to work properly since * the timer clocks have been modified. * * you will need to adjust bit- and framedelay values according to your * internal RC oscillator caclibration and/or set OSCCAL register to * callibrate manually. Serial communication won't work otherwise. */ #include "TinySoftwareSerial.h" #include <avr/pgmspace.h> #include <stdarg.h> ////////////////////////////////////////////////////////////////////////////////// // USER SETTINGS #define PIN_RED 4 #define PIN_BLUE 1 #define PIN_GREEN 0 #define PIN_BT_RX 2 #define PIN_BT_TX 3 #define MAX_RED 0xff #define MAX_GREEN 0xff #define MAX_BLUE 0xff #define FADE_WAIT 40 #define RAISE_PWM_FREQUENCY 1 #define LOCAL_ECHO 1; // END USER SETTINGS ////////////////////////////////////////////////////////////////////////////////// #ifdef RAISE_PWM_FREQUENCY #define CLCK_MULTIPLIER 16 #else #define CLCK_MULTIPLIER 1 #endif #define MODE_FADE 1 #define MODE_FIXED 2 TinySoftwareSerial bts(PIN_BT_RX,PIN_BT_TX); int targetRed = 0, targetGreen = 0, targetBlue = 0; // target values int currentRed = 0, currentGreen = 0, currentBlue = 0; // current values int offsetRed = -40, offsetGreen = -40, offsetBlue = -40; uint8_t maxRed=255, maxGreen=255, maxBlue = 255; uint8_t mode = MODE_FADE; uint8_t wait = FADE_WAIT; char buffer[16]; prog_uchar welcome[] PROGMEM = { "\f\aTiny RGB 1.0 by Paul Rogalinski, paul@paul.vc\r\n\r\nKnown commands: \r\nshow - shows current rgb values\r\nset - sets a fixed rgb value\r\nfade - enters the color cycling mode\r\nbounds - sets bounds for max and offset rgb values for the fade mode\r\nspeed - speed in the fade mode, lower values are faster.\r\n\r\nSend any dummy byte (keypress) over serial to enter the commandline mode.\r\n\r\nREADY.\r\n\t" }; void setup() { // OSCCAL = 0xff; #ifdef RAISE_PWM_FREQUENCY // set the PWM frequency to the highest possible synchronous rate // @see http://arduino.cc/playground/Main/TimerPWMCheatsheet for Arduino PWM frequency registers // the settings below are ATTiny*5 specific. TCCR0B = TCCR0B & 0b11111000 | 0b001; TCCR1 = TCCR1 & 0b11110000 | 0b0010; #endif pinMode(PIN_RED, OUTPUT); digitalWrite(PIN_RED,HIGH); pinMode(PIN_GREEN, OUTPUT); pinMode(PIN_BLUE, OUTPUT); pinMode(PIN_BT_TX, OUTPUT); pinMode(PIN_BT_RX, INPUT); digitalWrite(PIN_BT_RX,HIGH); digitalWrite(PIN_BT_TX,HIGH); delay(200); bts.begin(9600); bts._bitDelay = 75; bts._frameDelay = 27; delay(1000*CLCK_MULTIPLIER); digitalWrite(PIN_RED,LOW); digitalWrite(PIN_GREEN,HIGH); delay(1000*CLCK_MULTIPLIER); digitalWrite(PIN_GREEN,LOW); printHelp(); } void loop() { if (mode == MODE_FADE) { if (targetRed == currentRed) targetRed = getNextRandom(maxRed, offsetRed, currentRed); if (targetGreen == currentGreen) targetGreen = getNextRandom(maxGreen, offsetGreen, currentGreen); if (targetBlue == currentBlue) targetBlue = getNextRandom(maxBlue, offsetBlue, currentBlue); currentRed += (currentRed < targetRed) ? 1 : -1; currentGreen += (currentGreen < targetGreen) ? 1 : -1; currentBlue += (currentBlue < targetBlue) ? 1 : -1; } setRGB(); long waitc = wait * CLCK_MULTIPLIER; while (--waitc > 0) { if (!digitalRead(PIN_BT_RX)) { readLine(true); parseCommands(); } delay(1); } } ///////////////////////////////////////////////////////////////////////// BT Commandline Parser void readLine(bool prompt) { char v; if (prompt) { v = (char)bts.read(); // do not use this first read, chances are it will be garbage. bts.print("< CMD: "); } int c=0; do { v = (char)bts.read(); buffer[c++] = v; buffer[c+1] = 0; #ifdef LOCAL_ECHO bts.print(v); #endif if (v == '\n' || v == '\r') break; } while (c <= 15); } int readInt(char* prompt) { delay(200); bts.print(prompt); readLine(false); return atoi(buffer); } uint8_t readUInt(char* prompt) { delay(200); bts.print(prompt); readLine(false); return clamp(atoi(buffer)); } void parseCommands() { if (memcmp ( buffer, "show", 4 )==0) { showValues(); } else if (memcmp ( buffer, "set", 3)==0) { currentRed = readUInt("\r\n< r: "); currentGreen = readUInt("\r\n< g: "); currentBlue = readUInt("\r\n< b: "); mode = MODE_FIXED; setRGB(); printOK(); showValues(); printOK(); } else if (memcmp ( buffer, "fade", 4)==0) { mode = MODE_FADE; printOK(); } else if (memcmp ( buffer, "help", 4)==0) { printHelp(); } else if (memcmp ( buffer, "speed", 5)==0) { mode = MODE_FADE; bts.print("\r\n> current: "); bts.print((int)wait); wait = readUInt("\r\n< new: "); printOK(); } else if (memcmp ( buffer, "bounds", 6)==0) { maxRed = readUInt("\r\n< mR: "); maxGreen = readUInt("\r\n< mG: "); maxBlue = readUInt("\r\n< mB: "); offsetRed = readInt("\r\n< oR: "); offsetGreen = readInt("\r\n< oG: "); offsetBlue = readInt("\r\n< oB: "); printOK(); showValues(); } else { bts.print("> ERROR: Uknown Command\r\n"); } } void printOK() { bts.print("\r\n> OK\r\n"); } void showValues() { bts.print("> r:"); bts.print((int)currentRed); bts.print(", g:"); bts.print((int)currentGreen); bts.print(", b:"); bts.print((int)currentBlue); bts.print(", or:"); bts.print((int)offsetRed); bts.print(", og:"); bts.print((int)offsetGreen); bts.print(", ob:"); bts.print((int)offsetBlue); bts.print("\r\n"); } void printHelp() { char disp; int i = 0; while ((disp = pgm_read_byte_near(welcome + i++))!= '\t') bts.print(disp); } //////////////////////////////////////////////////////////////////////////////// Utils void setRGB() { analogWrite(PIN_RED, currentRed); analogWrite(PIN_GREEN, currentGreen); analogWrite(PIN_BLUE, currentBlue); } unsigned short getSeed() { unsigned short seed = 0; unsigned short *p = (unsigned short*) (RAMEND+1); extern unsigned short __heap_start; while (p >= &__heap_start + 1) seed ^= * (--p); return seed; } // @see http://en.wikipedia.org/wiki/Random_number_generation unsigned long m_w = getSeed(); unsigned long m_z = getSeed(); unsigned long getRandom() { m_z = 36969L * (m_z & 65535L) + (m_z >> 16); m_w = 18000L * (m_w & 65535L) + (m_w >> 16); return (m_z << 16) + m_w; } inline byte clamp(int value) { return value < 0 ? 0 : (value > 0xff ? 0xff : value); } uint8_t getNextRandom(uint8_t max,int offset, uint8_t current) { uint8_t tmp; do { tmp = clamp(((getRandom() % max) + offset)); } while (tmp == current); return tmp; }