├── .gitignore ├── LED Episode 06 ├── .vscode │ ├── settings.json │ ├── extensions.json │ └── tasks.json ├── .gitignore ├── platformio.ini ├── src │ ├── comet.h │ ├── twinkle.h │ ├── marquee.h │ ├── main.cpp │ └── bounce.h ├── lib │ └── README ├── include │ └── README └── .travis.yml ├── Fans ├── .gitignore ├── .vscode │ └── extensions.json ├── platformio.ini ├── include │ ├── twinkle.h │ ├── comet.h │ ├── marquee.h │ ├── fire.h │ ├── bounce.h │ └── ledgfx.h ├── lib │ └── README └── src │ └── main.cpp ├── LED Episode 02 ├── .gitignore ├── .vscode │ └── extensions.json ├── platformio.ini ├── test │ └── README ├── lib │ └── README ├── include │ └── README ├── .travis.yml └── src │ └── main.cpp ├── LED Episode 03 ├── .gitignore ├── .vscode │ └── extensions.json ├── test │ └── README ├── platformio.ini ├── src │ ├── v1.cpp │ └── main.cpp ├── lib │ └── README ├── include │ └── README └── .travis.yml ├── LED Episode 07 ├── .gitignore ├── .vscode │ └── extensions.json ├── platformio.ini ├── src │ ├── comet.h │ ├── twinkle.h │ ├── marquee.h │ ├── bounce.h │ └── main.cpp ├── lib │ └── README └── include │ └── README ├── LED Episode 08 ├── .gitignore ├── .vscode │ └── extensions.json ├── platformio.ini ├── src │ ├── comet.h │ ├── twinkle.h │ ├── marquee.h │ ├── bounce.h │ └── main.cpp ├── lib │ └── README └── include │ └── README ├── LED Episode 09 ├── .gitignore ├── .vscode │ └── extensions.json ├── platformio.ini ├── src │ ├── comet.h │ ├── twinkle.h │ ├── marquee.h │ ├── main.cpp │ └── bounce.h ├── lib │ └── README └── include │ └── README ├── LED Episode 10 ├── .gitignore ├── .vscode │ └── extensions.json ├── platformio.ini ├── include │ ├── twinkle.h │ ├── comet.h │ ├── marquee.h │ ├── ledgfx.h │ ├── bounce.h │ └── fire.h ├── lib │ └── README └── src │ └── main.cpp └── LED Episode 11 ├── .gitignore ├── .vscode └── extensions.json ├── platformio.ini ├── include ├── twinkle.h ├── comet.h ├── marquee.h ├── fire.h ├── bounce.h └── ledgfx.h ├── lib └── README └── src └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LED Episode 06/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.tcc": "cpp" 4 | } 5 | } -------------------------------------------------------------------------------- /Fans/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 02/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 03/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 06/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 07/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 08/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 09/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 10/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /LED Episode 11/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /Fans/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 02/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 03/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 06/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 07/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 08/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 09/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 10/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 11/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LED Episode 06/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "PlatformIO", 6 | "task": "Build", 7 | "problemMatcher": [ 8 | "$platformio" 9 | ], 10 | "group": "build", 11 | "label": "PlatformIO: Build" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /LED Episode 02/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32dev] 12 | platform = espressif32 13 | board = esp32dev 14 | framework = arduino 15 | -------------------------------------------------------------------------------- /LED Episode 02/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /LED Episode 03/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /LED Episode 03/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | upload_port = /dev/cu.usbserial-4 16 | lib_deps = U8g2 17 | 18 | -------------------------------------------------------------------------------- /LED Episode 03/src/v1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define DISPLAY_CLOCK_PIN 15 5 | #define DISPLAY_DATA_PIN 4 6 | #define DISPLAY_RESET_PIN 16 7 | 8 | U8G2_SSD1306_128X64_NONAME_F_SW_I2C g_OLED(U8G2_R2, DISPLAY_CLOCK_PIN, DISPLAY_DATA_PIN, DISPLAY_RESET_PIN); 9 | 10 | void setup() 11 | { 12 | g_OLED.begin(); 13 | g_OLED.clear(); 14 | g_OLED.setFont(u8g2_font_profont15_tf); // Choose a suitable font 15 | g_OLED.setCursor(2, 12); // Cursor is at bottom of letter, so we need to move down 16 | g_OLED.print("Hello World"); 17 | g_OLED.sendBuffer(); 18 | } 19 | 20 | void loop() 21 | { 22 | digitalWrite(LED_BUILTIN, 0); 23 | delay(100); 24 | digitalWrite(LED_BUILTIN, 1); 25 | delay(100); 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /Fans/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | build_flags = -Wno-unused-variable 16 | upload_port = /dev/cu.SLAB_USBtoUART 17 | monitor_port = /dev/cu.SLAB_USBtoUART 18 | monitor_speed = 115200 19 | 20 | lib_deps = U8g2 21 | FastLED 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LED Episode 06/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | build_flags = -Wno-unused-variable 16 | upload_port = /dev/cu.SLAB_USBtoUART 17 | monitor_port = /dev/cu.SLAB_USBtoUART 18 | monitor_speed = 115200 19 | 20 | lib_deps = U8g2 21 | FastLED 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LED Episode 07/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | build_flags = -Wno-unused-variable 16 | upload_port = /dev/cu.SLAB_USBtoUART 17 | monitor_port = /dev/cu.SLAB_USBtoUART 18 | monitor_speed = 115200 19 | 20 | lib_deps = U8g2 21 | FastLED 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LED Episode 08/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | build_flags = -Wno-unused-variable 16 | upload_port = /dev/cu.SLAB_USBtoUART 17 | monitor_port = /dev/cu.SLAB_USBtoUART 18 | monitor_speed = 115200 19 | 20 | lib_deps = U8g2 21 | FastLED 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LED Episode 09/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | build_flags = -Wno-unused-variable 16 | upload_port = /dev/cu.SLAB_USBtoUART 17 | monitor_port = /dev/cu.SLAB_USBtoUART 18 | monitor_speed = 115200 19 | 20 | lib_deps = U8g2 21 | FastLED 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LED Episode 10/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | build_flags = -Wno-unused-variable 16 | upload_port = /dev/cu.SLAB_USBtoUART 17 | monitor_port = /dev/cu.SLAB_USBtoUART 18 | monitor_speed = 115200 19 | 20 | lib_deps = U8g2 21 | FastLED 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LED Episode 11/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:heltec_wifi_kit_32] 12 | platform = espressif32 13 | board = heltec_wifi_kit_32 14 | framework = arduino 15 | build_flags = -Wno-unused-variable 16 | upload_port = /dev/cu.SLAB_USBtoUART 17 | monitor_port = /dev/cu.SLAB_USBtoUART 18 | monitor_speed = 115200 19 | 20 | lib_deps = U8g2 21 | FastLED 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Fans/include/twinkle.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #include "ledgfx.h" 20 | 21 | static const CRGB TwinkleColors [] = 22 | { 23 | CRGB::Red, 24 | CRGB::Blue, 25 | CRGB::Purple, 26 | CRGB::Green, 27 | CRGB::Yellow 28 | }; 29 | 30 | void DrawTwinkle() 31 | { 32 | static int passCount = 0; 33 | if (passCount++ == FastLED.count()/4) 34 | { 35 | passCount = 0; 36 | FastLED.clear(false); 37 | } 38 | FastLED.leds()[random(FastLED.count())] = TwinkleColors[random(0, ARRAYSIZE(TwinkleColors))]; 39 | delay(200); 40 | } -------------------------------------------------------------------------------- /LED Episode 10/include/twinkle.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #include "ledgfx.h" 20 | 21 | static const CRGB TwinkleColors [] = 22 | { 23 | CRGB::Red, 24 | CRGB::Blue, 25 | CRGB::Purple, 26 | CRGB::Green, 27 | CRGB::Yellow 28 | }; 29 | 30 | void DrawTwinkle() 31 | { 32 | static int passCount = 0; 33 | if (passCount++ == FastLED.count()/4) 34 | { 35 | passCount = 0; 36 | FastLED.clear(false); 37 | } 38 | FastLED.leds()[random(FastLED.count())] = TwinkleColors[random(0, ARRAYSIZE(TwinkleColors))]; 39 | delay(200); 40 | } -------------------------------------------------------------------------------- /LED Episode 11/include/twinkle.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #include "ledgfx.h" 20 | 21 | static const CRGB TwinkleColors [] = 22 | { 23 | CRGB::Red, 24 | CRGB::Blue, 25 | CRGB::Purple, 26 | CRGB::Green, 27 | CRGB::Yellow 28 | }; 29 | 30 | void DrawTwinkle() 31 | { 32 | static int passCount = 0; 33 | if (passCount++ == FastLED.count()/4) 34 | { 35 | passCount = 0; 36 | FastLED.clear(false); 37 | } 38 | FastLED.leds()[random(FastLED.count())] = TwinkleColors[random(0, ARRAYSIZE(TwinkleColors))]; 39 | delay(200); 40 | } -------------------------------------------------------------------------------- /Fans/include/comet.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | void DrawComet() 20 | { 21 | const byte fadeAmt = 128; 22 | const int cometSize = 5; 23 | const int deltaHue = 4; 24 | 25 | static byte hue = HUE_RED; 26 | static int iDirection = 1; 27 | static int iPos = 0; 28 | 29 | hue += deltaHue; 30 | 31 | iPos += iDirection; 32 | if (iPos == (FastLED.count() - cometSize) || iPos == 0) 33 | iDirection *= -1; 34 | 35 | for (int i = 0; i < cometSize; i++) 36 | FastLED.leds()[iPos + i].setHue(hue); 37 | 38 | // Randomly fade the LEDs 39 | for (int j = 0; j < FastLED.count(); j++) 40 | if (random(10) > 5) 41 | FastLED.leds()[j] = FastLED.leds()[j].fadeToBlackBy(fadeAmt); 42 | 43 | delay(30); 44 | } -------------------------------------------------------------------------------- /LED Episode 06/src/comet.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | extern CRGB g_LEDs[]; 20 | 21 | void DrawComet() 22 | { 23 | const byte fadeAmt = 128; 24 | const int cometSize = 5; 25 | const int deltaHue = 4; 26 | 27 | static byte hue = HUE_RED; 28 | static int iDirection = 1; 29 | static int iPos = 0; 30 | 31 | hue += deltaHue; 32 | 33 | iPos += iDirection; 34 | if (iPos == (NUM_LEDS - cometSize) || iPos == 0) 35 | iDirection *= -1; 36 | 37 | for (int i = 0; i < cometSize; i++) 38 | g_LEDs[iPos + i].setHue(hue); 39 | 40 | // Randomly fade the LEDs 41 | for (int j = 0; j < NUM_LEDS; j++) 42 | if (random(10) > 5) 43 | g_LEDs[j] = g_LEDs[j].fadeToBlackBy(fadeAmt); 44 | 45 | delay(50); 46 | } -------------------------------------------------------------------------------- /LED Episode 07/src/comet.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | extern CRGB g_LEDs[]; 20 | 21 | void DrawComet() 22 | { 23 | const byte fadeAmt = 128; 24 | const int cometSize = 5; 25 | const int deltaHue = 4; 26 | 27 | static byte hue = HUE_RED; 28 | static int iDirection = 1; 29 | static int iPos = 0; 30 | 31 | hue += deltaHue; 32 | 33 | iPos += iDirection; 34 | if (iPos == (NUM_LEDS - cometSize) || iPos == 0) 35 | iDirection *= -1; 36 | 37 | for (int i = 0; i < cometSize; i++) 38 | g_LEDs[iPos + i].setHue(hue); 39 | 40 | // Randomly fade the LEDs 41 | for (int j = 0; j < NUM_LEDS; j++) 42 | if (random(10) > 5) 43 | g_LEDs[j] = g_LEDs[j].fadeToBlackBy(fadeAmt); 44 | 45 | delay(30); 46 | } -------------------------------------------------------------------------------- /LED Episode 08/src/comet.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | extern CRGB g_LEDs[]; 20 | 21 | void DrawComet() 22 | { 23 | const byte fadeAmt = 128; 24 | const int cometSize = 5; 25 | const int deltaHue = 4; 26 | 27 | static byte hue = HUE_RED; 28 | static int iDirection = 1; 29 | static int iPos = 0; 30 | 31 | hue += deltaHue; 32 | 33 | iPos += iDirection; 34 | if (iPos == (NUM_LEDS - cometSize) || iPos == 0) 35 | iDirection *= -1; 36 | 37 | for (int i = 0; i < cometSize; i++) 38 | g_LEDs[iPos + i].setHue(hue); 39 | 40 | // Randomly fade the LEDs 41 | for (int j = 0; j < NUM_LEDS; j++) 42 | if (random(10) > 5) 43 | g_LEDs[j] = g_LEDs[j].fadeToBlackBy(fadeAmt); 44 | 45 | delay(30); 46 | } -------------------------------------------------------------------------------- /LED Episode 09/src/comet.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | extern CRGB g_LEDs[]; 20 | 21 | void DrawComet() 22 | { 23 | const byte fadeAmt = 128; 24 | const int cometSize = 5; 25 | const int deltaHue = 4; 26 | 27 | static byte hue = HUE_RED; 28 | static int iDirection = 1; 29 | static int iPos = 0; 30 | 31 | hue += deltaHue; 32 | 33 | iPos += iDirection; 34 | if (iPos == (NUM_LEDS - cometSize) || iPos == 0) 35 | iDirection *= -1; 36 | 37 | for (int i = 0; i < cometSize; i++) 38 | g_LEDs[iPos + i].setHue(hue); 39 | 40 | // Randomly fade the LEDs 41 | for (int j = 0; j < NUM_LEDS; j++) 42 | if (random(10) > 5) 43 | g_LEDs[j] = g_LEDs[j].fadeToBlackBy(fadeAmt); 44 | 45 | delay(30); 46 | } -------------------------------------------------------------------------------- /LED Episode 10/include/comet.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | void DrawComet() 20 | { 21 | const byte fadeAmt = 128; 22 | const int cometSize = 5; 23 | const int deltaHue = 4; 24 | 25 | static byte hue = HUE_RED; 26 | static int iDirection = 1; 27 | static int iPos = 0; 28 | 29 | hue += deltaHue; 30 | 31 | iPos += iDirection; 32 | if (iPos == (FastLED.count() - cometSize) || iPos == 0) 33 | iDirection *= -1; 34 | 35 | for (int i = 0; i < cometSize; i++) 36 | FastLED.leds()[iPos + i].setHue(hue); 37 | 38 | // Randomly fade the LEDs 39 | for (int j = 0; j < FastLED.count(); j++) 40 | if (random(10) > 5) 41 | FastLED.leds()[j] = FastLED.leds()[j].fadeToBlackBy(fadeAmt); 42 | 43 | delay(30); 44 | } -------------------------------------------------------------------------------- /LED Episode 11/include/comet.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | void DrawComet() 20 | { 21 | const byte fadeAmt = 128; 22 | const int cometSize = 5; 23 | const int deltaHue = 4; 24 | 25 | static byte hue = HUE_RED; 26 | static int iDirection = 1; 27 | static int iPos = 0; 28 | 29 | hue += deltaHue; 30 | 31 | iPos += iDirection; 32 | if (iPos == (FastLED.count() - cometSize) || iPos == 0) 33 | iDirection *= -1; 34 | 35 | for (int i = 0; i < cometSize; i++) 36 | FastLED.leds()[iPos + i].setHue(hue); 37 | 38 | // Randomly fade the LEDs 39 | for (int j = 0; j < FastLED.count(); j++) 40 | if (random(10) > 5) 41 | FastLED.leds()[j] = FastLED.leds()[j].fadeToBlackBy(fadeAmt); 42 | 43 | delay(30); 44 | } -------------------------------------------------------------------------------- /Fans/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 02/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 03/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 06/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 07/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 08/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 09/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 10/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 11/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /LED Episode 06/src/twinkle.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: 6 | // 7 | // Description: 8 | // 9 | // 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #define NUM_COLORS 5 20 | static const CRGB TwinkleColors [NUM_COLORS] = 21 | { 22 | CRGB::Red, 23 | CRGB::Blue, 24 | CRGB::Purple, 25 | CRGB::Green, 26 | CRGB::Yellow 27 | }; 28 | 29 | void DrawTwinkle() 30 | { 31 | FastLED.clear(false); 32 | 33 | for (int i=0; i 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #define NUM_COLORS 5 20 | static const CRGB TwinkleColors [NUM_COLORS] = 21 | { 22 | CRGB::Red, 23 | CRGB::Blue, 24 | CRGB::Purple, 25 | CRGB::Green, 26 | CRGB::Yellow 27 | }; 28 | 29 | void DrawTwinkle() 30 | { 31 | FastLED.clear(false); 32 | 33 | for (int i=0; i 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #define NUM_COLORS 5 20 | static const CRGB TwinkleColors [NUM_COLORS] = 21 | { 22 | CRGB::Red, 23 | CRGB::Blue, 24 | CRGB::Purple, 25 | CRGB::Green, 26 | CRGB::Yellow 27 | }; 28 | 29 | void DrawTwinkle() 30 | { 31 | FastLED.clear(false); 32 | 33 | for (int i=0; i 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #define NUM_COLORS 5 20 | static const CRGB TwinkleColors [NUM_COLORS] = 21 | { 22 | CRGB::Red, 23 | CRGB::Blue, 24 | CRGB::Purple, 25 | CRGB::Green, 26 | CRGB::Yellow 27 | }; 28 | 29 | void DrawTwinkle() 30 | { 31 | FastLED.clear(false); 32 | 33 | for (int i=0; i 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | 21 | void DrawMarquee() 22 | { 23 | static byte j = 0; 24 | j+=4; 25 | byte k = j; 26 | 27 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 28 | 29 | CRGB c; 30 | for (int i = 0; i < NUM_LEDS; i ++) 31 | g_LEDs[i] = c.setHue(k+=8); 32 | 33 | static int scroll = 0; 34 | scroll++; 35 | 36 | for (int i = scroll % 5; i < NUM_LEDS - 1; i += 5) 37 | { 38 | g_LEDs[i] = CRGB::Black; 39 | } 40 | delay(50); 41 | } 42 | 43 | void DrawMarqueeMirrored() 44 | { 45 | static byte j = 0; 46 | j+=4; 47 | byte k = j; 48 | 49 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 50 | 51 | CRGB c; 52 | for (int i = 0; i < (NUM_LEDS + 1) / 2; i ++) 53 | { 54 | g_LEDs[i] = c.setHue(k); 55 | g_LEDs[NUM_LEDS - 1 - i] = c.setHue(k); 56 | k+= 8; 57 | } 58 | 59 | 60 | static int scroll = 0; 61 | scroll++; 62 | 63 | for (int i = scroll % 5; i < NUM_LEDS / 2; i += 5) 64 | { 65 | g_LEDs[i] = CRGB::Black; 66 | g_LEDs[NUM_LEDS - 1 - i] = CRGB::Black; 67 | } 68 | 69 | delay(50); 70 | } 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /LED Episode 07/src/marquee.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: marque.h 6 | // 7 | // Description: 8 | // 9 | // Draws a theatre-style marquee 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | 21 | void DrawMarquee() 22 | { 23 | static byte j = 0; 24 | j+=4; 25 | byte k = j; 26 | 27 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 28 | 29 | CRGB c; 30 | for (int i = 0; i < NUM_LEDS; i ++) 31 | g_LEDs[i] = c.setHue(k+=8); 32 | 33 | static int scroll = 0; 34 | scroll++; 35 | 36 | for (int i = scroll % 5; i < NUM_LEDS - 1; i += 5) 37 | { 38 | g_LEDs[i] = CRGB::Black; 39 | } 40 | delay(50); 41 | } 42 | 43 | void DrawMarqueeMirrored() 44 | { 45 | static byte j = 0; 46 | j+=4; 47 | byte k = j; 48 | 49 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 50 | 51 | CRGB c; 52 | for (int i = 0; i < (NUM_LEDS + 1) / 2; i ++) 53 | { 54 | g_LEDs[i] = c.setHue(k); 55 | g_LEDs[NUM_LEDS - 1 - i] = c.setHue(k); 56 | k+= 8; 57 | } 58 | 59 | 60 | static int scroll = 0; 61 | scroll++; 62 | 63 | for (int i = scroll % 5; i < NUM_LEDS / 2; i += 5) 64 | { 65 | g_LEDs[i] = CRGB::Black; 66 | g_LEDs[NUM_LEDS - 1 - i] = CRGB::Black; 67 | } 68 | 69 | delay(50); 70 | } 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /LED Episode 09/src/marquee.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: marque.h 6 | // 7 | // Description: 8 | // 9 | // Draws a theatre-style marquee 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | 21 | void DrawMarquee() 22 | { 23 | static byte j = 0; 24 | j+=4; 25 | byte k = j; 26 | 27 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 28 | 29 | CRGB c; 30 | for (int i = 0; i < NUM_LEDS; i ++) 31 | g_LEDs[i] = c.setHue(k+=8); 32 | 33 | static int scroll = 0; 34 | scroll++; 35 | 36 | for (int i = scroll % 5; i < NUM_LEDS - 1; i += 5) 37 | { 38 | g_LEDs[i] = CRGB::Black; 39 | } 40 | delay(50); 41 | } 42 | 43 | void DrawMarqueeMirrored() 44 | { 45 | static byte j = 0; 46 | j+=4; 47 | byte k = j; 48 | 49 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 50 | 51 | CRGB c; 52 | for (int i = 0; i < (NUM_LEDS + 1) / 2; i ++) 53 | { 54 | g_LEDs[i] = c.setHue(k); 55 | g_LEDs[NUM_LEDS - 1 - i] = c.setHue(k); 56 | k+= 8; 57 | } 58 | 59 | 60 | static int scroll = 0; 61 | scroll++; 62 | 63 | for (int i = scroll % 5; i < NUM_LEDS / 2; i += 5) 64 | { 65 | g_LEDs[i] = CRGB::Black; 66 | g_LEDs[NUM_LEDS - 1 - i] = CRGB::Black; 67 | } 68 | 69 | delay(50); 70 | } 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Fans/include/marquee.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: marque.h 6 | // 7 | // Description: 8 | // 9 | // Draws a theatre-style marquee 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | 21 | void DrawMarquee() 22 | { 23 | static byte j = 0; 24 | j+=4; 25 | byte k = j; 26 | 27 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 28 | 29 | CRGB c; 30 | for (int i = 0; i < FastLED.count(); i ++) 31 | FastLED.leds()[i] = c.setHue(k+=8); 32 | 33 | static int scroll = 0; 34 | scroll++; 35 | 36 | for (int i = scroll % 5; i < FastLED.count() - 1; i += 5) 37 | { 38 | FastLED.leds()[i] = CRGB::Black; 39 | } 40 | delay(50); 41 | } 42 | 43 | void DrawMarqueeMirrored() 44 | { 45 | static byte j = 0; 46 | j+=4; 47 | byte k = j; 48 | 49 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 50 | 51 | CRGB c; 52 | for (int i = 0; i < (FastLED.count() + 1) / 2; i ++) 53 | { 54 | FastLED.leds()[i] = c.setHue(k); 55 | FastLED.leds()[FastLED.count() - 1 - i] = c.setHue(k); 56 | k+= 8; 57 | } 58 | 59 | 60 | static int scroll = 0; 61 | scroll++; 62 | 63 | for (int i = scroll % 5; i < FastLED.count() / 2; i += 5) 64 | { 65 | FastLED.leds()[i] = CRGB::Black; 66 | FastLED.leds()[FastLED.count() - 1 - i] = CRGB::Black; 67 | } 68 | 69 | delay(50); 70 | } 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /LED Episode 10/include/marquee.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: marque.h 6 | // 7 | // Description: 8 | // 9 | // Draws a theatre-style marquee 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | 21 | void DrawMarquee() 22 | { 23 | static byte j = 0; 24 | j+=4; 25 | byte k = j; 26 | 27 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 28 | 29 | CRGB c; 30 | for (int i = 0; i < FastLED.count(); i ++) 31 | FastLED.leds()[i] = c.setHue(k+=8); 32 | 33 | static int scroll = 0; 34 | scroll++; 35 | 36 | for (int i = scroll % 5; i < FastLED.count() - 1; i += 5) 37 | { 38 | FastLED.leds()[i] = CRGB::Black; 39 | } 40 | delay(50); 41 | } 42 | 43 | void DrawMarqueeMirrored() 44 | { 45 | static byte j = 0; 46 | j+=4; 47 | byte k = j; 48 | 49 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 50 | 51 | CRGB c; 52 | for (int i = 0; i < (FastLED.count() + 1) / 2; i ++) 53 | { 54 | FastLED.leds()[i] = c.setHue(k); 55 | FastLED.leds()[FastLED.count() - 1 - i] = c.setHue(k); 56 | k+= 8; 57 | } 58 | 59 | 60 | static int scroll = 0; 61 | scroll++; 62 | 63 | for (int i = scroll % 5; i < FastLED.count() / 2; i += 5) 64 | { 65 | FastLED.leds()[i] = CRGB::Black; 66 | FastLED.leds()[FastLED.count() - 1 - i] = CRGB::Black; 67 | } 68 | 69 | delay(50); 70 | } 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /LED Episode 11/include/marquee.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: marque.h 6 | // 7 | // Description: 8 | // 9 | // Draws a theatre-style marquee 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | 21 | void DrawMarquee() 22 | { 23 | static byte j = 0; 24 | j+=4; 25 | byte k = j; 26 | 27 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 28 | 29 | CRGB c; 30 | for (int i = 0; i < FastLED.count(); i ++) 31 | FastLED.leds()[i] = c.setHue(k+=8); 32 | 33 | static int scroll = 0; 34 | scroll++; 35 | 36 | for (int i = scroll % 5; i < FastLED.count() - 1; i += 5) 37 | { 38 | FastLED.leds()[i] = CRGB::Black; 39 | } 40 | delay(50); 41 | } 42 | 43 | void DrawMarqueeMirrored() 44 | { 45 | static byte j = 0; 46 | j+=4; 47 | byte k = j; 48 | 49 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 50 | 51 | CRGB c; 52 | for (int i = 0; i < (FastLED.count() + 1) / 2; i ++) 53 | { 54 | FastLED.leds()[i] = c.setHue(k); 55 | FastLED.leds()[FastLED.count() - 1 - i] = c.setHue(k); 56 | k+= 8; 57 | } 58 | 59 | 60 | static int scroll = 0; 61 | scroll++; 62 | 63 | for (int i = scroll % 5; i < FastLED.count() / 2; i += 5) 64 | { 65 | FastLED.leds()[i] = CRGB::Black; 66 | FastLED.leds()[FastLED.count() - 1 - i] = CRGB::Black; 67 | } 68 | 69 | delay(50); 70 | } 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /LED Episode 02/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /LED Episode 03/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /LED Episode 06/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /LED Episode 03/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | U8G2_SSD1306_128X64_NONAME_F_SW_I2C g_TFT(U8G2_R2, 15, 4, 16); 5 | 6 | void setup() 7 | { 8 | pinMode(LED_BUILTIN, OUTPUT); // Set the LED pin to output 9 | g_TFT.begin(); // One-time startup 10 | g_TFT.clear(); // Clear the screen 11 | g_TFT.setFont(u8g2_font_profont15_tf); // Choose a suitable font 12 | g_TFT.setCursor(2, 12); // Cursor is at bottom of letter, so we need to move down 13 | //g_TFT.println("Hello World!"); // Print something 14 | 15 | // Draw a border around the screen 16 | 17 | g_TFT.drawFrame(0, 0, 128, 64); 18 | 19 | // Draw a moire pattern like its 1984 20 | 21 | for (int x=0; x<128; x+= 4) 22 | g_TFT.drawLine(x, 0, 128-x, 64); 23 | 24 | // Draw some text on the left hand side 25 | 26 | g_TFT.setCursor(5, 32); 27 | g_TFT.print("Hello"); 28 | g_TFT.setCursor(5, 42); 29 | g_TFT.print("World"); 30 | 31 | // Draw a reticle on the right hand side 32 | 33 | const int reticleY = g_TFT.getHeight() / 2; // Vertical center 34 | const int reticleR = g_TFT.getHeight() / 4 - 2; // Slightly less than 1/4 screen height 35 | const int reticleX = g_TFT.getWidth() - reticleR - 8; // Right-justified with a small margin 36 | 37 | for (int r = reticleR; r > 0; r -= 3) 38 | g_TFT.drawCircle(reticleX, reticleY, r); 39 | g_TFT.drawHLine(reticleX - reticleR - 5, reticleY, 2 * reticleR + 10); 40 | g_TFT.drawVLine(reticleX, reticleY - reticleR - 5, 2 * reticleR + 10); 41 | 42 | g_TFT.sendBuffer(); // Ship-It! 43 | 44 | } 45 | 46 | void loop() 47 | { 48 | digitalWrite(LED_BUILTIN, 0); 49 | delay(100); 50 | digitalWrite(LED_BUILTIN, 1); 51 | delay(100); 52 | } -------------------------------------------------------------------------------- /LED Episode 08/src/marquee.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: marque.h 6 | // 7 | // Description: 8 | // 9 | // Draws a theatre-style marquee 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | void DrawMarqueeComparison() 21 | { 22 | static float scroll = 0.0f; 23 | scroll += 0.1f; 24 | if (scroll > 5.0f) 25 | scroll -= 5.0f; 26 | 27 | for (float i = scroll; i < NUM_LEDS/2 - 1; i += 5) 28 | { 29 | DrawPixels(i, 3, CRGB::Green); 30 | DrawPixels(NUM_LEDS-1-(int)i, 3, CRGB::Red); 31 | } 32 | } 33 | 34 | void DrawMarquee() 35 | { 36 | static byte j = 0; 37 | j+=4; 38 | byte k = j; 39 | 40 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 41 | 42 | CRGB c; 43 | for (int i = 0; i < NUM_LEDS; i ++) 44 | g_LEDs[i] = c.setHue(k+=8); 45 | 46 | static int scroll = 0; 47 | scroll++; 48 | 49 | for (int i = scroll % 5; i < NUM_LEDS - 1; i += 5) 50 | { 51 | g_LEDs[i] = CRGB::Black; 52 | } 53 | delay(50); 54 | } 55 | 56 | void DrawMarqueeMirrored() 57 | { 58 | static byte j = 0; 59 | j+=4; 60 | byte k = j; 61 | 62 | // Roughly equivalent to fill_rainbow(g_LEDs, NUM_LEDS, j, 8); 63 | 64 | CRGB c; 65 | for (int i = 0; i < (NUM_LEDS + 1) / 2; i ++) 66 | { 67 | g_LEDs[i] = c.setHue(k); 68 | g_LEDs[NUM_LEDS - 1 - i] = c.setHue(k); 69 | k+= 8; 70 | } 71 | 72 | 73 | static int scroll = 0; 74 | scroll++; 75 | 76 | for (int i = scroll % 5; i < NUM_LEDS / 2; i += 5) 77 | { 78 | g_LEDs[i] = CRGB::Black; 79 | g_LEDs[NUM_LEDS - 1 - i] = CRGB::Black; 80 | } 81 | 82 | delay(50); 83 | } 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /LED Episode 10/include/ledgfx.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: ledgfx.h 6 | // 7 | // Description: 8 | // 9 | // LED Drawing Routines for Dave's Garage Tutorial series 10 | // 11 | // History: OCt-18-2020 davepl Created from main.cpp code 12 | //--------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | #include // For time-of-day 21 | 22 | // Utility Macros 23 | 24 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 25 | #define TIMES_PER_SECOND(x) EVERY_N_MILLISECONDS(1000/x) 26 | 27 | //inline double RandomDouble() 28 | //{ 29 | // return random(UINT32_MAX) / (double) UINT32_MAX; 30 | //} 31 | 32 | inline float RandomFloat() 33 | { 34 | float r = random(1000000L) / 1000000.0f; 35 | return r; 36 | } 37 | 38 | inline double UnixTime() 39 | { 40 | timeval tv = { 0 }; 41 | gettimeofday(&tv, nullptr); 42 | return (double)(tv.tv_usec / 1000000.0 + (double) tv.tv_sec); 43 | } 44 | 45 | // FractionalColor 46 | // 47 | // Returns a fraction of a color; abstracts the fadeToBlack out to this function in case we 48 | // want to improve the color math or do color correction all in one location at a later date. 49 | 50 | CRGB ColorFraction(CRGB colorIn, float fraction) 51 | { 52 | fraction = min(1.0f, fraction); 53 | return CRGB(colorIn).fadeToBlackBy(255 * (1.0f - fraction)); 54 | } 55 | 56 | void DrawPixels(float fPos, float count, CRGB color) 57 | { 58 | // Calculate how much the first pixel will hold 59 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); 60 | float amtFirstPixel = min(availFirstPixel, count); 61 | float remaining = min(count, FastLED.size()-fPos); 62 | int iPos = fPos; 63 | 64 | // Blend (add) in the color of the first partial pixel 65 | 66 | if (remaining > 0.0f) 67 | { 68 | FastLED.leds()[iPos++] += ColorFraction(color, amtFirstPixel); 69 | remaining -= amtFirstPixel; 70 | } 71 | 72 | // Now draw any full pixels in the middle 73 | 74 | while (remaining > 1.0f) 75 | { 76 | FastLED.leds()[iPos++] += color; 77 | remaining--; 78 | } 79 | 80 | // Draw tail pixel, up to a single full pixel 81 | 82 | if (remaining > 0.0f) 83 | { 84 | FastLED.leds()[iPos] += ColorFraction(color, remaining); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /LED Episode 02/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define RED_PIN 16 4 | #define GREEN_PIN 17 5 | #define BLUE_PIN 18 6 | 7 | // Courtesy http://www.instructables.com/id/How-to-Use-an-RGB-LED/?ALLSTEPS 8 | // function to convert a color to its Red, Green, and Blue components. 9 | 10 | uint32_t R, G, B; // the Red Green and Blue color components 11 | 12 | void hueToRGB(uint8_t hue, uint8_t brightness) 13 | { 14 | uint16_t scaledHue = (hue * 6); 15 | uint8_t segment = scaledHue / 256; // segment 0 to 5 around the 16 | // color wheel 17 | uint16_t segmentOffset = 18 | scaledHue - (segment * 256); // position within the segment 19 | 20 | uint8_t complement = 0; 21 | uint16_t prev = (brightness * ( 255 - segmentOffset)) / 256; 22 | uint16_t next = (brightness * segmentOffset) / 256; 23 | 24 | switch(segment ) { 25 | case 0: // red 26 | R = brightness; 27 | G = next; 28 | B = complement; 29 | break; 30 | case 1: // yellow 31 | R = prev; 32 | G = brightness; 33 | B = complement; 34 | break; 35 | case 2: // green 36 | R = complement; 37 | G = brightness; 38 | B = next; 39 | break; 40 | case 3: // cyan 41 | R = complement; 42 | G = prev; 43 | B = brightness; 44 | break; 45 | case 4: // blue 46 | R = next; 47 | G = complement; 48 | B = brightness; 49 | break; 50 | case 5: // magenta 51 | default: 52 | R = brightness; 53 | G = complement; 54 | B = prev; 55 | break; 56 | } 57 | } 58 | 59 | void setup() 60 | { 61 | pinMode(RED_PIN, OUTPUT); 62 | pinMode(GREEN_PIN, OUTPUT); 63 | pinMode(BLUE_PIN, OUTPUT); 64 | 65 | digitalWrite(GREEN_PIN, HIGH); 66 | digitalWrite(BLUE_PIN, HIGH); 67 | 68 | ledcAttachPin(RED_PIN, 1); // Assign PWM generator 1 to RED 69 | ledcAttachPin(GREEN_PIN, 2); // Assign PWM generator 2 to GREEN 70 | ledcAttachPin(BLUE_PIN, 3); // Assign PWM generator 3 to BLUE 71 | 72 | ledcSetup(1, 12000, 8); // Set it to 12kHZ and 8-bit resolution 73 | ledcSetup(2, 12000, 8); // Set it to 12kHZ and 8-bit resolution 74 | ledcSetup(3, 12000, 8); // Set it to 12kHZ and 8-bit resolution 75 | } 76 | 77 | void loop() 78 | { 79 | for (int c = 0; c < 256; c++) 80 | { 81 | hueToRGB(c, 255); // Convert color to max brightness 82 | 83 | ledcWrite(1, R); 84 | ledcWrite(2, G); 85 | ledcWrite(3, B); 86 | 87 | delay(100); 88 | } 89 | } -------------------------------------------------------------------------------- /Fans/include/fire.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: fire.h 6 | // 7 | // Description: A realistic flame simulation for LED strips 8 | // 9 | // History: Oct-23-2020 davepl Created 10 | // 11 | //--------------------------------------------------------------------------- 12 | 13 | #include 14 | #define FASTLED_INTERNAL 15 | #include 16 | 17 | #include "ledgfx.h" 18 | 19 | class FireEffect 20 | { 21 | protected: 22 | int Size; // How many pixels the flame is total 23 | int Cooling; // Rate at which the pixels cool off 24 | int Sparks; // How many sparks will be attempted each frame 25 | int SparkHeight; // If created, max height for a spark 26 | int Sparking; // Probability of a spark each attempt 27 | bool bReversed; // If reversed we draw from 0 outwards 28 | bool bMirrored; // If mirrored we split and duplicate the drawing 29 | 30 | byte * heat; 31 | 32 | // When diffusing the fire upwards, these control how much to blend in from the cells below (ie: downward neighbors) 33 | // You can tune these coefficients to control how quickly and smoothly the fire spreads 34 | 35 | static const byte BlendSelf = 2; 36 | static const byte BlendNeighbor1 = 3; 37 | static const byte BlendNeighbor2 = 2; 38 | static const byte BlendNeighbor3 = 1; 39 | static const byte BlendTotal = (BlendSelf + BlendNeighbor1 + BlendNeighbor2 + BlendNeighbor3); 40 | 41 | public: 42 | 43 | FireEffect(int size, int cooling = 20, int sparking = 100, int sparks = 3, int sparkHeight = 4, bool breversed = true, bool bmirrored = true) 44 | : Size(size), 45 | Cooling(cooling), 46 | Sparks(sparks), 47 | SparkHeight(sparkHeight), 48 | Sparking(sparking), 49 | bReversed(breversed), 50 | bMirrored(bmirrored) 51 | { 52 | if (bMirrored) 53 | Size = Size / 2; 54 | 55 | heat = new byte[size] { 0 }; 56 | } 57 | 58 | virtual ~FireEffect() 59 | { 60 | delete [] heat; 61 | } 62 | 63 | virtual void DrawFire(PixelOrder order = Sequential) 64 | { 65 | // First cool each cell by a litle bit 66 | for (int i = 0; i < Size; i++) 67 | heat[i] = max(0L, heat[i] - random(0, ((Cooling * 10) / Size) + 2)); 68 | 69 | // Next drift heat up and diffuse it a little bit 70 | for (int i = 0; i < Size; i++) 71 | heat[i] = (heat[i] * BlendSelf + 72 | heat[(i + 1) % Size] * BlendNeighbor1 + 73 | heat[(i + 2) % Size] * BlendNeighbor2 + 74 | heat[(i + 3) % Size] * BlendNeighbor3) 75 | / BlendTotal; 76 | 77 | // Randomly ignite new sparks down in the flame kernel 78 | 79 | for (int i = 0 ; i < Sparks; i++) 80 | { 81 | if (random(255) < Sparking) 82 | { 83 | int y = Size - 1 - random(SparkHeight); 84 | heat[y] = heat[y] + random(160, 255); // Can roll over which actually looks good! 85 | } 86 | } 87 | 88 | // Finally, convert heat to a color 89 | 90 | for (int i = 0; i < Size; i++) 91 | { 92 | CRGB color = HeatColor(heat[i]); 93 | int j = bReversed ? (Size - 1 - i) : i; 94 | DrawFanPixels(j, 1, color, order); 95 | if (bMirrored) 96 | DrawFanPixels(!bReversed ? (2 * Size - 1 - i) : Size + i, 1, color, order); 97 | } 98 | } 99 | }; -------------------------------------------------------------------------------- /LED Episode 11/include/fire.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: fire.h 6 | // 7 | // Description: A realistic flame simulation for LED strips 8 | // 9 | // History: Oct-23-2020 davepl Created 10 | // 11 | //--------------------------------------------------------------------------- 12 | 13 | #include 14 | #define FASTLED_INTERNAL 15 | #include 16 | 17 | #include "ledgfx.h" 18 | 19 | class FireEffect 20 | { 21 | protected: 22 | int Size; // How many pixels the flame is total 23 | int Cooling; // Rate at which the pixels cool off 24 | int Sparks; // How many sparks will be attempted each frame 25 | int SparkHeight; // If created, max height for a spark 26 | int Sparking; // Probability of a spark each attempt 27 | bool bReversed; // If reversed we draw from 0 outwards 28 | bool bMirrored; // If mirrored we split and duplicate the drawing 29 | 30 | byte * heat; 31 | 32 | // When diffusing the fire upwards, these control how much to blend in from the cells below (ie: downward neighbors) 33 | // You can tune these coefficients to control how quickly and smoothly the fire spreads 34 | 35 | static const byte BlendSelf = 2; 36 | static const byte BlendNeighbor1 = 3; 37 | static const byte BlendNeighbor2 = 2; 38 | static const byte BlendNeighbor3 = 1; 39 | static const byte BlendTotal = (BlendSelf + BlendNeighbor1 + BlendNeighbor2 + BlendNeighbor3); 40 | 41 | public: 42 | 43 | FireEffect(int size, int cooling = 20, int sparking = 100, int sparks = 3, int sparkHeight = 4, bool breversed = true, bool bmirrored = true) 44 | : Size(size), 45 | Cooling(cooling), 46 | Sparks(sparks), 47 | SparkHeight(sparkHeight), 48 | Sparking(sparking), 49 | bReversed(breversed), 50 | bMirrored(bmirrored) 51 | { 52 | if (bMirrored) 53 | Size = Size / 2; 54 | 55 | heat = new byte[size] { 0 }; 56 | } 57 | 58 | virtual ~FireEffect() 59 | { 60 | delete [] heat; 61 | } 62 | 63 | virtual void DrawFire(PixelOrder order = Sequential) 64 | { 65 | // First cool each cell by a litle bit 66 | for (int i = 0; i < Size; i++) 67 | heat[i] = max(0L, heat[i] - random(0, ((Cooling * 10) / Size) + 2)); 68 | 69 | // Next drift heat up and diffuse it a little bit 70 | for (int i = 0; i < Size; i++) 71 | heat[i] = (heat[i] * BlendSelf + 72 | heat[(i + 1) % Size] * BlendNeighbor1 + 73 | heat[(i + 2) % Size] * BlendNeighbor2 + 74 | heat[(i + 3) % Size] * BlendNeighbor3) 75 | / BlendTotal; 76 | 77 | // Randomly ignite new sparks down in the flame kernel 78 | 79 | for (int i = 0 ; i < Sparks; i++) 80 | { 81 | if (random(255) < Sparking) 82 | { 83 | int y = Size - 1 - random(SparkHeight); 84 | heat[y] = heat[y] + random(160, 255); // Can roll over which actually looks good! 85 | } 86 | } 87 | 88 | // Finally, convert heat to a color 89 | 90 | for (int i = 0; i < Size; i++) 91 | { 92 | CRGB color = HeatColor(heat[i]); 93 | int j = bReversed ? (Size - 1 - i) : i; 94 | DrawFanPixels(j, 1, color, order); 95 | if (bMirrored) 96 | DrawFanPixels(!bReversed ? (2 * Size - 1 - i) : Size + i, 1, color, order); 97 | } 98 | } 99 | }; -------------------------------------------------------------------------------- /LED Episode 10/src/main.cpp: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: LED Episode 08 6 | // 7 | // Description: 8 | // 9 | // Draws sample effects on a an addressable strip using FastLED 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // Oct-05-2020 davepl Revised for Episode 07 13 | // Oct-11-2020 davepl Revised for Episode 08 14 | // Oct-16-2020 davepl Revised for Episode 09 15 | //--------------------------------------------------------------------------- 16 | 17 | #include // Arduino Framework 18 | #include // For text on the little on-chip OLED 19 | #define FASTLED_INTERNAL // Suppress build banner 20 | #include 21 | 22 | #define OLED_CLOCK 15 // Pins for the OLED display 23 | #define OLED_DATA 4 24 | #define OLED_RESET 16 25 | 26 | #define NUM_LEDS 40 // FastLED definitions 27 | #define LED_PIN 5 28 | 29 | CRGB g_LEDs[NUM_LEDS] = {0}; // Frame buffer for FastLED 30 | 31 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C g_OLED(U8G2_R2, OLED_RESET, OLED_CLOCK, OLED_DATA); 32 | int g_lineHeight = 0; 33 | int g_Brightness = 255; // 0-255 LED brightness scale 34 | int g_PowerLimit = 3000; // 900mW Power Limit 35 | 36 | #include "ledgfx.h" 37 | #include "comet.h" 38 | #include "marquee.h" 39 | #include "twinkle.h" 40 | #include "fire.h" 41 | 42 | void setup() 43 | { 44 | pinMode(LED_BUILTIN, OUTPUT); 45 | pinMode(LED_PIN, OUTPUT); 46 | 47 | Serial.begin(115200); 48 | while (!Serial) { } 49 | Serial.println("ESP32 Startup"); 50 | 51 | g_OLED.begin(); 52 | g_OLED.clear(); 53 | g_OLED.setFont(u8g2_font_profont15_tf); 54 | g_lineHeight = g_OLED.getFontAscent() - g_OLED.getFontDescent(); // Descent is a negative number so we add it to the total 55 | 56 | FastLED.addLeds(g_LEDs, NUM_LEDS); // Add our LED strip to the FastLED library 57 | FastLED.setBrightness(g_Brightness); 58 | set_max_power_indicator_LED(LED_BUILTIN); // Light the builtin LED if we power throttle 59 | FastLED.setMaxPowerInMilliWatts(g_PowerLimit); // Set the power limit, above which brightness will be throttled 60 | } 61 | 62 | void DrawMarqueeComparison() 63 | { 64 | static float scroll = 0.0f; 65 | scroll += 0.1f; 66 | if (scroll > 5.0) 67 | scroll -= 5.0; 68 | 69 | for (float i = scroll; i < NUM_LEDS/2 -1; i+= 5) 70 | { 71 | DrawPixels(i, 3, CRGB::Green); 72 | DrawPixels(NUM_LEDS-1-(int)i, 3, CRGB::Red); 73 | } 74 | } 75 | 76 | void loop() 77 | { 78 | bool bLED = 0; 79 | 80 | //ClassicFireEffect fire(NUM_LEDS, 30, 100, 3, 2, false, true); // Outwards from Middle 81 | //ClassicFireEffect fire(NUM_LEDS, 30, 100, 3, 2, true, true); // Inwards toward Middle 82 | //ClassicFireEffect fire(NUM_LEDS, 20, 100, 3, 4, true, false); // Outwards from Zero 83 | //ClassicFireEffect fire(NUM_LEDS, 20, 100, 3, 4, false, false); // Inwards from End 84 | //ClassicFireEffect fire(NUM_LEDS, 50, 300, 30, 12, true, false); // More Intense, Extra Sparking 85 | 86 | ClassicFireEffect fire(NUM_LEDS, 20, 100, 3, NUM_LEDS, true, false); // Fan with correct rotation 87 | 88 | while (true) 89 | { 90 | FastLED.clear(); 91 | fire.DrawFire(); 92 | FastLED.show(g_Brightness); // Show and delay 93 | 94 | EVERY_N_MILLISECONDS(250) 95 | { 96 | g_OLED.clearBuffer(); 97 | g_OLED.setCursor(0, g_lineHeight); 98 | g_OLED.printf("FPS : %u", FastLED.getFPS()); 99 | g_OLED.setCursor(0, g_lineHeight * 2); 100 | g_OLED.printf("Power: %u mW", calculate_unscaled_power_mW(g_LEDs, 4)); 101 | g_OLED.setCursor(0, g_lineHeight * 3); 102 | g_OLED.printf("Brite: %d", calculate_max_brightness_for_power_mW(g_Brightness, g_PowerLimit)); 103 | g_OLED.sendBuffer(); 104 | } 105 | delay(33); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Fans/include/bounce.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: bounce.h 6 | // 7 | // Description: 8 | // 9 | // Bouncing Ball effect on an LED strip 10 | // 11 | // History: Oct-04-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | using namespace std; 20 | #include 21 | 22 | #include "ledgfx.h" 23 | 24 | static const CRGB ballColors [] = 25 | { 26 | CRGB::Green, 27 | CRGB::Red, 28 | CRGB::Blue, 29 | CRGB::Orange, 30 | CRGB::Indigo 31 | }; 32 | 33 | class BouncingBallEffect 34 | { 35 | private: 36 | 37 | double InitialBallSpeed(double height) const 38 | { 39 | return sqrt(-2 * Gravity * height); // Because MATH! 40 | } 41 | 42 | size_t _cLength; 43 | size_t _cBalls; 44 | byte _fadeRate; 45 | bool _bMirrored; 46 | 47 | const double Gravity = -9.81; // Because PHYSICS! 48 | const double StartHeight = 1; // Drop balls from max height initially 49 | const double ImpactVelocity = InitialBallSpeed(StartHeight); 50 | const double SpeedKnob = 4.0; // Higher values will slow the effect 51 | 52 | vector ClockTimeAtLastBounce, Height, BallSpeed, Dampening; 53 | vector Colors; 54 | 55 | public: 56 | 57 | // BouncingBallEffect 58 | // 59 | // Caller specs strip length, number of balls, persistence level (255 is least), and whether the 60 | // balls should be drawn mirrored from each side. 61 | 62 | BouncingBallEffect(size_t cLength, size_t ballCount = 3, byte fade = 0, bool bMirrored = false) 63 | : _cLength(cLength - 1), 64 | _cBalls(ballCount), 65 | _fadeRate(fade), 66 | _bMirrored(bMirrored), 67 | ClockTimeAtLastBounce(ballCount), 68 | Height(ballCount), 69 | BallSpeed(ballCount), 70 | Dampening(ballCount), 71 | Colors(ballCount) 72 | { 73 | for (size_t i = 0; i < ballCount; i++) 74 | { 75 | Height[i] = StartHeight; // Current Ball Height 76 | ClockTimeAtLastBounce[i] = UnixTime(); // When ball last hit ground state 77 | Dampening[i] = 0.90 - i / pow(_cBalls, 2); // Bounciness of this ball 78 | BallSpeed[i] = InitialBallSpeed(Height[i]); // Don't dampen initial launch 79 | Colors[i] = ballColors[i % ARRAYSIZE(ballColors) ]; 80 | } 81 | } 82 | 83 | // Draw 84 | // 85 | // Draw each of the balls. When any ball settles with too little energy, it it "kicked" to restart it 86 | 87 | virtual void Draw() 88 | { 89 | if (_fadeRate != 0) 90 | { 91 | for (size_t i = 0; i < _cLength; i++) 92 | FastLED.leds()[i].fadeToBlackBy(_fadeRate); 93 | } 94 | else 95 | FastLED.clear(); 96 | 97 | // Draw each of the balls 98 | 99 | for (size_t i = 0; i < _cBalls; i++) 100 | { 101 | double TimeSinceLastBounce = (UnixTime() - ClockTimeAtLastBounce[i]) / SpeedKnob; 102 | 103 | // Use standard constant acceleration function - https://en.wikipedia.org/wiki/Acceleration 104 | Height[i] = 0.5 * Gravity * pow(TimeSinceLastBounce, 2.0) + BallSpeed[i] * TimeSinceLastBounce; 105 | 106 | // Ball hits ground - bounce! 107 | if (Height[i] < 0) 108 | { 109 | Height[i] = 0; 110 | BallSpeed[i] = Dampening[i] * BallSpeed[i]; 111 | ClockTimeAtLastBounce[i] = Time(); 112 | 113 | if (BallSpeed[i] < 0.01) 114 | BallSpeed[i] = InitialBallSpeed(StartHeight) * Dampening[i]; 115 | } 116 | 117 | size_t position = (size_t)(Height[i] * (_cLength - 1) / StartHeight); 118 | 119 | FastLED.leds()[position] += Colors[i]; 120 | FastLED.leds()[position+1] += Colors[i]; 121 | 122 | if (_bMirrored) 123 | { 124 | FastLED.leds()[_cLength - 1 - position] += Colors[i]; 125 | FastLED.leds()[_cLength - position] += Colors[i]; 126 | } 127 | } 128 | delay(20); 129 | } 130 | }; -------------------------------------------------------------------------------- /LED Episode 10/include/bounce.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: bounce.h 6 | // 7 | // Description: 8 | // 9 | // Bouncing Ball effect on an LED strip 10 | // 11 | // History: Oct-04-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | using namespace std; 20 | #include 21 | 22 | #include "ledgfx.h" 23 | 24 | static const CRGB ballColors [] = 25 | { 26 | CRGB::Green, 27 | CRGB::Red, 28 | CRGB::Blue, 29 | CRGB::Orange, 30 | CRGB::Indigo 31 | }; 32 | 33 | class BouncingBallEffect 34 | { 35 | private: 36 | 37 | double InitialBallSpeed(double height) const 38 | { 39 | return sqrt(-2 * Gravity * height); // Because MATH! 40 | } 41 | 42 | size_t _cLength; 43 | size_t _cBalls; 44 | byte _fadeRate; 45 | bool _bMirrored; 46 | 47 | const double Gravity = -9.81; // Because PHYSICS! 48 | const double StartHeight = 1; // Drop balls from max height initially 49 | const double ImpactVelocity = InitialBallSpeed(StartHeight); 50 | const double SpeedKnob = 4.0; // Higher values will slow the effect 51 | 52 | vector ClockTimeAtLastBounce, Height, BallSpeed, Dampening; 53 | vector Colors; 54 | 55 | public: 56 | 57 | // BouncingBallEffect 58 | // 59 | // Caller specs strip length, number of balls, persistence level (255 is least), and whether the 60 | // balls should be drawn mirrored from each side. 61 | 62 | BouncingBallEffect(size_t cLength, size_t ballCount = 3, byte fade = 0, bool bMirrored = false) 63 | : _cLength(cLength - 1), 64 | _cBalls(ballCount), 65 | _fadeRate(fade), 66 | _bMirrored(bMirrored), 67 | ClockTimeAtLastBounce(ballCount), 68 | Height(ballCount), 69 | BallSpeed(ballCount), 70 | Dampening(ballCount), 71 | Colors(ballCount) 72 | { 73 | for (size_t i = 0; i < ballCount; i++) 74 | { 75 | Height[i] = StartHeight; // Current Ball Height 76 | ClockTimeAtLastBounce[i] = UnixTime(); // When ball last hit ground state 77 | Dampening[i] = 0.90 - i / pow(_cBalls, 2); // Bounciness of this ball 78 | BallSpeed[i] = InitialBallSpeed(Height[i]); // Don't dampen initial launch 79 | Colors[i] = ballColors[i % ARRAYSIZE(ballColors) ]; 80 | } 81 | } 82 | 83 | // Draw 84 | // 85 | // Draw each of the balls. When any ball settles with too little energy, it it "kicked" to restart it 86 | 87 | virtual void Draw() 88 | { 89 | if (_fadeRate != 0) 90 | { 91 | for (size_t i = 0; i < _cLength; i++) 92 | FastLED.leds()[i].fadeToBlackBy(_fadeRate); 93 | } 94 | else 95 | FastLED.clear(); 96 | 97 | // Draw each of the balls 98 | 99 | for (size_t i = 0; i < _cBalls; i++) 100 | { 101 | double TimeSinceLastBounce = (UnixTime() - ClockTimeAtLastBounce[i]) / SpeedKnob; 102 | 103 | // Use standard constant acceleration function - https://en.wikipedia.org/wiki/Acceleration 104 | Height[i] = 0.5 * Gravity * pow(TimeSinceLastBounce, 2.0) + BallSpeed[i] * TimeSinceLastBounce; 105 | 106 | // Ball hits ground - bounce! 107 | if (Height[i] < 0) 108 | { 109 | Height[i] = 0; 110 | BallSpeed[i] = Dampening[i] * BallSpeed[i]; 111 | ClockTimeAtLastBounce[i] = Time(); 112 | 113 | if (BallSpeed[i] < 0.01) 114 | BallSpeed[i] = InitialBallSpeed(StartHeight) * Dampening[i]; 115 | } 116 | 117 | size_t position = (size_t)(Height[i] * (_cLength - 1) / StartHeight); 118 | 119 | FastLED.leds()[position] += Colors[i]; 120 | FastLED.leds()[position+1] += Colors[i]; 121 | 122 | if (_bMirrored) 123 | { 124 | FastLED.leds()[_cLength - 1 - position] += Colors[i]; 125 | FastLED.leds()[_cLength - position] += Colors[i]; 126 | } 127 | } 128 | delay(20); 129 | } 130 | }; -------------------------------------------------------------------------------- /LED Episode 11/include/bounce.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: bounce.h 6 | // 7 | // Description: 8 | // 9 | // Bouncing Ball effect on an LED strip 10 | // 11 | // History: Oct-04-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | using namespace std; 20 | #include 21 | 22 | #include "ledgfx.h" 23 | 24 | static const CRGB ballColors [] = 25 | { 26 | CRGB::Green, 27 | CRGB::Red, 28 | CRGB::Blue, 29 | CRGB::Orange, 30 | CRGB::Indigo 31 | }; 32 | 33 | class BouncingBallEffect 34 | { 35 | private: 36 | 37 | double InitialBallSpeed(double height) const 38 | { 39 | return sqrt(-2 * Gravity * height); // Because MATH! 40 | } 41 | 42 | size_t _cLength; 43 | size_t _cBalls; 44 | byte _fadeRate; 45 | bool _bMirrored; 46 | 47 | const double Gravity = -9.81; // Because PHYSICS! 48 | const double StartHeight = 1; // Drop balls from max height initially 49 | const double ImpactVelocity = InitialBallSpeed(StartHeight); 50 | const double SpeedKnob = 4.0; // Higher values will slow the effect 51 | 52 | vector ClockTimeAtLastBounce, Height, BallSpeed, Dampening; 53 | vector Colors; 54 | 55 | public: 56 | 57 | // BouncingBallEffect 58 | // 59 | // Caller specs strip length, number of balls, persistence level (255 is least), and whether the 60 | // balls should be drawn mirrored from each side. 61 | 62 | BouncingBallEffect(size_t cLength, size_t ballCount = 3, byte fade = 0, bool bMirrored = false) 63 | : _cLength(cLength - 1), 64 | _cBalls(ballCount), 65 | _fadeRate(fade), 66 | _bMirrored(bMirrored), 67 | ClockTimeAtLastBounce(ballCount), 68 | Height(ballCount), 69 | BallSpeed(ballCount), 70 | Dampening(ballCount), 71 | Colors(ballCount) 72 | { 73 | for (size_t i = 0; i < ballCount; i++) 74 | { 75 | Height[i] = StartHeight; // Current Ball Height 76 | ClockTimeAtLastBounce[i] = UnixTime(); // When ball last hit ground state 77 | Dampening[i] = 0.90 - i / pow(_cBalls, 2); // Bounciness of this ball 78 | BallSpeed[i] = InitialBallSpeed(Height[i]); // Don't dampen initial launch 79 | Colors[i] = ballColors[i % ARRAYSIZE(ballColors) ]; 80 | } 81 | } 82 | 83 | // Draw 84 | // 85 | // Draw each of the balls. When any ball settles with too little energy, it it "kicked" to restart it 86 | 87 | virtual void Draw() 88 | { 89 | if (_fadeRate != 0) 90 | { 91 | for (size_t i = 0; i < _cLength; i++) 92 | FastLED.leds()[i].fadeToBlackBy(_fadeRate); 93 | } 94 | else 95 | FastLED.clear(); 96 | 97 | // Draw each of the balls 98 | 99 | for (size_t i = 0; i < _cBalls; i++) 100 | { 101 | double TimeSinceLastBounce = (UnixTime() - ClockTimeAtLastBounce[i]) / SpeedKnob; 102 | 103 | // Use standard constant acceleration function - https://en.wikipedia.org/wiki/Acceleration 104 | Height[i] = 0.5 * Gravity * pow(TimeSinceLastBounce, 2.0) + BallSpeed[i] * TimeSinceLastBounce; 105 | 106 | // Ball hits ground - bounce! 107 | if (Height[i] < 0) 108 | { 109 | Height[i] = 0; 110 | BallSpeed[i] = Dampening[i] * BallSpeed[i]; 111 | ClockTimeAtLastBounce[i] = Time(); 112 | 113 | if (BallSpeed[i] < 0.01) 114 | BallSpeed[i] = InitialBallSpeed(StartHeight) * Dampening[i]; 115 | } 116 | 117 | size_t position = (size_t)(Height[i] * (_cLength - 1) / StartHeight); 118 | 119 | FastLED.leds()[position] += Colors[i]; 120 | FastLED.leds()[position+1] += Colors[i]; 121 | 122 | if (_bMirrored) 123 | { 124 | FastLED.leds()[_cLength - 1 - position] += Colors[i]; 125 | FastLED.leds()[_cLength - position] += Colors[i]; 126 | } 127 | } 128 | delay(20); 129 | } 130 | }; -------------------------------------------------------------------------------- /LED Episode 06/src/main.cpp: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: LED Episode 06 6 | // 7 | // Description: 8 | // 9 | // Draws sample effects on a an addressable strip using FastLED 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include // Arduino Framework 16 | #include // For text on the little on-chip OLED 17 | #define FASTLED_INTERNAL // Suppress build banner 18 | #include 19 | 20 | #define OLED_CLOCK 15 // Pins for the OLED display 21 | #define OLED_DATA 4 22 | #define OLED_RESET 16 23 | 24 | #define NUM_LEDS 45 // FastLED definitions 25 | #define LED_PIN 5 26 | 27 | CRGB g_LEDs[NUM_LEDS] = {0}; // Frame buffer for FastLED 28 | 29 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C g_OLED(U8G2_R2, OLED_RESET, OLED_CLOCK, OLED_DATA); 30 | int g_lineHeight = 0; 31 | int g_Brightness = 255; // 0-255 LED brightness scale 32 | 33 | 34 | 35 | // FramesPerSecond 36 | // 37 | // Tracks a weighted average to smooth out the values that it calcs as the simple reciprocal 38 | // of the amount of time taken specified by the caller. So 1/3 of a second is 3 fps, and it 39 | // will take up to 10 frames or so to stabilize on that value. 40 | 41 | double FramesPerSecond(double seconds) 42 | { 43 | static double framesPerSecond; 44 | framesPerSecond = (framesPerSecond * .9) + (1.0 / seconds * .1); 45 | return framesPerSecond; 46 | } 47 | 48 | void DrawPixels(double fPos, double count, CRGB color) 49 | { 50 | double availFirstPixel = 1.0 - (fPos - (long)(fPos)); 51 | double amtFirstPixel = min(availFirstPixel, count); 52 | count = min(count, FastLED.size()-fPos); 53 | if (fPos >= 0 && fPos < FastLED.size()) 54 | { 55 | CRGB frontColor = color; 56 | frontColor.fadeToBlackBy(255 * (1.0 - amtFirstPixel)); 57 | FastLED.leds()[(uint)fPos] += frontColor; 58 | } 59 | 60 | fPos += amtFirstPixel; 61 | count -= amtFirstPixel; 62 | 63 | while (count >= 1.0) 64 | { 65 | if (fPos >= 0 && fPos < FastLED.size()) 66 | { 67 | FastLED.leds()[(uint)fPos] += color; 68 | count -= 1.0; 69 | } 70 | fPos += 1.0; 71 | } 72 | 73 | if (count > 0.0) 74 | { 75 | if (fPos >= 0 && fPos < FastLED.size()) 76 | { 77 | CRGB backColor = color; 78 | backColor.fadeToBlackBy(255 * (1.0 - count)); 79 | FastLED.leds()[(uint)fPos] += backColor; 80 | } 81 | } 82 | } 83 | 84 | void set_max_power_indicator_LED(uint8_t); 85 | 86 | #include "twinkle.h" 87 | #include "marquee.h" 88 | #include "comet.h" 89 | #include "bounce.h" 90 | 91 | void setup() 92 | { 93 | pinMode(LED_BUILTIN, OUTPUT); 94 | pinMode(LED_PIN, OUTPUT); 95 | 96 | Serial.begin(115200); 97 | while (!Serial) { } 98 | Serial.println("ESP32 Startup"); 99 | 100 | g_OLED.begin(); 101 | g_OLED.clear(); 102 | g_OLED.setFont(u8g2_font_profont15_tf); 103 | g_lineHeight = g_OLED.getFontAscent() - g_OLED.getFontDescent(); // Descent is a negative number so we add it to the total 104 | 105 | FastLED.addLeds(g_LEDs, NUM_LEDS); // Add our LED strip to the FastLED library 106 | FastLED.setBrightness(g_Brightness); 107 | FastLED.setMaxPowerInMilliWatts(900); 108 | set_max_power_indicator_LED(LED_BUILTIN); 109 | } 110 | 111 | void loop() 112 | { 113 | double fps = 0; 114 | 115 | BouncingBallEffect balls(NUM_LEDS, 3, 0, false, 8.0); 116 | 117 | while (true) 118 | { 119 | double dStart = millis() / 1000.0; // Display a frame and calc how long it takes 120 | 121 | // Handle LEDs 122 | 123 | balls.Draw(); 124 | 125 | // Handle OLED drawing 126 | 127 | uint32_t milliwatts = calculate_unscaled_power_mW(g_LEDs, NUM_LEDS); 128 | 129 | static unsigned long msLastUpdate = millis(); 130 | if (millis() - msLastUpdate > 500) 131 | { 132 | g_OLED.clearBuffer(); 133 | g_OLED.setCursor(0, g_lineHeight); 134 | g_OLED.printf("FPS: %.1lf", fps); 135 | g_OLED.setCursor(1, g_lineHeight * 2); 136 | g_OLED.printf("Power: %u mW", milliwatts); 137 | g_OLED.sendBuffer(); 138 | msLastUpdate = millis(); 139 | } 140 | 141 | FastLED.show(g_Brightness); 142 | 143 | double dEnd = millis() / 1000.0; 144 | fps = FramesPerSecond(dEnd - dStart); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /LED Episode 08/src/bounce.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: bounce.h 6 | // 7 | // Description: 8 | // 9 | // Bouncing Ball effect on an LED strip 10 | // 11 | // History: Oct-04-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include // For time-of-day 16 | 17 | #include 18 | #define FASTLED_INTERNAL 19 | #include 20 | 21 | using namespace std; 22 | #include 23 | 24 | extern CRGB g_LEDs[]; 25 | 26 | static const CRGB ballColors [] = 27 | { 28 | CRGB::Green, 29 | CRGB::Red, 30 | CRGB::Blue, 31 | CRGB::Orange, 32 | CRGB::Indigo 33 | }; 34 | 35 | class BouncingBallEffect 36 | { 37 | private: 38 | 39 | float InitialBallSpeed(float height) const 40 | { 41 | return sqrt(-2 * Gravity * height); // Because MATH! 42 | } 43 | 44 | size_t _cLength; 45 | size_t _cBalls; 46 | byte _fadeRate; 47 | bool _bMirrored; 48 | 49 | const float Gravity = -9.81; // Because PHYSICS! 50 | const float StartHeight = 1; // Drop balls from max height initially 51 | const float ImpactVelocity = InitialBallSpeed(StartHeight); 52 | const float SpeedKnob = 4.0; // Higher values will slow the effect 53 | 54 | vector ClockTimeAtLastBounce, Height, BallSpeed, Dampening; 55 | vector Colors; 56 | 57 | static float Time() 58 | { 59 | timeval tv = { 0 }; 60 | gettimeofday(&tv, nullptr); 61 | return (float)(tv.tv_usec / 1000000.0 + (float) tv.tv_sec); 62 | } 63 | 64 | public: 65 | 66 | // BouncingBallEffect 67 | // 68 | // Caller specs strip length, number of balls, persistence level (255 is least), and whether the 69 | // balls should be drawn mirrored from each side. 70 | 71 | BouncingBallEffect(size_t cLength, size_t ballCount = 3, byte fade = 0, bool bMirrored = false) 72 | : _cLength(cLength - 1), 73 | _cBalls(ballCount), 74 | _fadeRate(fade), 75 | _bMirrored(bMirrored), 76 | ClockTimeAtLastBounce(ballCount), 77 | Height(ballCount), 78 | BallSpeed(ballCount), 79 | Dampening(ballCount), 80 | Colors(ballCount) 81 | { 82 | for (size_t i = 0; i < ballCount; i++) 83 | { 84 | Height[i] = StartHeight; // Current Ball Height 85 | ClockTimeAtLastBounce[i] = Time(); // When ball last hit ground state 86 | Dampening[i] = 0.90 - i / pow(_cBalls, 2); // Bounciness of this ball 87 | BallSpeed[i] = InitialBallSpeed(Height[i]); // Don't dampen initial launch 88 | Colors[i] = ballColors[i % ARRAYSIZE(ballColors) ]; 89 | } 90 | } 91 | 92 | // Draw 93 | // 94 | // Draw each of the balls. When any ball settles with too little energy, it it "kicked" to restart it 95 | 96 | virtual void Draw() 97 | { 98 | if (_fadeRate != 0) 99 | { 100 | for (size_t i = 0; i < _cLength; i++) 101 | g_LEDs[i].fadeToBlackBy(_fadeRate); 102 | } 103 | else 104 | FastLED.clear(); 105 | 106 | // Draw each of the balls 107 | 108 | for (size_t i = 0; i < _cBalls; i++) 109 | { 110 | float TimeSinceLastBounce = (Time() - ClockTimeAtLastBounce[i]) / SpeedKnob; 111 | 112 | // Use standard constant acceleration function - https://en.wikipedia.org/wiki/Acceleration 113 | Height[i] = 0.5 * Gravity * pow(TimeSinceLastBounce, 2.0) + BallSpeed[i] * TimeSinceLastBounce; 114 | 115 | // Ball hits ground - bounce! 116 | if (Height[i] < 0) 117 | { 118 | Height[i] = 0; 119 | BallSpeed[i] = Dampening[i] * BallSpeed[i]; 120 | ClockTimeAtLastBounce[i] = Time(); 121 | 122 | if (BallSpeed[i] < 0.01) 123 | BallSpeed[i] = InitialBallSpeed(StartHeight) * Dampening[i]; 124 | } 125 | 126 | size_t position = (size_t)(Height[i] * (_cLength - 1) / StartHeight); 127 | 128 | g_LEDs[position] += Colors[i]; 129 | g_LEDs[position+1] += Colors[i]; 130 | 131 | if (_bMirrored) 132 | { 133 | g_LEDs[_cLength - 1 - position] += Colors[i]; 134 | g_LEDs[_cLength - position] += Colors[i]; 135 | } 136 | } 137 | delay(20); 138 | } 139 | }; -------------------------------------------------------------------------------- /LED Episode 09/src/main.cpp: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: LED Episode 08 6 | // 7 | // Description: 8 | // 9 | // Draws sample effects on a an addressable strip using FastLED 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // Oct-05-2020 davepl Revised for Episode 07 13 | // Oct-11-2020 davepl Revised for Episode 08 14 | // Oct-16-2020 davepl Revised for Episode 09 15 | //--------------------------------------------------------------------------- 16 | 17 | #include // Arduino Framework 18 | #include // For text on the little on-chip OLED 19 | #define FASTLED_INTERNAL // Suppress build banner 20 | #include 21 | 22 | #define OLED_CLOCK 15 // Pins for the OLED display 23 | #define OLED_DATA 4 24 | #define OLED_RESET 16 25 | 26 | #define NUM_LEDS 40 // FastLED definitions 27 | #define LED_PIN 5 28 | 29 | CRGB g_LEDs[NUM_LEDS] = {0}; // Frame buffer for FastLED 30 | 31 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C g_OLED(U8G2_R2, OLED_RESET, OLED_CLOCK, OLED_DATA); 32 | int g_lineHeight = 0; 33 | int g_Brightness = 255; // 0-255 LED brightness scale 34 | int g_PowerLimit = 900; // 900mW Power Limit 35 | 36 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 37 | #define TIMES_PER_SECOND(x) EVERY_N_MILLISECONDS(1000/x) 38 | 39 | // FractionalColor 40 | // 41 | // Returns a fraction of a color; abstracts the fadeToBlack out to this function in case we 42 | // want to improve the color math or do color correction all in one location at a later date. 43 | 44 | CRGB ColorFraction(CRGB colorIn, float fraction) 45 | { 46 | fraction = min(1.0f, fraction); 47 | return CRGB(colorIn).fadeToBlackBy(255 * (1.0f - fraction)); 48 | } 49 | 50 | void DrawPixels(float fPos, float count, CRGB color) 51 | { 52 | // Calculate how much the first pixel will hold 53 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); 54 | float amtFirstPixel = min(availFirstPixel, count); 55 | float remaining = min(count, FastLED.size()-fPos); 56 | int iPos = fPos; 57 | 58 | // Blend (add) in the color of the first partial pixel 59 | 60 | if (remaining > 0.0f) 61 | { 62 | FastLED.leds()[iPos++] += ColorFraction(color, amtFirstPixel); 63 | remaining -= amtFirstPixel; 64 | } 65 | 66 | // Now draw any full pixels in the middle 67 | 68 | while (remaining > 1.0f) 69 | { 70 | FastLED.leds()[iPos++] += color; 71 | remaining--; 72 | } 73 | 74 | // Draw tail pixel, up to a single full pixel 75 | 76 | if (remaining > 0.0f) 77 | { 78 | FastLED.leds()[iPos] += ColorFraction(color, remaining); 79 | } 80 | } 81 | 82 | void DrawMarqueeComparison() 83 | { 84 | static float scroll = 0.0f; 85 | scroll += 0.1f; 86 | if (scroll > 5.0) 87 | scroll -= 5.0; 88 | 89 | for (float i = scroll; i < NUM_LEDS/2 -1; i+= 5) 90 | { 91 | DrawPixels(i, 3, CRGB::Green); 92 | DrawPixels(NUM_LEDS-1-(int)i, 3, CRGB::Red); 93 | } 94 | } 95 | 96 | 97 | void setup() 98 | { 99 | pinMode(LED_BUILTIN, OUTPUT); 100 | pinMode(LED_PIN, OUTPUT); 101 | 102 | Serial.begin(115200); 103 | while (!Serial) { } 104 | Serial.println("ESP32 Startup"); 105 | 106 | g_OLED.begin(); 107 | g_OLED.clear(); 108 | g_OLED.setFont(u8g2_font_profont15_tf); 109 | g_lineHeight = g_OLED.getFontAscent() - g_OLED.getFontDescent(); // Descent is a negative number so we add it to the total 110 | 111 | FastLED.addLeds(g_LEDs, NUM_LEDS); // Add our LED strip to the FastLED library 112 | FastLED.setBrightness(g_Brightness); 113 | set_max_power_indicator_LED(LED_BUILTIN); // Light the builtin LED if we power throttle 114 | FastLED.setMaxPowerInMilliWatts(g_PowerLimit); // Set the power limit, above which brightness will be throttled 115 | } 116 | 117 | void loop() 118 | { 119 | bool bLED = 0; 120 | 121 | while (true) 122 | { 123 | FastLED.clear(); 124 | // Draw here 125 | 126 | EVERY_N_MILLISECONDS(250) 127 | { 128 | g_OLED.clearBuffer(); 129 | g_OLED.setCursor(0, g_lineHeight); 130 | g_OLED.printf("FPS : %u", FastLED.getFPS()); 131 | g_OLED.setCursor(0, g_lineHeight * 2); 132 | g_OLED.printf("Power: %u mW", calculate_unscaled_power_mW(g_LEDs, NUM_LEDS)); 133 | g_OLED.setCursor(0, g_lineHeight * 3); 134 | g_OLED.printf("Brite: %d", calculate_max_brightness_for_power_mW(g_Brightness, g_PowerLimit)); 135 | g_OLED.sendBuffer(); 136 | } 137 | 138 | FastLED.setBrightness(g_Brightness); // Set the brightness scale 139 | FastLED.delay(33); // Show and delay 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /LED Episode 07/src/bounce.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: bounce.h 6 | // 7 | // Description: 8 | // 9 | // Bouncing Ball effect on an LED strip 10 | // 11 | // History: Oct-04-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include // For time-of-day 16 | 17 | #include 18 | #define FASTLED_INTERNAL 19 | #include 20 | 21 | using namespace std; 22 | #include 23 | 24 | extern CRGB g_LEDs[]; 25 | 26 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) // Count elements in a static array 27 | 28 | static const CRGB ballColors [] = 29 | { 30 | CRGB::Green, 31 | CRGB::Red, 32 | CRGB::Blue, 33 | CRGB::Orange, 34 | CRGB::Indigo 35 | }; 36 | 37 | class BouncingBallEffect 38 | { 39 | private: 40 | 41 | double InitialBallSpeed(double height) const 42 | { 43 | return sqrt(-2 * Gravity * height); // Because MATH! 44 | } 45 | 46 | size_t _cLength; 47 | size_t _cBalls; 48 | byte _fadeRate; 49 | bool _bMirrored; 50 | 51 | const double Gravity = -9.81; // Because PHYSICS! 52 | const double StartHeight = 1; // Drop balls from max height initially 53 | const double ImpactVelocity = InitialBallSpeed(StartHeight); 54 | const double SpeedKnob = 4.0; // Higher values will slow the effect 55 | 56 | vector ClockTimeAtLastBounce, Height, BallSpeed, Dampening; 57 | vector Colors; 58 | 59 | static double Time() 60 | { 61 | timeval tv = { 0 }; 62 | gettimeofday(&tv, nullptr); 63 | return (double)(tv.tv_usec / 1000000.0 + (double) tv.tv_sec); 64 | } 65 | 66 | public: 67 | 68 | // BouncingBallEffect 69 | // 70 | // Caller specs strip length, number of balls, persistence level (255 is least), and whether the 71 | // balls should be drawn mirrored from each side. 72 | 73 | BouncingBallEffect(size_t cLength, size_t ballCount = 3, byte fade = 0, bool bMirrored = false) 74 | : _cLength(cLength - 1), 75 | _cBalls(ballCount), 76 | _fadeRate(fade), 77 | _bMirrored(bMirrored), 78 | ClockTimeAtLastBounce(ballCount), 79 | Height(ballCount), 80 | BallSpeed(ballCount), 81 | Dampening(ballCount), 82 | Colors(ballCount) 83 | { 84 | for (size_t i = 0; i < ballCount; i++) 85 | { 86 | Height[i] = StartHeight; // Current Ball Height 87 | ClockTimeAtLastBounce[i] = Time(); // When ball last hit ground state 88 | Dampening[i] = 0.90 - i / pow(_cBalls, 2); // Bounciness of this ball 89 | BallSpeed[i] = InitialBallSpeed(Height[i]); // Don't dampen initial launch 90 | Colors[i] = ballColors[i % ARRAYSIZE(ballColors) ]; 91 | } 92 | } 93 | 94 | // Draw 95 | // 96 | // Draw each of the balls. When any ball settles with too little energy, it it "kicked" to restart it 97 | 98 | virtual void Draw() 99 | { 100 | if (_fadeRate != 0) 101 | { 102 | for (size_t i = 0; i < _cLength; i++) 103 | g_LEDs[i].fadeToBlackBy(_fadeRate); 104 | } 105 | else 106 | FastLED.clear(); 107 | 108 | // Draw each of the balls 109 | 110 | for (size_t i = 0; i < _cBalls; i++) 111 | { 112 | double TimeSinceLastBounce = (Time() - ClockTimeAtLastBounce[i]) / SpeedKnob; 113 | 114 | // Use standard constant acceleration function - https://en.wikipedia.org/wiki/Acceleration 115 | Height[i] = 0.5 * Gravity * pow(TimeSinceLastBounce, 2.0) + BallSpeed[i] * TimeSinceLastBounce; 116 | 117 | // Ball hits ground - bounce! 118 | if (Height[i] < 0) 119 | { 120 | Height[i] = 0; 121 | BallSpeed[i] = Dampening[i] * BallSpeed[i]; 122 | ClockTimeAtLastBounce[i] = Time(); 123 | 124 | if (BallSpeed[i] < 0.01) 125 | BallSpeed[i] = InitialBallSpeed(StartHeight) * Dampening[i]; 126 | } 127 | 128 | size_t position = (size_t)(Height[i] * (_cLength - 1) / StartHeight); 129 | 130 | g_LEDs[position] += Colors[i]; 131 | g_LEDs[position+1] += Colors[i]; 132 | 133 | if (_bMirrored) 134 | { 135 | g_LEDs[_cLength - 1 - position] += Colors[i]; 136 | g_LEDs[_cLength - position] += Colors[i]; 137 | } 138 | } 139 | delay(20); 140 | } 141 | }; -------------------------------------------------------------------------------- /LED Episode 09/src/bounce.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: bounce.h 6 | // 7 | // Description: 8 | // 9 | // Bouncing Ball effect on an LED strip 10 | // 11 | // History: Oct-04-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include // For time-of-day 16 | 17 | #include 18 | #define FASTLED_INTERNAL 19 | #include 20 | 21 | using namespace std; 22 | #include 23 | 24 | extern CRGB g_LEDs[]; 25 | 26 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) // Count elements in a static array 27 | 28 | static const CRGB ballColors [] = 29 | { 30 | CRGB::Green, 31 | CRGB::Red, 32 | CRGB::Blue, 33 | CRGB::Orange, 34 | CRGB::Indigo 35 | }; 36 | 37 | class BouncingBallEffect 38 | { 39 | private: 40 | 41 | double InitialBallSpeed(double height) const 42 | { 43 | return sqrt(-2 * Gravity * height); // Because MATH! 44 | } 45 | 46 | size_t _cLength; 47 | size_t _cBalls; 48 | byte _fadeRate; 49 | bool _bMirrored; 50 | 51 | const double Gravity = -9.81; // Because PHYSICS! 52 | const double StartHeight = 1; // Drop balls from max height initially 53 | const double ImpactVelocity = InitialBallSpeed(StartHeight); 54 | const double SpeedKnob = 4.0; // Higher values will slow the effect 55 | 56 | vector ClockTimeAtLastBounce, Height, BallSpeed, Dampening; 57 | vector Colors; 58 | 59 | static double Time() 60 | { 61 | timeval tv = { 0 }; 62 | gettimeofday(&tv, nullptr); 63 | return (double)(tv.tv_usec / 1000000.0 + (double) tv.tv_sec); 64 | } 65 | 66 | public: 67 | 68 | // BouncingBallEffect 69 | // 70 | // Caller specs strip length, number of balls, persistence level (255 is least), and whether the 71 | // balls should be drawn mirrored from each side. 72 | 73 | BouncingBallEffect(size_t cLength, size_t ballCount = 3, byte fade = 0, bool bMirrored = false) 74 | : _cLength(cLength - 1), 75 | _cBalls(ballCount), 76 | _fadeRate(fade), 77 | _bMirrored(bMirrored), 78 | ClockTimeAtLastBounce(ballCount), 79 | Height(ballCount), 80 | BallSpeed(ballCount), 81 | Dampening(ballCount), 82 | Colors(ballCount) 83 | { 84 | for (size_t i = 0; i < ballCount; i++) 85 | { 86 | Height[i] = StartHeight; // Current Ball Height 87 | ClockTimeAtLastBounce[i] = Time(); // When ball last hit ground state 88 | Dampening[i] = 0.90 - i / pow(_cBalls, 2); // Bounciness of this ball 89 | BallSpeed[i] = InitialBallSpeed(Height[i]); // Don't dampen initial launch 90 | Colors[i] = ballColors[i % ARRAYSIZE(ballColors) ]; 91 | } 92 | } 93 | 94 | // Draw 95 | // 96 | // Draw each of the balls. When any ball settles with too little energy, it it "kicked" to restart it 97 | 98 | virtual void Draw() 99 | { 100 | if (_fadeRate != 0) 101 | { 102 | for (size_t i = 0; i < _cLength; i++) 103 | g_LEDs[i].fadeToBlackBy(_fadeRate); 104 | } 105 | else 106 | FastLED.clear(); 107 | 108 | // Draw each of the balls 109 | 110 | for (size_t i = 0; i < _cBalls; i++) 111 | { 112 | double TimeSinceLastBounce = (Time() - ClockTimeAtLastBounce[i]) / SpeedKnob; 113 | 114 | // Use standard constant acceleration function - https://en.wikipedia.org/wiki/Acceleration 115 | Height[i] = 0.5 * Gravity * pow(TimeSinceLastBounce, 2.0) + BallSpeed[i] * TimeSinceLastBounce; 116 | 117 | // Ball hits ground - bounce! 118 | if (Height[i] < 0) 119 | { 120 | Height[i] = 0; 121 | BallSpeed[i] = Dampening[i] * BallSpeed[i]; 122 | ClockTimeAtLastBounce[i] = Time(); 123 | 124 | if (BallSpeed[i] < 0.01) 125 | BallSpeed[i] = InitialBallSpeed(StartHeight) * Dampening[i]; 126 | } 127 | 128 | size_t position = (size_t)(Height[i] * (_cLength - 1) / StartHeight); 129 | 130 | g_LEDs[position] += Colors[i]; 131 | g_LEDs[position+1] += Colors[i]; 132 | 133 | if (_bMirrored) 134 | { 135 | g_LEDs[_cLength - 1 - position] += Colors[i]; 136 | g_LEDs[_cLength - position] += Colors[i]; 137 | } 138 | } 139 | delay(20); 140 | } 141 | }; -------------------------------------------------------------------------------- /LED Episode 07/src/main.cpp: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: LED Episode 08 6 | // 7 | // Description: 8 | // 9 | // Draws sample effects on a an addressable strip using FastLED 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // Oct-05-2020 davepl Revised for Episode 07 13 | // Oct-11-2020 davepl Revised for Episode 08 14 | // Oct-16-2020 davepl Revised for Episode 09 15 | //--------------------------------------------------------------------------- 16 | 17 | #include // Arduino Framework 18 | #include // For text on the little on-chip OLED 19 | #define FASTLED_INTERNAL // Suppress build banner 20 | #include 21 | 22 | #define OLED_CLOCK 15 // Pins for the OLED display 23 | #define OLED_DATA 4 24 | #define OLED_RESET 16 25 | 26 | #define NUM_LEDS 40 // FastLED definitions 27 | #define LED_PIN 5 28 | 29 | CRGB g_LEDs[NUM_LEDS] = {0}; // Frame buffer for FastLED 30 | 31 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C g_OLED(U8G2_R2, OLED_RESET, OLED_CLOCK, OLED_DATA); 32 | int g_lineHeight = 0; 33 | int g_Brightness = 255; // 0-255 LED brightness scale 34 | int g_PowerLimit = 900; // 900mW Power Limit 35 | 36 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 37 | #define TIMES_PER_SECOND(x) EVERY_N_MILLISECONDS(1000/x) 38 | 39 | // FractionalColor 40 | // 41 | // Returns a fraction of a color; abstracts the fadeToBlack out to this function in case we 42 | // want to improve the color math or do color correction all in one location at a later date. 43 | 44 | CRGB ColorFraction(CRGB colorIn, float fraction) 45 | { 46 | fraction = min(1.0f, fraction); 47 | return CRGB(colorIn).fadeToBlackBy(255 * (1.0f - fraction)); 48 | } 49 | 50 | void DrawPixels(float fPos, float count, CRGB color) 51 | { 52 | // Calculate how much the first pixel will hold 53 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); 54 | float amtFirstPixel = min(availFirstPixel, count); 55 | float remaining = min(count, FastLED.size()-fPos); 56 | int iPos = fPos; 57 | 58 | // Blend (add) in the color of the first partial pixel 59 | 60 | if (remaining > 0.0f) 61 | { 62 | FastLED.leds()[iPos++] += ColorFraction(color, amtFirstPixel); 63 | remaining -= amtFirstPixel; 64 | } 65 | 66 | // Now draw any full pixels in the middle 67 | 68 | while (remaining > 1.0f) 69 | { 70 | FastLED.leds()[iPos++] += color; 71 | remaining--; 72 | } 73 | 74 | // Draw tail pixel, up to a single full pixel 75 | 76 | if (remaining > 0.0f) 77 | { 78 | FastLED.leds()[iPos] += ColorFraction(color, remaining); 79 | } 80 | } 81 | 82 | void DrawMarqueeComparison() 83 | { 84 | static float scroll = 0.0f; 85 | scroll += 0.1f; 86 | if (scroll > 5.0) 87 | scroll -= 5.0; 88 | 89 | for (float i = scroll; i < NUM_LEDS/2 -1; i+= 5) 90 | { 91 | DrawPixels(i, 3, CRGB::Green); 92 | DrawPixels(NUM_LEDS-1-(int)i, 3, CRGB::Red); 93 | } 94 | } 95 | 96 | 97 | void setup() 98 | { 99 | pinMode(LED_BUILTIN, OUTPUT); 100 | pinMode(LED_PIN, OUTPUT); 101 | 102 | Serial.begin(115200); 103 | while (!Serial) { } 104 | Serial.println("ESP32 Startup"); 105 | 106 | g_OLED.begin(); 107 | g_OLED.clear(); 108 | g_OLED.setFont(u8g2_font_profont15_tf); 109 | g_lineHeight = g_OLED.getFontAscent() - g_OLED.getFontDescent(); // Descent is a negative number so we add it to the total 110 | 111 | FastLED.addLeds(g_LEDs, NUM_LEDS); // Add our LED strip to the FastLED library 112 | FastLED.setBrightness(g_Brightness); 113 | set_max_power_indicator_LED(LED_BUILTIN); // Light the builtin LED if we power throttle 114 | FastLED.setMaxPowerInMilliWatts(g_PowerLimit); // Set the power limit, above which brightness will be throttled 115 | } 116 | 117 | void loop() 118 | { 119 | bool bLED = 0; 120 | 121 | while (true) 122 | { 123 | EVERY_N_MILLISECONDS(20) 124 | { 125 | /* 126 | fadeToBlackBy(g_LEDs, NUM_LEDS, 64); 127 | int cometSize = 5; 128 | int iPos = beatsin16(32, 0, NUM_LEDS-cometSize); 129 | byte hue = beatsin8(96); 130 | for (int i = iPos; i < iPos + cometSize; i++) 131 | g_LEDs[i] = CHSV(hue, 255, 255); 132 | */ 133 | 134 | DrawMarqueeComparison(); 135 | } 136 | 137 | EVERY_N_MILLISECONDS(250) 138 | { 139 | g_OLED.clearBuffer(); 140 | g_OLED.setCursor(0, g_lineHeight); 141 | g_OLED.printf("FPS : %u", FastLED.getFPS()); 142 | g_OLED.setCursor(0, g_lineHeight * 2); 143 | g_OLED.printf("Power: %u mW", calculate_unscaled_power_mW(g_LEDs, NUM_LEDS)); 144 | g_OLED.setCursor(0, g_lineHeight * 3); 145 | g_OLED.printf("Brite: %d", calculate_max_brightness_for_power_mW(g_Brightness, g_PowerLimit)); 146 | g_OLED.sendBuffer(); 147 | } 148 | 149 | FastLED.setBrightness(g_Brightness); // Set the brightness scale 150 | FastLED.delay(10); // Show and delay 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /LED Episode 08/src/main.cpp: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: LED Episode 07 6 | // 7 | // Description: 8 | // 9 | // Draws sample effects on a an addressable strip using FastLED 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // Oct-15-2020 davepl Revised for Episode 07 13 | // 14 | //--------------------------------------------------------------------------- 15 | 16 | #include // Arduino Framework 17 | #include // For text on the little on-chip OLED 18 | #define FASTLED_INTERNAL // Suppress build banner 19 | #include 20 | 21 | #define OLED_CLOCK 15 // Pins for the OLED display 22 | #define OLED_DATA 4 23 | #define OLED_RESET 16 24 | 25 | #define NUM_LEDS 40 // FastLED definitions 26 | #define LED_PIN 5 27 | 28 | CRGB g_LEDs[NUM_LEDS] = {0}; // Frame buffer for FastLED 29 | 30 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C g_OLED(U8G2_R2, OLED_RESET, OLED_CLOCK, OLED_DATA); 31 | int g_lineHeight = 0; 32 | int g_Brightness = 255; // 0-255 LED brightness scale 33 | int g_PowerLimit = 900; // 900mW draw 34 | 35 | #define TIMES_PER_SECOND(x) EVERY_N_MILLISECONDS(1000/x) 36 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 37 | 38 | // FractionalColor 39 | // 40 | // Returns a fraction of a color; abstracts the fadeToBlack away so that we can later 41 | // do better color correction as needed 42 | 43 | CRGB ColorFraction(const CRGB colorIn, float fraction) 44 | { 45 | fraction = min(1.0f, fraction); 46 | return CRGB(colorIn).fadeToBlackBy(255 * (1.0f - fraction)); 47 | } 48 | 49 | // DrawPixels 50 | // 51 | // Draw a sub-pixel precise amount of pixels starting at a floating point offset; for example 52 | // you can draw 2.75 pixels starting a 5.5, and it will end at 8.25 53 | 54 | void DrawPixels(float fPos, float count, CRGB color) 55 | { 56 | // Figure out how much the first pixel will hold 57 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); // If we are starting at 2.25, there would be 0.75 avail here 58 | float amtFirstPixel = min(availFirstPixel, count); // But of course we never draw more than we need 59 | float remaining = min(count, FastLED.size()-fPos); // How many pixels remain after we draw the front header pixel 60 | int iPos = fPos; 61 | 62 | // Blend (add) in the color value of this first partial pixel ...and decrement the remaining pixel count by that same amount 63 | 64 | if (remaining > 0.0f) 65 | { 66 | FastLED.leds()[iPos++] += ColorFraction(color, amtFirstPixel); 67 | remaining -= amtFirstPixel; 68 | } 69 | 70 | // Draw any full pixels and stop when we have a full pixel or less remainining 71 | 72 | while (remaining > 1.0f) // Final pixel can 'handle' up to 1.0 full pixels, so we draw anything more here 73 | { 74 | FastLED.leds()[iPos++] += color; // Draw them in one at aa time and update the remaining counts 75 | remaining--; 76 | } 77 | 78 | // Draw tail pixel, up to a single full pixel 79 | 80 | if (remaining > 0.0f) 81 | { 82 | FastLED.leds()[iPos] += ColorFraction(color, remaining); 83 | } 84 | } 85 | 86 | 87 | #include "marquee.h" 88 | 89 | void setup() 90 | { 91 | pinMode(LED_BUILTIN, OUTPUT); 92 | pinMode(LED_PIN, OUTPUT); 93 | 94 | Serial.begin(115200); 95 | while (!Serial) { } 96 | Serial.println("ESP32 Startup"); 97 | 98 | g_OLED.begin(); 99 | g_OLED.clear(); 100 | g_OLED.setFont(u8g2_font_profont15_tf); 101 | g_lineHeight = g_OLED.getFontAscent() - g_OLED.getFontDescent(); // Descent is a negative number so we add it to the total 102 | 103 | FastLED.addLeds(g_LEDs, NUM_LEDS); // Add our LED strip to the FastLED library 104 | FastLED.setBrightness(g_Brightness); 105 | set_max_power_indicator_LED(LED_BUILTIN); // FastLED will light LED if power limiting 106 | FastLED.setMaxPowerInMilliWatts(g_PowerLimit); 107 | } 108 | 109 | 110 | void loop() 111 | { 112 | bool bLED = 0; 113 | float fps = 0; 114 | byte gHue = 0; 115 | 116 | while (true) 117 | { 118 | TIMES_PER_SECOND(50) 119 | { 120 | fadeToBlackBy(g_LEDs, NUM_LEDS, 64); 121 | float pos = beatsin16(32, 0, NUM_LEDS-10); 122 | byte hue = beatsin8(32, 0, 255); 123 | DrawPixels(pos, 10, CHSV(0, 255, 255)); 124 | FastLED.show(g_Brightness); 125 | } 126 | 127 | /* 128 | TIMES_PER_SECOND(50) 129 | { 130 | DrawMarqueeComparison(); 131 | } 132 | */ 133 | EVERY_N_MILLISECONDS(250) 134 | { 135 | g_OLED.clearBuffer(); 136 | g_OLED.setCursor(0, g_lineHeight); 137 | g_OLED.printf("FPS : %u", FastLED.getFPS()); 138 | g_OLED.setCursor(0, g_lineHeight * 2); 139 | g_OLED.printf("Power: %u mW", calculate_unscaled_power_mW(g_LEDs, NUM_LEDS)); 140 | g_OLED.setCursor(0, g_lineHeight * 3); 141 | g_OLED.printf("Brite: %d", calculate_max_brightness_for_power_mW( g_Brightness, g_PowerLimit)); 142 | g_OLED.sendBuffer(); 143 | } 144 | 145 | FastLED.delay(10); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /LED Episode 06/src/bounce.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: bounce.h 6 | // 7 | // Description: 8 | // 9 | // Draws bouncing balls on an LED strip 10 | // 11 | // History: Ocf-01-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | //+-------------------------------------------------------------------------- 16 | // 17 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 18 | // 19 | // File: 20 | // 21 | // Description: 22 | // 23 | // 24 | // 25 | // History: Oct-04-2020 davepl Created 26 | // 27 | //--------------------------------------------------------------------------- 28 | 29 | #include // For time-of-day 30 | 31 | #include 32 | #define FASTLED_INTERNAL 33 | #include 34 | 35 | using namespace std; 36 | #include // Use the C++ resizable array 37 | 38 | extern CRGB g_LEDs[]; 39 | 40 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) // Count elements in a static array 41 | 42 | // BouncingBallEffect 43 | // 44 | // Draws a set of N bouncing balls using a simple little kinematics formula. Clears the section first. 45 | 46 | static const CRGB ballColors[] = 47 | { 48 | CRGB::Green, 49 | CRGB::Red, 50 | CRGB::Blue, 51 | CRGB::Orange, 52 | CRGB::Indigo, 53 | CRGB::Cyan 54 | }; 55 | 56 | class BouncingBallEffect 57 | { 58 | private: 59 | 60 | double InitialBallSpeed(double height) const 61 | { 62 | return sqrt(-2 * Gravity * height); 63 | } 64 | 65 | size_t _cLength; 66 | size_t _cBalls; 67 | byte _Fade; 68 | bool _bMirrored; 69 | double _SpeedKnob; 70 | 71 | const double Gravity = -9.81; // Because PHYSICS! 72 | const double StartHeight = 1; // Drop balls from max height to start 73 | const double ImpactVelocityStart = InitialBallSpeed(StartHeight); // Speed for a 74 | const double SpeedKnob = 4; // High number will slow effect down 75 | 76 | vector ClockTimeAtLastBounce, Height, BallSpeed, Dampening; // When the ball last bounced 77 | 78 | // Time - Return current time in floating form for easier calcs than ms 79 | 80 | double Time() const 81 | { 82 | timeval tv = { 0 }; 83 | gettimeofday(&tv, nullptr); 84 | return (double)(tv.tv_usec / (double)1000000 +(double)tv.tv_sec); 85 | } 86 | 87 | 88 | public: 89 | 90 | // BouncingBallEffect 91 | // 92 | // Caller specs strip length, number of balls, persistence level (255 is least), and whether 93 | // the balls should be drawn mirrored from each side. 94 | 95 | BouncingBallEffect(size_t cLength, size_t ballCount = 3, byte fade = 0, bool bMirrored = false, double SpeedKnob = 4.0) 96 | : _cLength(cLength-1), // Reserve one LED for floating point fraction draw 97 | _cBalls(ballCount), 98 | _Fade(fade), 99 | _bMirrored(bMirrored), 100 | _SpeedKnob(SpeedKnob), 101 | ClockTimeAtLastBounce(ballCount), 102 | Height(ballCount), 103 | BallSpeed(ballCount), 104 | Dampening(ballCount) 105 | { 106 | 107 | for (size_t i = 0; i < ballCount; i++) 108 | { 109 | Height[i] = StartHeight; // Current ball height 110 | ClockTimeAtLastBounce[i] = Time(); // When the last time it hit ground was 111 | Dampening[i] = 1.0 - i / pow(_cBalls, 2); // Each ball bounces differently 112 | BallSpeed[i] = InitialBallSpeed(Height[i]); // Don't dampen initial launch to they go together 113 | } 114 | } 115 | 116 | // Draw 117 | // 118 | // Draw each of the balls. When any ball gets too little energy it would just sit at the base so it is re-kicked with new energy.#pragma endregion 119 | 120 | virtual void Draw() 121 | { 122 | if (_Fade) 123 | { 124 | for (size_t i = 0; i < _cLength; i++) 125 | { 126 | g_LEDs[i].fadeToBlackBy(_Fade); 127 | } 128 | } 129 | else 130 | { 131 | FastLED.clear(); 132 | } 133 | 134 | // Draw each of the three balls 135 | for (size_t i = 0; i < _cBalls; i++) 136 | { 137 | double TimeSinceLastBounce = (Time() - ClockTimeAtLastBounce[i]) / _SpeedKnob; 138 | Height[i] = 0.5 * Gravity * pow(TimeSinceLastBounce, 2.0) + BallSpeed[i] * TimeSinceLastBounce; 139 | 140 | if (Height[i] < 0) 141 | { 142 | Height[i] = 0; 143 | BallSpeed[i] = Dampening[i] * BallSpeed[i]; 144 | ClockTimeAtLastBounce[i] = Time(); 145 | 146 | if (BallSpeed[i] < 1.0) 147 | BallSpeed[i] = InitialBallSpeed(StartHeight) * Dampening[i]; 148 | } 149 | 150 | static const CRGB ballColors[] = { CRGB::Red, CRGB::Blue, CRGB::Green, CRGB::Orange, CRGB::Violet }; 151 | CRGB color = ballColors[i % ARRAYSIZE(ballColors)]; 152 | 153 | double position = (Height[i] * (_cLength - 1.0) / StartHeight); 154 | DrawPixels(position, 1, color); 155 | if (_bMirrored) 156 | DrawPixels(_cLength - 1 - position, 1, color); 157 | 158 | } 159 | delay(20); 160 | } 161 | }; 162 | -------------------------------------------------------------------------------- /Fans/include/ledgfx.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: ledgfx.h 6 | // 7 | // Description: 8 | // 9 | // LED Drawing Routines for Dave's Garage Tutorial series 10 | // 11 | // History: OCt-18-2020 davepl Created from main.cpp code 12 | //--------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | #include // For time-of-day 21 | 22 | // Utility Macros 23 | 24 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 25 | #define TIMES_PER_SECOND(x) EVERY_N_MILLISECONDS(1000/x) 26 | 27 | //inline double RandomDouble() 28 | //{ 29 | // return random(UINT32_MAX) / (double) UINT32_MAX; 30 | //} 31 | 32 | inline float RandomFloat() 33 | { 34 | float r = random(1000000L) / 1000000.0f; 35 | return r; 36 | } 37 | 38 | inline double UnixTime() 39 | { 40 | timeval tv = { 0 }; 41 | gettimeofday(&tv, nullptr); 42 | return (double)(tv.tv_usec / 1000000.0 + (double) tv.tv_sec); 43 | } 44 | 45 | // FractionalColor 46 | // 47 | // Returns a fraction of a color; abstracts the fadeToBlack out to this function in case we 48 | // want to improve the color math or do color correction all in one location at a later date. 49 | 50 | CRGB ColorFraction(CRGB colorIn, float fraction) 51 | { 52 | fraction = min(1.0f, fraction); 53 | return CRGB(colorIn).fadeToBlackBy(255 * (1.0f - fraction)); 54 | } 55 | 56 | void DrawPixels(float fPos, float count, CRGB color) 57 | { 58 | // Calculate how much the first pixel will hold 59 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); 60 | float amtFirstPixel = min(availFirstPixel, count); 61 | float remaining = min(count, FastLED.size()-fPos); 62 | int iPos = fPos; 63 | 64 | // Blend (add) in the color of the first partial pixel 65 | 66 | if (remaining > 0.0f) 67 | { 68 | FastLED.leds()[iPos++] += ColorFraction(color, amtFirstPixel); 69 | remaining -= amtFirstPixel; 70 | } 71 | 72 | // Now draw any full pixels in the middle 73 | 74 | while (remaining > 1.0f) 75 | { 76 | FastLED.leds()[iPos++] += color; 77 | remaining--; 78 | } 79 | 80 | // Draw tail pixel, up to a single full pixel 81 | 82 | if (remaining > 0.0f) 83 | { 84 | FastLED.leds()[iPos] += ColorFraction(color, remaining); 85 | } 86 | } 87 | 88 | DEFINE_GRADIENT_PALETTE( vu_gpGreen ) 89 | { 90 | 0, 0, 4, 0, // near black green 91 | 64, 0, 255, 0, // green 92 | 128, 255, 255, 0, // yellow 93 | 192, 255, 0, 0, // red 94 | 255, 255, 0, 0 // red 95 | }; 96 | 97 | DEFINE_GRADIENT_PALETTE( vu_gpSeahawks ) 98 | { 99 | 0, 0, 0, 4, 100 | 64, 3, 38, 58, 101 | 128, 0, 21, 50, 102 | 192, 78, 167, 1, 103 | 255, 54, 87, 140, 104 | }; 105 | 106 | static const int FanPixelsVertical[FAN_SIZE] = 107 | { 108 | 0, 1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8 109 | }; 110 | 111 | static const int FanPixelsHorizontal[FAN_SIZE] = 112 | { 113 | 3, 4, 2, 5, 1, 6, 0, 7, 15, 8, 14, 9, 13, 10, 12, 11 114 | }; 115 | 116 | enum PixelOrder 117 | { 118 | Sequential = 0, 119 | Reverse = 1, 120 | BottomUp = 2, 121 | TopDown = 4, 122 | LeftRight = 8, 123 | RightLeft = 16 124 | }; 125 | 126 | int GetFanPixelOrder(int iPos, PixelOrder order = Sequential) 127 | { 128 | while (iPos < 0) 129 | iPos += FAN_SIZE; 130 | 131 | int offset = (iPos + LED_FAN_OFFSET) % FAN_SIZE; // Offset within this fan 132 | int roffset = (iPos + FAN_SIZE - LED_FAN_OFFSET) % FAN_SIZE; // Offset within this fan 133 | 134 | int fanBase = iPos - (iPos % FAN_SIZE); // Round down to previous multiple of FAN_SIZE 135 | 136 | switch (order) 137 | { 138 | case BottomUp: 139 | return fanBase + FAN_SIZE - 1 - (FanPixelsVertical[iPos % FAN_SIZE] + LED_FAN_OFFSET) % FAN_SIZE; 140 | 141 | case TopDown: 142 | return NUM_LEDS - 1 - (fanBase + (FanPixelsVertical[FAN_SIZE - 1 - (iPos % FAN_SIZE)] + LED_FAN_OFFSET) % FAN_SIZE); 143 | 144 | case LeftRight: 145 | return fanBase + (FanPixelsHorizontal[ iPos % FAN_SIZE ] + LED_FAN_OFFSET - 1) % FAN_SIZE; 146 | 147 | case RightLeft: 148 | return fanBase + (FanPixelsHorizontal[FAN_SIZE - 1 - (iPos % FAN_SIZE) ] + LED_FAN_OFFSET - 1) % FAN_SIZE; 149 | 150 | case Reverse: 151 | return fanBase + FAN_SIZE - 1 - roffset; 152 | 153 | case Sequential: 154 | default: 155 | return fanBase + offset; 156 | } 157 | } 158 | 159 | void DrawFanPixels(float fPos, float count, CRGB color, PixelOrder order = Sequential, int iFan = 0) 160 | { 161 | fPos += iFan * FAN_SIZE; 162 | 163 | // Calculate how much the first pixel will hold 164 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); 165 | float amtFirstPixel = min(availFirstPixel, count); 166 | float remaining = min(count, FastLED.size()-fPos); 167 | int iPos = fPos; 168 | 169 | // Blend (add) in the color of the first partial pixel 170 | 171 | if (remaining > 0.0f) 172 | { 173 | FastLED.leds()[GetFanPixelOrder(iPos++, order)] += ColorFraction(color, amtFirstPixel); 174 | remaining -= amtFirstPixel; 175 | } 176 | 177 | // Now draw any full pixels in the middle 178 | 179 | while (remaining > 1.0f) 180 | { 181 | FastLED.leds()[GetFanPixelOrder(iPos++, order)] += color; 182 | remaining--; 183 | } 184 | 185 | // Draw tail pixel, up to a single full pixel 186 | 187 | if (remaining > 0.0f) 188 | { 189 | FastLED.leds()[GetFanPixelOrder(iPos, order)] += ColorFraction(color, remaining); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /LED Episode 11/include/ledgfx.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: ledgfx.h 6 | // 7 | // Description: 8 | // 9 | // LED Drawing Routines for Dave's Garage Tutorial series 10 | // 11 | // History: OCt-18-2020 davepl Created from main.cpp code 12 | //--------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | #include 17 | #define FASTLED_INTERNAL 18 | #include 19 | 20 | #include // For time-of-day 21 | 22 | // Utility Macros 23 | 24 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 25 | #define TIMES_PER_SECOND(x) EVERY_N_MILLISECONDS(1000/x) 26 | 27 | // Simple definitions of what direction we're talking about 28 | 29 | enum PixelOrder 30 | { 31 | Sequential = 0, 32 | Reverse = 1, 33 | BottomUp = 2, 34 | TopDown = 4, 35 | LeftRight = 8, 36 | RightLeft = 16 37 | }; 38 | 39 | DEFINE_GRADIENT_PALETTE( vu_gpGreen ) 40 | { 41 | 0, 0, 4, 0, // near black green 42 | 64, 0, 255, 0, // green 43 | 128, 255, 255, 0, // yellow 44 | 192, 255, 0, 0, // red 45 | 255, 255, 0, 0 // red 46 | }; 47 | 48 | DEFINE_GRADIENT_PALETTE( gpSeahawks ) 49 | { 50 | 0, 0, 0, 4, 51 | 64, 3, 38, 58, 52 | 128, 0, 21, 50, 53 | 192, 78, 167, 1, 54 | 255, 54, 87, 140, 55 | }; 56 | 57 | // These tables represent the physical order of LEDs when looking at 58 | // the fan in a particular direction, like top to bottom or left to right 59 | 60 | static const int FanPixelsVertical[FAN_SIZE] = 61 | { 62 | 0, 1, 15, 2, 14, 3, 13, 4, 12, 5, 11, 6, 10, 7, 9, 8 63 | }; 64 | 65 | static const int FanPixelsHorizontal[FAN_SIZE] = 66 | { 67 | 3, 4, 2, 5, 1, 6, 0, 7, 15, 8, 14, 9, 13, 10, 12, 11 68 | }; 69 | 70 | // GetFanPixelOrder 71 | // 72 | // Returns the sequential strip postion of a an LED on the fans based 73 | // on the index and direction specified, like 32nd most TopDown pixel. 74 | 75 | int GetFanPixelOrder(int iPos, PixelOrder order = Sequential) 76 | { 77 | while (iPos < 0) 78 | iPos += FAN_SIZE; 79 | 80 | int offset = (iPos + LED_FAN_OFFSET) % FAN_SIZE; 81 | int roffset = (iPos + FAN_SIZE - LED_FAN_OFFSET) % FAN_SIZE; 82 | int fanBase = iPos - (iPos % FAN_SIZE); 83 | 84 | switch (order) 85 | { 86 | case BottomUp: 87 | return fanBase + FAN_SIZE - 1 - (FanPixelsVertical[iPos % FAN_SIZE] + LED_FAN_OFFSET) % FAN_SIZE; 88 | 89 | case TopDown: 90 | return NUM_LEDS - 1 - (fanBase + (FanPixelsVertical[FAN_SIZE - 1 - (iPos % FAN_SIZE)] + LED_FAN_OFFSET) % FAN_SIZE); 91 | 92 | case LeftRight: 93 | return fanBase + (FanPixelsHorizontal[ iPos % FAN_SIZE ] + LED_FAN_OFFSET - 1) % FAN_SIZE; 94 | 95 | case RightLeft: 96 | return fanBase + (FanPixelsHorizontal[FAN_SIZE - 1 - (iPos % FAN_SIZE)] + LED_FAN_OFFSET - 1) % FAN_SIZE; 97 | 98 | case Reverse: 99 | return fanBase + FAN_SIZE - 1 - roffset; 100 | 101 | case Sequential: 102 | default: 103 | return fanBase + offset; 104 | } 105 | } 106 | 107 | 108 | inline float RandomFloat() 109 | { 110 | float r = random(1000000L) / 1000000.0f; 111 | return r; 112 | } 113 | 114 | inline double UnixTime() 115 | { 116 | timeval tv = { 0 }; 117 | gettimeofday(&tv, nullptr); 118 | return (double)(tv.tv_usec / 1000000.0 + (double) tv.tv_sec); 119 | } 120 | 121 | // FractionalColor 122 | // 123 | // Returns a fraction of a color; abstracts the fadeToBlack out to this function in case we 124 | // want to improve the color math or do color correction all in one location at a later date. 125 | 126 | CRGB ColorFraction(CRGB colorIn, float fraction) 127 | { 128 | fraction = min(1.0f, fraction); 129 | return CRGB(colorIn).fadeToBlackBy(255 * (1.0f - fraction)); 130 | } 131 | 132 | // DrawFanPixels 133 | // 134 | // Just like DrawPixels but draws logically into a fan bank in a direction such as top down rather than 135 | // just straight sequential strip order 136 | 137 | void DrawFanPixels(float fPos, float count, CRGB color, PixelOrder order = Sequential, int iFan = 0) 138 | { 139 | fPos += iFan * FAN_SIZE; 140 | 141 | // Calculate how much the first pixel will hold 142 | 143 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); 144 | float amtFirstPixel = min(availFirstPixel, count); 145 | float remaining = min(count, FastLED.size()-fPos); 146 | int iPos = fPos; 147 | 148 | // Blend (add) in the color of the first partial pixel 149 | 150 | if (remaining > 0.0f) 151 | { 152 | FastLED.leds()[GetFanPixelOrder(iPos++, order)] += ColorFraction(color, amtFirstPixel); 153 | remaining -= amtFirstPixel; 154 | } 155 | 156 | // Now draw any full pixels in the middle 157 | 158 | while (remaining > 1.0f) 159 | { 160 | FastLED.leds()[GetFanPixelOrder(iPos++, order)] += color; 161 | remaining--; 162 | } 163 | 164 | // Draw tail pixel, up to a single full pixel 165 | 166 | if (remaining > 0.0f) 167 | { 168 | FastLED.leds()[GetFanPixelOrder(iPos, order)] += ColorFraction(color, remaining); 169 | } 170 | } 171 | 172 | // DrawPixels 173 | // 174 | // Uses floating point math to draw a floating point number of pixels starting at a 175 | // floating point offset into the strip 176 | 177 | void DrawPixels(float fPos, float count, CRGB color) 178 | { 179 | // Calculate how much the first pixel will hold 180 | float availFirstPixel = 1.0f - (fPos - (long)(fPos)); 181 | float amtFirstPixel = min(availFirstPixel, count); 182 | float remaining = min(count, FastLED.size()-fPos); 183 | int iPos = fPos; 184 | 185 | // Blend (add) in the color of the first partial pixel 186 | 187 | if (remaining > 0.0f) 188 | { 189 | FastLED.leds()[iPos++] += ColorFraction(color, amtFirstPixel); 190 | remaining -= amtFirstPixel; 191 | } 192 | 193 | // Now draw any full pixels in the middle 194 | 195 | while (remaining > 1.0f) 196 | { 197 | FastLED.leds()[iPos++] += color; 198 | remaining--; 199 | } 200 | 201 | // Draw tail pixel, up to a single full pixel 202 | 203 | if (remaining > 0.0f) 204 | { 205 | FastLED.leds()[iPos] += ColorFraction(color, remaining); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /Fans/src/main.cpp: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: LED Episode 10 6 | // 7 | // Description: 8 | // 9 | // Draws sample effects on a an addressable strip using FastLED 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // Oct-05-2020 davepl Revised for Episode 07 13 | // Oct-11-2020 davepl Revised for Episode 08 14 | // Oct-16-2020 davepl Revised for Episode 09 15 | // Oct-23-2020 davepl Revised for Episode 10 16 | //--------------------------------------------------------------------------- 17 | 18 | #include // Arduino Framework 19 | #include // For text on the little on-chip OLED 20 | #define FASTLED_INTERNAL // Suppress build banner 21 | #include 22 | 23 | #define OLED_CLOCK 15 // Pins for the OLED display 24 | #define OLED_DATA 4 25 | #define OLED_RESET 16 26 | 27 | #define FAN_SIZE 16 // How many pixels per fan 28 | #define NUM_FANS 3 // Number of fans in the strans 29 | #define LED_FAN_OFFSET 4 // How far from 12 o'clock first pixel is 30 | #define NUM_LEDS (FAN_SIZE*NUM_FANS) 31 | #define LED_PIN 5 32 | 33 | CRGB g_LEDs[NUM_LEDS] = {0}; // Frame buffer for FastLED 34 | 35 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C g_OLED(U8G2_R2, OLED_RESET, OLED_CLOCK, OLED_DATA); 36 | int g_lineHeight = 0; 37 | int g_Brightness = 255; // 0-255 LED brightness scale 38 | int g_PowerLimit = 3000; // 900mW Power Limit 39 | 40 | #include "ledgfx.h" 41 | #include "comet.h" 42 | #include "marquee.h" 43 | #include "twinkle.h" 44 | #include "fire.h" 45 | 46 | 47 | void setup() 48 | { 49 | pinMode(LED_BUILTIN, OUTPUT); 50 | pinMode(LED_PIN, OUTPUT); 51 | 52 | Serial.begin(115200); 53 | while (!Serial) { } 54 | Serial.println("ESP32 Startup"); 55 | 56 | g_OLED.begin(); 57 | g_OLED.clear(); 58 | g_OLED.setFont(u8g2_font_profont15_tf); 59 | g_lineHeight = g_OLED.getFontAscent() - g_OLED.getFontDescent(); // Descent is a negative number so we add it to the total 60 | 61 | FastLED.addLeds(g_LEDs, NUM_LEDS); // Add our LED strip to the FastLED library 62 | FastLED.setBrightness(g_Brightness); 63 | set_max_power_indicator_LED(LED_BUILTIN); // Light the builtin LED if we power throttle 64 | FastLED.setMaxPowerInMilliWatts(g_PowerLimit); // Set the power limit, above which brightness will be throttled 65 | } 66 | 67 | void loop() 68 | { 69 | bool bLED = 0; 70 | 71 | while (true) 72 | { 73 | FastLED.clear(); 74 | 75 | /* 76 | // RGB Spinners 77 | float b = beat16(60) / 65535.0f * FAN_SIZE; 78 | DrawFanPixels(b, 1, CRGB::Red, Sequential, 0); 79 | DrawFanPixels(b, 1, CRGB::Green, Sequential, 1); 80 | DrawFanPixels(b, 1, CRGB::Blue, Sequential, 2); 81 | */ 82 | 83 | /* 84 | // Left to Right Cyan Wipe 85 | float b = beatsin16(60) / 65535.0f * FAN_SIZE; 86 | for (int iFan = 0; iFan < NUM_FANS; iFan++) 87 | DrawFanPixels(0, b, CRGB::Cyan, LeftRight, iFan); 88 | */ 89 | 90 | /* 91 | // Left to Right Cyan Wipe 92 | float b = beatsin16(60) / 65535.0f * FAN_SIZE; 93 | for (int iFan = 0; iFan < NUM_FANS; iFan++) 94 | DrawFanPixels(0, b, CRGB::Cyan, RightLeft, iFan); 95 | */ 96 | 97 | /* 98 | // Bottom up Green Wipe 99 | float b = beatsin16(60) / 65535.0f * NUM_LEDS; 100 | DrawFanPixels(0, b, CRGB::Green, BottomUp); 101 | */ 102 | 103 | /* 104 | // Bottom up Green Wipe 105 | float b = beatsin16(60) / 65535.0f * NUM_LEDS; 106 | DrawFanPixels(0, b, CRGB::Green, TopDown); 107 | */ 108 | 109 | /* 110 | // Simple Color Cycle 111 | static byte hue = 0; 112 | for (int i = 0; i < NUM_LEDS; i++) 113 | DrawFanPixels(i, 1, CHSV(hue, 255, 255)); 114 | hue += 4; 115 | */ 116 | 117 | /* 118 | // Sequential Rainbows 119 | static byte basehue = 0; 120 | byte hue = basehue; 121 | for (int i = 0; i < NUM_LEDS; i++) 122 | DrawFanPixels(i, 1, CHSV(hue+=16, 255, 255)); 123 | basehue += 4; 124 | */ 125 | 126 | /* 127 | // Vertical Rainbow Wipe 128 | static byte basehue = 0; 129 | byte hue = basehue; 130 | for (int i = 0; i < NUM_LEDS; i++) 131 | DrawFanPixels(i, 1, CHSV(hue+=8, 255, 255), BottomUp); 132 | basehue += 4; 133 | */ 134 | 135 | /* 136 | // Horizontal Rainbow Stripe 137 | static byte basehue = 0; 138 | byte hue = basehue; 139 | for (int i = 0; i < NUM_LEDS; i++) 140 | DrawFanPixels(i, 1, CHSV(hue+=16, 255, 255), LeftRight); 141 | basehue += 8; 142 | */ 143 | 144 | /* 145 | // Rainbow Stripe Palette Effect 146 | static CRGBPalette256 pal(RainbowStripeColors_p); 147 | static byte baseColor = 0; 148 | byte hue = baseColor; 149 | for (int i = 0; i < NUM_LEDS; i++) 150 | DrawFanPixels(i, 1, ColorFromPalette(pal, hue += 4), BottomUp); 151 | baseColor += 1; 152 | */ 153 | 154 | /* 155 | // vu-Style Meter 156 | int b = beatsin16(30) * NUM_LEDS / 65535L; 157 | static const CRGBPalette256 vuPaletteGreen = vu_gpGreen; 158 | for (int i = 0; i < b; i++) 159 | DrawFanPixels(i, 1, ColorFromPalette(vuPaletteGreen, (int)(255 * i / NUM_LEDS)), BottomUp); 160 | */ 161 | 162 | /* 163 | // Sequential Fire Fans 164 | static FireEffect fire(NUM_LEDS, 20, 100, 3, NUM_LEDS, true, false); 165 | fire.DrawFire(); 166 | */ 167 | 168 | /* 169 | // Bottom Up Fire Effect with extra sparking on first fan only 170 | static FireEffect fire(NUM_LEDS, 20, 140, 3, FAN_SIZE, true, false); 171 | fire.DrawFire(BottomUp); 172 | */ 173 | 174 | /* 175 | // LeftRight (Wide) Fire Effect with extra sparking on first fan only 176 | static FireEffect fire(NUM_LEDS, 20, 140, 3, FAN_SIZE, true, false); 177 | fire.DrawFire(LeftRight); 178 | for (int i = 0; i < FAN_SIZE; i++) // Copy end fan down onto others 179 | { 180 | g_LEDs[i] = g_LEDs[i + 2 * FAN_SIZE]; 181 | g_LEDs[i + FAN_SIZE] = g_LEDs[i + 2 * FAN_SIZE]; 182 | } 183 | */ 184 | 185 | int b = beatsin16(30) * NUM_LEDS / 65535L; 186 | static const CRGBPalette256 seawhawksPalette = vu_gpSeahawks; 187 | for (int i = 0; i < NUM_LEDS; i++) 188 | DrawFanPixels(i, 1, ColorFromPalette(seawhawksPalette, beat8(64) + (int)(255 * i / NUM_LEDS)), BottomUp); 189 | 190 | 191 | FastLED.show(g_Brightness); // Show and delay 192 | 193 | EVERY_N_MILLISECONDS(250) 194 | { 195 | g_OLED.clearBuffer(); 196 | g_OLED.setCursor(0, g_lineHeight); 197 | g_OLED.printf("FPS : %u", FastLED.getFPS()); 198 | g_OLED.setCursor(0, g_lineHeight * 2); 199 | g_OLED.printf("Power: %u mW", calculate_unscaled_power_mW(g_LEDs, 4)); 200 | g_OLED.setCursor(0, g_lineHeight * 3); 201 | g_OLED.printf("Brite: %d", calculate_max_brightness_for_power_mW(g_Brightness, g_PowerLimit)); 202 | g_OLED.sendBuffer(); 203 | } 204 | delay(33); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /LED Episode 10/include/fire.h: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2020 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: fire.h 6 | // 7 | // Description: 8 | // 9 | // LED Flame Effect 10 | // 11 | // History: Sep-28-2020 davepl Created 12 | // 13 | //--------------------------------------------------------------------------- 14 | 15 | #include 16 | #define FASTLED_INTERNAL 17 | #include 18 | 19 | #include "ledgfx.h" 20 | 21 | class FireEffectSmooth 22 | { 23 | protected: 24 | float * Temperatures; 25 | float LastDraw; // Last time we drew the flame 26 | 27 | const float IGNITION_KNOB = 50.0f; // Preference-based constant factor for ignition rate 28 | const float SPREADRATE_KNOB = 12.0f; // Preference-based constant for flame spread rate 29 | const float SPARKRATE_KNOB = 8.0f; // Preference-based constant for spark ignition rate 30 | 31 | public: 32 | bool Mirrored; // Should the flame be mirrored, drawn from both sides? 33 | bool Reversed; // Only applicable when not reversed, should it be reversed? 34 | float Cooling; // Pixel cooldown rate 35 | int Size; 36 | int SparkHeight; // Ignition zone for where new pixels start up 37 | float SparkProbability; // Probability of a spark in each ignition zone pixel 38 | float SpreadRate; // Rate at which fire spreads pixel to pixel 39 | 40 | FireEffectSmooth(int size, bool mirrored = true, bool reversed = false, int sparkHeight = 0, float sparkProbability = 1.0, float cooling = 1.0, float spreadRate = 1.0) 41 | { 42 | Mirrored = mirrored; 43 | if (mirrored) 44 | size /= 2; 45 | 46 | Reversed = reversed; 47 | Cooling = cooling; 48 | Size = size; // 49 | SparkHeight = sparkHeight; // 50 | SparkProbability = sparkProbability * SPARKRATE_KNOB / SparkHeight; // Chance that each LED cell will ignite when tested 51 | Temperatures = new float[Size]; // Array of temperatures, one per LED 52 | SpreadRate = spreadRate * SPREADRATE_KNOB; // How fast the flame spreads per second 53 | LastDraw = UnixTime(); // Start of time 54 | } 55 | 56 | virtual ~FireEffectSmooth() // Because we have a virtual function, destructor is virtual as well 57 | { 58 | delete [] Temperatures; 59 | } 60 | 61 | void DrawFire() 62 | { 63 | FastLED.clear(); 64 | 65 | float elapsedSeconds = UnixTime() - LastDraw; 66 | float cooldown = 1.0f * RandomFloat() * Cooling * elapsedSeconds; 67 | LastDraw = UnixTime(); 68 | 69 | for (int i = 0; i < Size; i++) 70 | { 71 | Temperatures[i] = max(0.0f, Temperatures[i] - cooldown); // Cool cell by cooldown amount, but don't go below zero 72 | 73 | int neighborIndex = (i == 0) ? Size - 1 : i - 1; // Index of cell to our left, wrapping around to front 74 | float spreadAmount = min(0.25f, Temperatures[neighborIndex]) * SpreadRate * elapsedSeconds; 75 | spreadAmount = min(Temperatures[neighborIndex], spreadAmount); 76 | Temperatures[i] += spreadAmount; // Exchange 'spreadAmount' of heat between cells 77 | Temperatures[neighborIndex] -= spreadAmount; 78 | 79 | // Check to see if this cell ignites a new spark 80 | if (i <= SparkHeight && RandomFloat() < SparkProbability * elapsedSeconds) 81 | { 82 | //Temperatures[i] = Temperatures[i] + RandomFloat() * 30 * elapsedSeconds; 83 | Temperatures[i] = 2.0; // min(1.0f, (Temperatures[i] + RandomFloat() * 30 * elapsedSeconds)); 84 | //printf("Spark at %d: %f", i, Temperatures[i]); 85 | } 86 | } 87 | for (int i = 0; i < Size; i++) 88 | { 89 | FastLED.leds()[i] = HeatColor(240 * min(1.0f, Temperatures[i])); 90 | } 91 | } 92 | }; 93 | 94 | class ClassicFireEffect 95 | { 96 | protected: 97 | int Size; 98 | int Cooling; 99 | int Sparks; 100 | int SparkHeight; 101 | int Sparking; 102 | bool bReversed; 103 | bool bMirrored; 104 | 105 | byte * heat; 106 | 107 | // When diffusing the fire upwards, these control how much to blend in from the cells below (ie: downward neighbors) 108 | // You can tune these coefficients to control how quickly and smoothly the fire spreads. 109 | 110 | static const byte BlendSelf = 2; 111 | static const byte BlendNeighbor1 = 3; 112 | static const byte BlendNeighbor2 = 2; 113 | static const byte BlendNeighbor3 = 1; 114 | static const byte BlendTotal = (BlendSelf + BlendNeighbor1 + BlendNeighbor2 + BlendNeighbor3); 115 | 116 | public: 117 | 118 | // Lower sparking -> more flicker. Higher sparking -> more consistent flame 119 | 120 | ClassicFireEffect(int size, int cooling = 80, int sparking = 50, int sparks = 3, int sparkHeight = 4, bool breversed = true, bool bmirrored = true) 121 | : Size(size), 122 | Cooling(cooling), 123 | Sparks(sparks), 124 | SparkHeight(sparkHeight), 125 | Sparking(sparking), 126 | bReversed(breversed), 127 | bMirrored(bmirrored) 128 | { 129 | if (bMirrored) 130 | Size = Size / 2; 131 | 132 | heat = new byte[size] { 0 }; 133 | } 134 | 135 | virtual ~ClassicFireEffect() 136 | { 137 | delete [] heat; 138 | } 139 | 140 | virtual void DrawFire() 141 | { 142 | // First cool each cell by a little bit 143 | for (int i = 0; i < Size; i++) 144 | heat[i] = max(0L, heat[i] - random(0, ((Cooling * 10) / Size) + 2)); 145 | 146 | // Next drift heat up and diffuse it a little but 147 | for (int i = 0; i < Size; i++) 148 | heat[i] = (heat[i] * BlendSelf + 149 | heat[(i + 1) % Size] * BlendNeighbor1 + 150 | heat[(i + 2) % Size] * BlendNeighbor2 + 151 | heat[(i + 3) % Size] * BlendNeighbor3) 152 | / BlendTotal; 153 | 154 | // Randomly ignite new sparks down in the flame kernel 155 | for (int i = 0; i < Sparks; i++) 156 | { 157 | if (random(255) < Sparking) 158 | { 159 | int y = Size - 1 - random(SparkHeight); 160 | heat[y] = heat[y] + random(160, 255); // This randomly rolls over sometimes of course, and that's essential to the effect 161 | } 162 | } 163 | 164 | // Finally convert heat to a color 165 | for (int i = 0; i < Size; i++) 166 | { 167 | CRGB color = HeatColor(heat[i]); 168 | int j = bReversed ? (Size - 1 - i) : i; 169 | DrawPixels(j, 1, color); 170 | if (bMirrored) 171 | { 172 | int j2 = !bReversed ? (2 * Size - 1 - i) : Size + i; 173 | DrawPixels(j2, 1, color); 174 | } 175 | } 176 | } 177 | }; 178 | -------------------------------------------------------------------------------- /LED Episode 11/src/main.cpp: -------------------------------------------------------------------------------- 1 | //+-------------------------------------------------------------------------- 2 | // 3 | // NightDriver - (c) 2018 Dave Plummer. All Rights Reserved. 4 | // 5 | // File: LED Episode 11 6 | // 7 | // Description: 8 | // 9 | // Draws sample effects on a an addressable strip using FastLED 10 | // 11 | // History: Sep-15-2020 davepl Created 12 | // Oct-05-2020 davepl Revised for Episode 07 13 | // Oct-11-2020 davepl Revised for Episode 08 14 | // Oct-16-2020 davepl Revised for Episode 09 15 | // Oct-23-2020 davepl Revised for Episode 10 16 | //--------------------------------------------------------------------------- 17 | 18 | #include // Arduino Framework 19 | #include // For text on the little on-chip OLED 20 | #define FASTLED_INTERNAL // Suppress build banner 21 | #include 22 | 23 | #define OLED_CLOCK 15 // Pins for the OLED display 24 | #define OLED_DATA 4 25 | #define OLED_RESET 16 26 | 27 | #define FAN_SIZE 16 // Number of LEDs in each fan 28 | #define NUM_FANS 3 // Number of Fans 29 | #define LED_FAN_OFFSET 4 // How far from bottom first pixel is 30 | #define NUM_LEDS 48 // FastLED definitions 31 | #define LED_PIN 5 32 | 33 | CRGB g_LEDs[NUM_LEDS] = {0}; // Frame buffer for FastLED 34 | 35 | U8G2_SSD1306_128X64_NONAME_F_HW_I2C g_OLED(U8G2_R2, OLED_RESET, OLED_CLOCK, OLED_DATA); 36 | int g_lineHeight = 0; 37 | int g_Brightness = 255; // 0-255 LED brightness scale 38 | int g_PowerLimit = 3000; // 900mW Power Limit 39 | 40 | #include "ledgfx.h" 41 | #include "comet.h" 42 | #include "marquee.h" 43 | #include "twinkle.h" 44 | #include "fire.h" 45 | 46 | void setup() 47 | { 48 | pinMode(LED_BUILTIN, OUTPUT); 49 | pinMode(LED_PIN, OUTPUT); 50 | 51 | Serial.begin(115200); 52 | while (!Serial) { } 53 | Serial.println("ESP32 Startup"); 54 | 55 | g_OLED.begin(); 56 | g_OLED.clear(); 57 | g_OLED.setFont(u8g2_font_profont15_tf); 58 | g_lineHeight = g_OLED.getFontAscent() - g_OLED.getFontDescent(); // Descent is a negative number so we add it to the total 59 | 60 | FastLED.addLeds(g_LEDs, NUM_LEDS); // Add our LED strip to the FastLED library 61 | FastLED.setBrightness(g_Brightness); 62 | set_max_power_indicator_LED(LED_BUILTIN); // Light the builtin LED if we power throttle 63 | FastLED.setMaxPowerInMilliWatts(g_PowerLimit); // Set the power limit, above which brightness will be throttled 64 | } 65 | 66 | void DrawMarqueeComparison() 67 | { 68 | static float scroll = 0.0f; 69 | scroll += 0.1f; 70 | if (scroll > 5.0) 71 | scroll -= 5.0; 72 | 73 | for (float i = scroll; i < NUM_LEDS/2 -1; i+= 5) 74 | { 75 | DrawPixels(i, 3, CRGB::Green); 76 | DrawPixels(NUM_LEDS-1-(int)i, 3, CRGB::Red); 77 | } 78 | } 79 | 80 | void loop() 81 | { 82 | bool bLED = 0; 83 | 84 | while (true) 85 | { 86 | FastLED.clear(); 87 | 88 | /* 89 | // RGB Spinners 90 | float b = beat16(60) / 65535.0f * FAN_SIZE; 91 | DrawFanPixels(b, 1, CRGB::Red, Sequential, 0); 92 | DrawFanPixels(b, 1, CRGB::Green, Sequential, 1); 93 | DrawFanPixels(b, 1, CRGB::Blue, Sequential, 2); 94 | */ 95 | 96 | /* 97 | // Left to Right Cyan Wipe 98 | float b = beatsin16(60) / 65535.0f * FAN_SIZE; 99 | for (int iFan = 0; iFan < NUM_FANS; iFan++) 100 | DrawFanPixels(0, b, CRGB::Cyan, LeftRight, iFan); 101 | */ 102 | 103 | /* Right to Left Cyan Wipe 104 | float b = beatsin16(60) / 65535.0f * FAN_SIZE; 105 | for (int iFan = 0; iFan < NUM_FANS; iFan++) 106 | DrawFanPixels(0, b, CRGB::Cyan, RightLeft, iFan); 107 | */ 108 | 109 | /* 110 | // Bottom Up Green Wipe 111 | float b = beatsin16(60) / 65535.0f * NUM_LEDS; 112 | DrawFanPixels(0, b, CRGB::Green, BottomUp); 113 | */ 114 | 115 | /* 116 | // Top Down Green Wipe 117 | float b = beatsin16(60) / 65535.0f * NUM_LEDS; 118 | DrawFanPixels(0, b, CRGB::Green, TopDown); 119 | */ 120 | 121 | /* 122 | // Simple Color Cycle 123 | static byte hue = 0; 124 | for (int i = 0; i < NUM_LEDS; i++) 125 | DrawFanPixels(i, 1, CHSV(hue, 255, 255)); 126 | hue += 4; 127 | */ 128 | 129 | /* 130 | // Sequential Color Rainbows 131 | static byte basehue = 0; 132 | byte hue = basehue; 133 | basehue += 4; 134 | for (int i = 0; i < NUM_LEDS; i++) 135 | DrawFanPixels(i, 1, CHSV(hue+=16, 255, 255)); 136 | basehue += 4; 137 | */ 138 | 139 | /* 140 | // Vertical Rainbow Wipe 141 | static byte basehue = 0; 142 | byte hue = basehue; 143 | basehue += 8; 144 | for (int i = 0; i < NUM_LEDS; i++) 145 | DrawFanPixels(i, 1, CHSV(hue+=16, 255, 255), LeftRight); 146 | */ 147 | 148 | /* 149 | static byte basehue = 0; 150 | byte hue = basehue; 151 | basehue += 8; 152 | for (int i = 0; i < NUM_LEDS; i++) 153 | DrawFanPixels(i, 1, CHSV(hue+=16, 255, 255), BottomUp); 154 | */ 155 | 156 | /* 157 | // Rainbow Strip Palette Effect 158 | static CRGBPalette256 pal(RainbowStripeColors_p); 159 | static byte baseColor = 0; 160 | byte hue = baseColor; 161 | for (int i = 0; i < NUM_LEDS; i++) 162 | DrawFanPixels(i, 1, ColorFromPalette(pal, hue += 4), BottomUp); 163 | baseColor += 1; 164 | */ 165 | 166 | /* 167 | // vu-style Meter bar 168 | int b = beatsin16(30) * NUM_LEDS / 65535L; 169 | static const CRGBPalette256 vuPaletteGreen = vu_gpGreen; 170 | for (int i = 0; i < b; i++) 171 | DrawFanPixels(i, 1, ColorFromPalette(vuPaletteGreen, (int)(255 * i / NUM_LEDS)), BottomUp); 172 | */ 173 | 174 | /* 175 | // Sequential Fire Fans 176 | static FireEffect fire(NUM_LEDS, 20, 100, 3, NUM_LEDS, true, false); 177 | fire.DrawFire(); 178 | */ 179 | 180 | /* 181 | // Bottom Up Fire Effect with extra sparking on first fan only 182 | static FireEffect fire(NUM_LEDS, 20, 140, 3, FAN_SIZE, true, false); 183 | fire.DrawFire(BottomUp); 184 | */ 185 | 186 | // LeftRight (Wide Style) Fire Effect with extra sparking on first fan only 187 | 188 | /* 189 | static FireEffect fire(NUM_LEDS, 20, 140, 3, FAN_SIZE, true, false); 190 | fire.DrawFire(LeftRight); 191 | for (int i = 0; i < FAN_SIZE; i++) 192 | { 193 | g_LEDs[i] = g_LEDs[i + 2 * FAN_SIZE]; 194 | g_LEDs[i + FAN_SIZE] = g_LEDs[i + 2 * FAN_SIZE]; 195 | } 196 | */ 197 | 198 | int b = beatsin16(30) * NUM_LEDS / 65535L; 199 | static const CRGBPalette256 seahawksPalette = gpSeahawks; 200 | for (int i = 0; i < NUM_LEDS; i++) 201 | DrawFanPixels(i, 1, ColorFromPalette(seahawksPalette, beat8(64) + (int)(255 * i / NUM_LEDS)), BottomUp); 202 | 203 | 204 | FastLED.show(g_Brightness); // Show and delay 205 | 206 | EVERY_N_MILLISECONDS(250) 207 | { 208 | g_OLED.clearBuffer(); 209 | g_OLED.setCursor(0, g_lineHeight); 210 | g_OLED.printf("FPS : %u", FastLED.getFPS()); 211 | g_OLED.setCursor(0, g_lineHeight * 2); 212 | g_OLED.printf("Power: %u mW", calculate_unscaled_power_mW(g_LEDs, 4)); 213 | g_OLED.setCursor(0, g_lineHeight * 3); 214 | g_OLED.printf("Brite: %d", calculate_max_brightness_for_power_mW(g_Brightness, g_PowerLimit)); 215 | g_OLED.sendBuffer(); 216 | } 217 | delay(33); 218 | } 219 | } 220 | --------------------------------------------------------------------------------