Tiny RGB Firmware

Work in progress, check back later.

  1. long foo;
  2. /**
  3.  * Tiny RGB is a PWM controller firmware for RGB LEDs. By default a
  4.  * RGB Fader mode is active cycling through random colors. A SoftSerial
  5.  * Port is made available on pins 2 and 3 @ 9600 baud to control various
  6.  * runtime parameters such as speed, bounds and fixed color values.
  7.  *
  8.  * Author: Paul Rogalinski, http://codewut.de
  9.  * License: Public Domain
  10.  *
  11.  * uses attiny core: http://code.google.com/p/arduino-tiny/
  12.  * developed & tested on ATTiny85 with interal 8mhz oscillator,
  13.  *
  14.  * fuses:
  15.  * extended: 0xff
  16.  * high: 0xd7
  17.  * low: 0xe2
  18.  *
  19.  * do not expect arduino timer based functions to work properly since
  20.  * the timer clocks have been modified.
  21.  *
  22.  * you will need to adjust bit- and framedelay values according to your
  23.  * internal RC oscillator caclibration and/or set OSCCAL register to
  24.  * callibrate manually. Serial communication won't work otherwise.
  25.  */
  26.  
  27. #include "TinySoftwareSerial.h"
  28. #include <avr/pgmspace.h>
  29. #include <stdarg.h>
  30.  
  31. //////////////////////////////////////////////////////////////////////////////////
  32. // USER SETTINGS
  33. #define PIN_RED 4
  34. #define PIN_BLUE 1
  35. #define PIN_GREEN 0
  36. #define PIN_BT_RX 2
  37. #define PIN_BT_TX 3
  38.  
  39. #define MAX_RED 0xff
  40. #define MAX_GREEN 0xff
  41. #define MAX_BLUE 0xff
  42.  
  43. #define FADE_WAIT 40
  44. #define RAISE_PWM_FREQUENCY 1
  45. #define LOCAL_ECHO 1;
  46. // END USER SETTINGS
  47. //////////////////////////////////////////////////////////////////////////////////
  48.  
  49. #ifdef RAISE_PWM_FREQUENCY
  50. #define CLCK_MULTIPLIER 16
  51. #else
  52. #define CLCK_MULTIPLIER 1
  53. #endif
  54.  
  55. #define MODE_FADE 1
  56. #define MODE_FIXED 2
  57.  
  58.  
  59. TinySoftwareSerial bts(PIN_BT_RX,PIN_BT_TX);
  60. int targetRed = 0, targetGreen = 0, targetBlue = 0; // target values
  61. int currentRed = 0, currentGreen = 0, currentBlue = 0; // current values
  62. int offsetRed = -40, offsetGreen = -40, offsetBlue = -40;
  63. uint8_t maxRed=255, maxGreen=255, maxBlue = 255;
  64. uint8_t mode = MODE_FADE;
  65. uint8_t wait = FADE_WAIT;
  66. char buffer[16];
  67.  
  68. prog_uchar welcome[] PROGMEM = {
  69. "\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"
  70. };
  71.  
  72.  
  73. void setup()
  74. {
  75. // OSCCAL = 0xff;
  76. #ifdef RAISE_PWM_FREQUENCY
  77. // set the PWM frequency to the highest possible synchronous rate
  78. // @see http://arduino.cc/playground/Main/TimerPWMCheatsheet for Arduino PWM frequency registers
  79. // the settings below are ATTiny*5 specific.
  80. TCCR0B = TCCR0B & 0b11111000 | 0b001;
  81. TCCR1 = TCCR1 & 0b11110000 | 0b0010;
  82. #endif
  83.  
  84. pinMode(PIN_RED, OUTPUT);
  85. digitalWrite(PIN_RED,HIGH);
  86.  
  87. pinMode(PIN_GREEN, OUTPUT);
  88. pinMode(PIN_BLUE, OUTPUT);
  89. pinMode(PIN_BT_TX, OUTPUT);
  90. pinMode(PIN_BT_RX, INPUT);
  91. digitalWrite(PIN_BT_RX,HIGH);
  92. digitalWrite(PIN_BT_TX,HIGH);
  93. delay(200);
  94. bts.begin(9600);
  95. bts._bitDelay = 75;
  96. bts._frameDelay = 27;
  97. delay(1000*CLCK_MULTIPLIER);
  98. digitalWrite(PIN_RED,LOW);
  99. digitalWrite(PIN_GREEN,HIGH);
  100. delay(1000*CLCK_MULTIPLIER);
  101. digitalWrite(PIN_GREEN,LOW);
  102. printHelp();
  103. }
  104.  
  105.  
  106. void loop()
  107. {
  108. if (mode == MODE_FADE)
  109. {
  110. if (targetRed == currentRed) targetRed = getNextRandom(maxRed, offsetRed, currentRed);
  111. if (targetGreen == currentGreen) targetGreen = getNextRandom(maxGreen, offsetGreen, currentGreen);
  112. if (targetBlue == currentBlue) targetBlue = getNextRandom(maxBlue, offsetBlue, currentBlue);
  113. currentRed += (currentRed < targetRed) ? 1 : -1;
  114. currentGreen += (currentGreen < targetGreen) ? 1 : -1;
  115. currentBlue += (currentBlue < targetBlue) ? 1 : -1;
  116. }
  117.  
  118. setRGB();
  119. long waitc = wait * CLCK_MULTIPLIER;
  120. while (--waitc > 0)
  121. {
  122. if (!digitalRead(PIN_BT_RX))
  123. {
  124. readLine(true);
  125. parseCommands();
  126. }
  127. delay(1);
  128. }
  129. }
  130.  
  131.  
  132. ///////////////////////////////////////////////////////////////////////// BT Commandline Parser
  133. void readLine(bool prompt)
  134. {
  135. char v;
  136. if (prompt)
  137. {
  138. v = (char)bts.read(); // do not use this first read, chances are it will be garbage.
  139. bts.print("< CMD: ");
  140. }
  141.  
  142. int c=0;
  143. do
  144. {
  145. v = (char)bts.read();
  146. buffer[c++] = v;
  147. buffer[c+1] = 0;
  148. #ifdef LOCAL_ECHO
  149. bts.print(v);
  150. #endif
  151. if (v == '\n' || v == '\r') break;
  152. } while (c <= 15);
  153. }
  154.  
  155. int readInt(char* prompt)
  156. {
  157. delay(200);
  158. bts.print(prompt);
  159. readLine(false);
  160. return atoi(buffer);
  161. }
  162.  
  163. uint8_t readUInt(char* prompt)
  164. {
  165. delay(200);
  166. bts.print(prompt);
  167. readLine(false);
  168. return clamp(atoi(buffer));
  169. }
  170.  
  171. void parseCommands()
  172. {
  173. if (memcmp ( buffer, "show", 4 )==0)
  174. {
  175. showValues();
  176. }
  177. else if (memcmp ( buffer, "set", 3)==0)
  178. {
  179. currentRed = readUInt("\r\n< r: ");
  180. currentGreen = readUInt("\r\n< g: ");
  181. currentBlue = readUInt("\r\n< b: ");
  182. mode = MODE_FIXED;
  183.  
  184. setRGB();
  185. printOK();
  186. showValues();
  187. printOK();
  188. }
  189. else if (memcmp ( buffer, "fade", 4)==0)
  190. {
  191. mode = MODE_FADE;
  192. printOK();
  193. }
  194. else if (memcmp ( buffer, "help", 4)==0)
  195. {
  196. printHelp();
  197. }
  198. else if (memcmp ( buffer, "speed", 5)==0)
  199. {
  200. mode = MODE_FADE;
  201. bts.print("\r\n> current: ");
  202. bts.print((int)wait);
  203. wait = readUInt("\r\n< new: ");
  204. printOK();
  205. }
  206. else if (memcmp ( buffer, "bounds", 6)==0)
  207. {
  208. maxRed = readUInt("\r\n< mR: ");
  209. maxGreen = readUInt("\r\n< mG: ");
  210. maxBlue = readUInt("\r\n< mB: ");
  211. offsetRed = readInt("\r\n< oR: ");
  212. offsetGreen = readInt("\r\n< oG: ");
  213. offsetBlue = readInt("\r\n< oB: ");
  214. printOK();
  215. showValues();
  216. }
  217. else
  218. {
  219. bts.print("> ERROR: Uknown Command\r\n");
  220. }
  221. }
  222.  
  223. void printOK()
  224. {
  225. bts.print("\r\n> OK\r\n");
  226. }
  227.  
  228. void showValues()
  229. {
  230. bts.print("> r:");
  231. bts.print((int)currentRed);
  232. bts.print(", g:");
  233. bts.print((int)currentGreen);
  234. bts.print(", b:");
  235. bts.print((int)currentBlue);
  236. bts.print(", or:");
  237. bts.print((int)offsetRed);
  238. bts.print(", og:");
  239. bts.print((int)offsetGreen);
  240. bts.print(", ob:");
  241. bts.print((int)offsetBlue);
  242. bts.print("\r\n");
  243. }
  244.  
  245. void printHelp()
  246. {
  247. char disp;
  248. int i = 0;
  249. while ((disp = pgm_read_byte_near(welcome + i++))!= '\t') bts.print(disp);
  250. }
  251.  
  252. //////////////////////////////////////////////////////////////////////////////// Utils
  253. void setRGB()
  254. {
  255. analogWrite(PIN_RED, currentRed);
  256. analogWrite(PIN_GREEN, currentGreen);
  257. analogWrite(PIN_BLUE, currentBlue);
  258. }
  259.  
  260. unsigned short getSeed()
  261. {
  262. unsigned short seed = 0;
  263. unsigned short *p = (unsigned short*) (RAMEND+1);
  264. extern unsigned short __heap_start;
  265. while (p >= &__heap_start + 1) seed ^= * (--p);
  266. return seed;
  267. }
  268.  
  269. // @see http://en.wikipedia.org/wiki/Random_number_generation
  270. unsigned long m_w = getSeed();
  271. unsigned long m_z = getSeed();
  272. unsigned long getRandom()
  273. {
  274. m_z = 36969L * (m_z & 65535L) + (m_z >> 16);
  275. m_w = 18000L * (m_w & 65535L) + (m_w >> 16);
  276. return (m_z << 16) + m_w;
  277. }
  278.  
  279. inline byte clamp(int value)
  280. {
  281. return value < 0 ? 0 : (value > 0xff ? 0xff : value);
  282. }
  283.  
  284. uint8_t getNextRandom(uint8_t max,int offset, uint8_t current)
  285. {
  286. uint8_t tmp;
  287. do
  288. {
  289. tmp = clamp(((getRandom() % max) + offset));
  290. }
  291. while (tmp == current);
  292. return tmp;
  293. }