Difference between revisions of "Techinc Wheel"
m (link to neopixel lib) |
|||
(43 intermediate revisions by 7 users not shown) | |||
Line 2: | Line 2: | ||
|picture=20130729-techinc-wheel-at-ohm.jpeg | |picture=20130729-techinc-wheel-at-ohm.jpeg | ||
|ProjectSkills=Electronics, Mechanics, | |ProjectSkills=Electronics, Mechanics, | ||
− | |ProjectStatus= | + | |ProjectStatus=Finished |
|ProjectNiche=Electronics | |ProjectNiche=Electronics | ||
|ProjectPurpose=Promotion | |ProjectPurpose=Promotion | ||
}} | }} | ||
− | + | == Bringing the wheel to events == | |
− | + | If you can't reach Narya or Mariejel, assume a "yes" when you (a techinc member) want to bring the wheel to an event. Please put it back on the wall when the event is over. If the LEDs come loose you can simply put it back with double-sided tape and/or ductape. | |
− | |||
− | == Things to make and do == | + | == Summary == |
− | This project has several parts: '''backlit''' the wheel, '''mount''' the wheel to the wall or on some stand, and make the wheel '''control''' something. It would be nice to be able to unmount the wheel and take it somewhere else, e.g. to display it at events | + | |
+ | * The wooden techinc wheel has a WS2801 LED strip stuck on the back and is controlled via an <s>Arduino Nano</s> esp8266 with ESPHome | ||
+ | * The 8 strips consist of 5 pixels each (3 LEDs per pixel). The first "spoke" goes outwards, the second inwards, the third outwards, etc | ||
+ | * The data pin is GPIO4 and the clock pin GPIO2 | ||
+ | * Color order is BRG, which is supported by the FastLED library, but for other libraries you need to put the colors in the right order | ||
+ | * The Wheel is on wifi, as 'ti-wheel.local' | ||
+ | * The wheel is connected to our HomeAssistant instance on https://spass.techinc.nl: device light.techinc_wheel | ||
+ | * The old arduino which ran the wheel before is attached to the power supply, in case a revert is ever needed. | ||
+ | |||
+ | Feel free to add/suggest extra code to the ESPhome settup, add sensors or whatever. | ||
+ | |||
+ | [http://www.narya.dds.nl/stuff/techinc-wheel.mp4 MOVING PICTURES] | ||
+ | |||
+ | [[File:wheelesp.jpg|thumb|the brains of the project]] | ||
+ | |||
+ | The wheel is not connected to [[Powerbars]] | ||
+ | |||
+ | == Old Code == | ||
+ | <s>Currently the ColorPalette code runs on the Arduino.</s> | ||
+ | |||
+ | <s>[https://github.com/techinc/wheel Arduino code] - ''work in progress''</s> | ||
+ | |||
+ | ==Things to make and do== | ||
+ | |||
+ | This project has several parts: '''backlit''' the wheel, '''mount''' the wheel to the wall or on some stand, and make the wheel '''control''' something. It would be nice to be able to unmount the wheel and take it somewhere else, e.g. to display it at events. | ||
+ | |||
+ | === Mount === | ||
+ | Who: justa, narya, control-k | ||
+ | * <s>Location: on the wall - done</s> | ||
+ | * Location: infront of the window - Done | ||
+ | [[File:wheel-on-the-wall.JPG|200px|thumb|none|wheel when it was mounted on the wall]] | ||
=== Painting === | === Painting === | ||
− | |||
* NO color painting! | * NO color painting! | ||
− | * | + | * Scratched parts could eventually be fixed with varnish |
=== Backlit === | === Backlit === | ||
− | Who: [[User:Narya|Narya]], [[User:Brainsmoke | Brainsmoke]] and [[User:Mariejel | Mariejel]] | + | Who: [[User:Narya|Narya]], [[User:Brainsmoke | Brainsmoke]] and [[User:Mariejel | Mariejel]] |
− | + | Who, later: [[User:Justa|Justa]] who moved it to ESPHome | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Soldering: done | |
− | |||
− | |||
− | |||
− | + | '''WS2801 12V magic strip''' | |
− | * | + | * 12V |
− | * | + | * 40 addressable pixels, color profile BRG |
− | * | + | * Wires: green 12V (not attached), blue clock (<s>pin 11</s> GPIO02), red data (<s>pin 12</s> GPIO04), black GND (pin GND) |
− | |||
− | + | ==== Color patterns ==== | |
− | + | * Make a few color patterns: | |
− | * Make a | ||
** No rotation: colors of logo | ** No rotation: colors of logo | ||
− | ** | + | ** From center to outside and vice versa (knight rider) |
− | + | ** Rainbow glow - Done | |
− | + | ** Rotating colors - Done | |
+ | ** FIRE - Done | ||
+ | ** Twinkle - Done | ||
+ | |||
+ | ==== Sensors ==== | ||
+ | * Color sensor to change knight rider color for example | ||
+ | * Distance sensor: change color and/or speed. If hand is within 4cm it can function as a switch (switch between color programs) | ||
+ | |||
+ | === Software === | ||
+ | * FastLED library http://fastled.io/ | ||
+ | * Neopixel library https://github.com/adafruit/Adafruit_NeoPixel | ||
+ | * Adafruit_WS2801 https://github.com/adafruit/Adafruit-WS2801-Library | ||
+ | * FastSPI library https://code.google.com/p/fastspi/ | ||
+ | * ShiftPWM http://www.elcojacobs.com/using-shiftpwm-to-control-led-strips-with-arduino/ | ||
+ | * Related projects @techinc: [[LEDLightDistrict]], [[Neopixel]] | ||
+ | |||
+ | |||
− | === | + | == Old == |
− | + | [[Techinc_Wheel/Old]] | |
− | * | + | |
+ | == Recent code == | ||
+ | |||
+ | The most recent code should be on the ESPHome plugin of Home Assistant. | ||
+ | Below is a copy of the code as it is on 2023-10-19, for informative purposes. | ||
+ | |||
+ | <pre> | ||
+ | substitutions: | ||
+ | devicename: ti-wheel | ||
+ | friendly_name: TI Wheel | ||
+ | device_description: ESP12E TI Wheel Profile | ||
+ | project_name: "Espressif.ESP12E" | ||
+ | project_version: "ESP12E TI Wheel by Justa" | ||
+ | # ${friendly_name} | ||
+ | |||
+ | esphome: | ||
+ | name: $devicename | ||
+ | comment: ${device_description} | ||
+ | project: | ||
+ | name: ${project_name} | ||
+ | version: ${project_version} | ||
+ | on_boot: | ||
+ | priority: 600 | ||
+ | then: | ||
+ | light.turn_on: | ||
+ | id: 'ti_wheel' | ||
+ | effect: 'Rainbow' | ||
+ | |||
+ | esp8266: | ||
+ | board: esp12e | ||
+ | framework: | ||
+ | version: 2.7.4 | ||
+ | |||
+ | wifi: | ||
+ | ssid: !secret wifi_ssid | ||
+ | password: !secret wifi_password | ||
+ | fast_connect: True | ||
+ | # use_address: [REDACTED] | ||
+ | # enable_mdns: True | ||
+ | |||
+ | # Enable fallback hotspot (captive portal) in case wifi connection fails | ||
+ | ap: | ||
+ | ssid: "${friendly_name} Fallback Hotspot" | ||
+ | password: !secret hotspot_password | ||
+ | |||
+ | captive_portal: | ||
+ | |||
+ | # Enable logging | ||
+ | logger: | ||
+ | |||
+ | # Enable Home Assistant API | ||
+ | api: | ||
+ | encryption: | ||
+ | key: !secret api_key | ||
+ | #password: !secret api_password | ||
+ | reboot_timeout: 0s | ||
+ | |||
+ | ota: | ||
+ | password: !secret ota_password | ||
+ | safe_mode: True | ||
+ | |||
+ | web_server: | ||
+ | port: 80 | ||
+ | # local: true | ||
+ | auth: | ||
+ | username: !secret web_user | ||
+ | password: !secret web_password | ||
+ | |||
+ | light: | ||
+ | - platform: fastled_spi | ||
+ | name: "Techinc Wheel" | ||
+ | id: "ti_wheel" | ||
+ | chipset: WS2801 | ||
+ | data_pin: GPIO4 | ||
+ | clock_pin: GPIO2 | ||
+ | num_leds: 40 | ||
+ | rgb_order: BRG | ||
+ | effects: | ||
+ | - addressable_rainbow: | ||
+ | name: Rainbow | ||
+ | speed: 10 | ||
+ | width: 40 | ||
+ | - strobe: | ||
+ | name: Strobe1 | ||
+ | colors: | ||
+ | - state: true | ||
+ | brightness: 100% | ||
+ | red: 100% | ||
+ | green: 90% | ||
+ | blue: 0% | ||
+ | duration: 500ms | ||
+ | - state: false | ||
+ | duration: 250ms | ||
+ | - state: true | ||
+ | brightness: 100% | ||
+ | red: 0% | ||
+ | green: 100% | ||
+ | blue: 0% | ||
+ | duration: 500ms | ||
+ | - addressable_twinkle: | ||
+ | name: Twinkle | ||
+ | twinkle_probability: 5% | ||
+ | progress_interval: 4ms | ||
+ | - addressable_lambda: | ||
+ | name: "Fire" | ||
+ | update_interval: 15ms | ||
+ | lambda: |- | ||
+ | int Cooling = 55; | ||
+ | int Sparking = 110; | ||
+ | // Adjust size of array to length of pixels | ||
+ | static byte heat[40]; | ||
+ | int cooldown; | ||
+ | |||
+ | // Step 1. Cool down every cell a little | ||
+ | for( int i = 0; i < it.size(); i++) { | ||
+ | cooldown = random(0, ((Cooling * 10) / it.size()) + 2); | ||
+ | |||
+ | if(cooldown>heat[i]) { | ||
+ | heat[i]=0; | ||
+ | } else { | ||
+ | heat[i]=heat[i]-cooldown; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Step 2. Heat from each cell drifts 'up' and diffuses a little | ||
+ | for( int k= it.size() - 1; k >= 2; k--) { | ||
+ | heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; | ||
+ | } | ||
+ | |||
+ | // Step 3. Randomly ignite new 'sparks' near the bottom | ||
+ | if( random(255) < Sparking ) { | ||
+ | int y = random(7); | ||
+ | heat[y] = heat[y] + random(160,255); | ||
+ | } | ||
+ | |||
+ | // Step 4. Convert heat to LED colors | ||
+ | for( int Pixel = 0; Pixel < it.size(); Pixel++) { | ||
+ | // Scale 'heat' down from 0-255 to 0-191 | ||
+ | byte t192 = round((heat[Pixel]/255.0)*191); | ||
+ | |||
+ | // calculate ramp up from | ||
+ | byte heatramp = t192 & 0x3F; // 0..63 | ||
+ | heatramp <<= 2; // scale up to 0..252 | ||
+ | |||
+ | // figure out which third of the spectrum we're in: | ||
+ | //this is where you can reverse the effect by switching the commented out lines in all 3 places. | ||
+ | if( t192 > 0x80) { // hottest | ||
+ | //it[it.size() - Pixel - 1] = ESPColor(255, 255, heatramp); | ||
+ | it[Pixel] = ESPColor(255, 255, heatramp); | ||
+ | } else if( t192 > 0x40 ) { // middle | ||
+ | //it[it.size() - Pixel - 1] = ESPColor(255, heatramp, 0); | ||
+ | it[Pixel] = ESPColor(255, heatramp, 0); | ||
+ | } else { // coolest | ||
+ | //it[it.size() - Pixel - 1] = ESPColor(heatramp, 0, 0); | ||
+ | it[Pixel] = ESPColor(heatramp, 0, 0); | ||
+ | } | ||
+ | } | ||
+ | button: | ||
+ | - platform: restart | ||
+ | name: "${friendly_name} Restart Button" | ||
+ | |||
+ | switch: | ||
+ | - platform: restart | ||
+ | name: "${friendly_name} Restart" | ||
+ | - platform: safe_mode | ||
+ | name: "${friendly_name} Restart (Safe Mode)" | ||
+ | - platform: shutdown | ||
+ | name: "${friendly_name} Shutdown" | ||
+ | |||
+ | binary_sensor: | ||
+ | - platform: status | ||
+ | name: "${friendly_name} Status" | ||
+ | sensor: | ||
+ | - platform: uptime | ||
+ | name: "${friendly_name} Uptime" | ||
+ | id: uptime_sensor | ||
+ | update_interval: 30s | ||
+ | on_raw_value: | ||
+ | then: | ||
+ | - text_sensor.template.publish: | ||
+ | id: uptime_human | ||
+ | state: !lambda |- | ||
+ | int seconds = round(id(uptime_sensor).raw_state); | ||
+ | int days = seconds / (24 * 3600); | ||
+ | seconds = seconds % (24 * 3600); | ||
+ | int hours = seconds / 3600; | ||
+ | seconds = seconds % 3600; | ||
+ | int minutes = seconds / 60; | ||
+ | seconds = seconds % 60; | ||
+ | return ( | ||
+ | (days ? String(days) + "d " : "") + | ||
+ | (hours ? String(hours) + "h " : "") + | ||
+ | (minutes ? String(minutes) + "m " : "") + | ||
+ | (String(seconds) + "s") | ||
+ | ).c_str(); | ||
+ | |||
+ | text_sensor: | ||
+ | - platform: template | ||
+ | name: "${friendly_name} Human Uptime" | ||
+ | id: uptime_human | ||
+ | icon: mdi:clock-start | ||
+ | - platform: version | ||
+ | name: "${friendly_name} Version" | ||
+ | icon: mdi:new-box | ||
+ | hide_timestamp: True | ||
+ | - platform: wifi_info | ||
+ | ip_address: | ||
+ | name: "${friendly_name} IP Address" | ||
+ | icon: mdi:ip-network-outline | ||
− | + | </pre> | |
− | |||
− | + | == Old Arduino inmplementation == | |
− | + | <code> | |
− | + | ||
− | + | #include <SPI.h> | |
+ | |||
+ | void setup() | ||
+ | { | ||
+ | SPI.begin(); | ||
+ | SPI.setBitOrder(MSBFIRST); | ||
+ | SPI.setDataMode(SPI_MODE0); | ||
+ | SPI.setClockDivider(SPI_CLOCK_DIV8); | ||
+ | } | ||
+ | |||
+ | uint8_t fade[] = | ||
+ | { | ||
+ | //[ int(((.5-cos(2*pi*x/240.)*.5)**2.2)*255) for x in range(240) ] | ||
+ | |||
+ | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,3,3,4,4,5,6,7,7,8,9,10,12,13,14,16,17,19,20,22,24,26,28,30,33,35,38,40,43,46,49,52,55,58,62,65,69,72,76,80,84,88,92,96,100,104,108,113,117,121,126,130,135,139,144,148,153,157,162,166,171,175,179,184,188,192,196,200,204,208,211,215,218,222,225,228,231,234,236,239,241,243,245,247,248,250,251,252,253,254,254,254,255,254,254,254,253,252,251,250,248,247,245,243,241,239,236,234,231,228,225,222,218,215,211,208,204,200,196,192,188,184,179,175,171,166,162,157,153,148,144,139,135,130,126,121,117,113,108,104,100,96,92,88,84,80,76,72,69,65,62,58,55,52,49,46,43,40,38,35,33,30,28,26,24,22,20,19,17,16,14,13,12,10,9,8,7,7,6,5,4,4,3,3,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | ||
+ | }; | ||
+ | |||
+ | uint8_t r=0,g=80,b=160; | ||
+ | |||
+ | void loop() | ||
+ | { | ||
+ | for(;;) | ||
+ | { | ||
+ | r+=1;g+=1;b+=1; | ||
+ | |||
+ | for (i=0; i<40; i++) | ||
+ | { | ||
+ | r+=6;g+=6;b+=6; | ||
+ | if (r >= 240) r-= 240; | ||
+ | if (g >= 240) g-= 240; | ||
+ | if (b >= 240) b-= 240; | ||
+ | |||
+ | SPI.transfer(fade[r]); | ||
+ | SPI.transfer(fade[g]); | ||
+ | SPI.transfer(fade[b]); | ||
+ | |||
+ | } | ||
+ | delay(20); | ||
+ | } | ||
+ | } | ||
+ | </code> |
Latest revision as of 15:55, 16 November 2023
Projects | |
---|---|
Participants | Narya |
Skills | Electronics, Mechanics |
Status | Finished |
Niche | Electronics |
Purpose | Promotion |
Contents
Bringing the wheel to events
If you can't reach Narya or Mariejel, assume a "yes" when you (a techinc member) want to bring the wheel to an event. Please put it back on the wall when the event is over. If the LEDs come loose you can simply put it back with double-sided tape and/or ductape.
Summary
- The wooden techinc wheel has a WS2801 LED strip stuck on the back and is controlled via an
Arduino Nanoesp8266 with ESPHome - The 8 strips consist of 5 pixels each (3 LEDs per pixel). The first "spoke" goes outwards, the second inwards, the third outwards, etc
- The data pin is GPIO4 and the clock pin GPIO2
- Color order is BRG, which is supported by the FastLED library, but for other libraries you need to put the colors in the right order
- The Wheel is on wifi, as 'ti-wheel.local'
- The wheel is connected to our HomeAssistant instance on https://spass.techinc.nl: device light.techinc_wheel
- The old arduino which ran the wheel before is attached to the power supply, in case a revert is ever needed.
Feel free to add/suggest extra code to the ESPhome settup, add sensors or whatever.
The wheel is not connected to Powerbars
Old Code
Currently the ColorPalette code runs on the Arduino.
Arduino code - work in progress
Things to make and do
This project has several parts: backlit the wheel, mount the wheel to the wall or on some stand, and make the wheel control something. It would be nice to be able to unmount the wheel and take it somewhere else, e.g. to display it at events.
Mount
Who: justa, narya, control-k
-
Location: on the wall - done - Location: infront of the window - Done
Painting
- NO color painting!
- Scratched parts could eventually be fixed with varnish
Backlit
Who: Narya, Brainsmoke and Mariejel
Who, later: Justa who moved it to ESPHome
Soldering: done
WS2801 12V magic strip
- 12V
- 40 addressable pixels, color profile BRG
- Wires: green 12V (not attached), blue clock (
pin 11GPIO02), red data (pin 12GPIO04), black GND (pin GND)
Color patterns
- Make a few color patterns:
- No rotation: colors of logo
- From center to outside and vice versa (knight rider)
- Rainbow glow - Done
- Rotating colors - Done
- FIRE - Done
- Twinkle - Done
Sensors
- Color sensor to change knight rider color for example
- Distance sensor: change color and/or speed. If hand is within 4cm it can function as a switch (switch between color programs)
Software
- FastLED library http://fastled.io/
- Neopixel library https://github.com/adafruit/Adafruit_NeoPixel
- Adafruit_WS2801 https://github.com/adafruit/Adafruit-WS2801-Library
- FastSPI library https://code.google.com/p/fastspi/
- ShiftPWM http://www.elcojacobs.com/using-shiftpwm-to-control-led-strips-with-arduino/
- Related projects @techinc: LEDLightDistrict, Neopixel
Old
Recent code
The most recent code should be on the ESPHome plugin of Home Assistant. Below is a copy of the code as it is on 2023-10-19, for informative purposes.
substitutions: devicename: ti-wheel friendly_name: TI Wheel device_description: ESP12E TI Wheel Profile project_name: "Espressif.ESP12E" project_version: "ESP12E TI Wheel by Justa" # ${friendly_name} esphome: name: $devicename comment: ${device_description} project: name: ${project_name} version: ${project_version} on_boot: priority: 600 then: light.turn_on: id: 'ti_wheel' effect: 'Rainbow' esp8266: board: esp12e framework: version: 2.7.4 wifi: ssid: !secret wifi_ssid password: !secret wifi_password fast_connect: True # use_address: [REDACTED] # enable_mdns: True # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "${friendly_name} Fallback Hotspot" password: !secret hotspot_password captive_portal: # Enable logging logger: # Enable Home Assistant API api: encryption: key: !secret api_key #password: !secret api_password reboot_timeout: 0s ota: password: !secret ota_password safe_mode: True web_server: port: 80 # local: true auth: username: !secret web_user password: !secret web_password light: - platform: fastled_spi name: "Techinc Wheel" id: "ti_wheel" chipset: WS2801 data_pin: GPIO4 clock_pin: GPIO2 num_leds: 40 rgb_order: BRG effects: - addressable_rainbow: name: Rainbow speed: 10 width: 40 - strobe: name: Strobe1 colors: - state: true brightness: 100% red: 100% green: 90% blue: 0% duration: 500ms - state: false duration: 250ms - state: true brightness: 100% red: 0% green: 100% blue: 0% duration: 500ms - addressable_twinkle: name: Twinkle twinkle_probability: 5% progress_interval: 4ms - addressable_lambda: name: "Fire" update_interval: 15ms lambda: |- int Cooling = 55; int Sparking = 110; // Adjust size of array to length of pixels static byte heat[40]; int cooldown; // Step 1. Cool down every cell a little for( int i = 0; i < it.size(); i++) { cooldown = random(0, ((Cooling * 10) / it.size()) + 2); if(cooldown>heat[i]) { heat[i]=0; } else { heat[i]=heat[i]-cooldown; } } // Step 2. Heat from each cell drifts 'up' and diffuses a little for( int k= it.size() - 1; k >= 2; k--) { heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; } // Step 3. Randomly ignite new 'sparks' near the bottom if( random(255) < Sparking ) { int y = random(7); heat[y] = heat[y] + random(160,255); } // Step 4. Convert heat to LED colors for( int Pixel = 0; Pixel < it.size(); Pixel++) { // Scale 'heat' down from 0-255 to 0-191 byte t192 = round((heat[Pixel]/255.0)*191); // calculate ramp up from byte heatramp = t192 & 0x3F; // 0..63 heatramp <<= 2; // scale up to 0..252 // figure out which third of the spectrum we're in: //this is where you can reverse the effect by switching the commented out lines in all 3 places. if( t192 > 0x80) { // hottest //it[it.size() - Pixel - 1] = ESPColor(255, 255, heatramp); it[Pixel] = ESPColor(255, 255, heatramp); } else if( t192 > 0x40 ) { // middle //it[it.size() - Pixel - 1] = ESPColor(255, heatramp, 0); it[Pixel] = ESPColor(255, heatramp, 0); } else { // coolest //it[it.size() - Pixel - 1] = ESPColor(heatramp, 0, 0); it[Pixel] = ESPColor(heatramp, 0, 0); } } button: - platform: restart name: "${friendly_name} Restart Button" switch: - platform: restart name: "${friendly_name} Restart" - platform: safe_mode name: "${friendly_name} Restart (Safe Mode)" - platform: shutdown name: "${friendly_name} Shutdown" binary_sensor: - platform: status name: "${friendly_name} Status" sensor: - platform: uptime name: "${friendly_name} Uptime" id: uptime_sensor update_interval: 30s on_raw_value: then: - text_sensor.template.publish: id: uptime_human state: !lambda |- int seconds = round(id(uptime_sensor).raw_state); int days = seconds / (24 * 3600); seconds = seconds % (24 * 3600); int hours = seconds / 3600; seconds = seconds % 3600; int minutes = seconds / 60; seconds = seconds % 60; return ( (days ? String(days) + "d " : "") + (hours ? String(hours) + "h " : "") + (minutes ? String(minutes) + "m " : "") + (String(seconds) + "s") ).c_str(); text_sensor: - platform: template name: "${friendly_name} Human Uptime" id: uptime_human icon: mdi:clock-start - platform: version name: "${friendly_name} Version" icon: mdi:new-box hide_timestamp: True - platform: wifi_info ip_address: name: "${friendly_name} IP Address" icon: mdi:ip-network-outline
Old Arduino inmplementation
#include <SPI.h> void setup() { SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); SPI.setClockDivider(SPI_CLOCK_DIV8); } uint8_t fade[] = { //[ int(((.5-cos(2*pi*x/240.)*.5)**2.2)*255) for x in range(240) ] 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,3,3,4,4,5,6,7,7,8,9,10,12,13,14,16,17,19,20,22,24,26,28,30,33,35,38,40,43,46,49,52,55,58,62,65,69,72,76,80,84,88,92,96,100,104,108,113,117,121,126,130,135,139,144,148,153,157,162,166,171,175,179,184,188,192,196,200,204,208,211,215,218,222,225,228,231,234,236,239,241,243,245,247,248,250,251,252,253,254,254,254,255,254,254,254,253,252,251,250,248,247,245,243,241,239,236,234,231,228,225,222,218,215,211,208,204,200,196,192,188,184,179,175,171,166,162,157,153,148,144,139,135,130,126,121,117,113,108,104,100,96,92,88,84,80,76,72,69,65,62,58,55,52,49,46,43,40,38,35,33,30,28,26,24,22,20,19,17,16,14,13,12,10,9,8,7,7,6,5,4,4,3,3,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; uint8_t r=0,g=80,b=160; void loop() { for(;;) { r+=1;g+=1;b+=1; for (i=0; i<40; i++) { r+=6;g+=6;b+=6; if (r >= 240) r-= 240; if (g >= 240) g-= 240; if (b >= 240) b-= 240; SPI.transfer(fade[r]); SPI.transfer(fade[g]); SPI.transfer(fade[b]); } delay(20); } }