In our previous article, we got a simple spinning effect with the provided sketch. It was easy. We have already mentioned that controlling NeoPixel with PWM can be done both with Arduino and Raspberry Pi. When can control the speed of the spin with a potentiometer, we can use any PWM signal to control the speed.
The circuit diagram will be like this one:
The GND of the NeoPixel ring will be connected to the GND of Arduino.
The Data IN of the NeoPixel ring will be connected to GPIO number 6 of Arduino.
The VCc or Vin of the NeoPixel ring will be connected to 3.3v pin of Arduino.
The GND of the potentiometer will be connected to GND of Arduino.
The Vcc of the potentiometer will be connected to 5v of Arduino.
The middle pin of the potentiometer will be connected to A3 pin of Arduino.
---
The result will be like this simulation on TinkerCAD:
This is the main .ino
file (or sketch) for the above result:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | /** Copyright (C) 2018 Robert Ulbricht Modified by Abhishek Ghosh License: GNU General Public License version 3 */ #include <Adafruit_NeoPixel.h> #include "hsv.h" // data pin #define PIN 6 // led count #define CNT 24 // max Hue #define MAXHUE 256*6 int position = 0; int pot_speed; // A3 char output[128]; unsigned long next_time = 0; Adafruit_NeoPixel strip = Adafruit_NeoPixel(CNT, PIN, NEO_GRB + NEO_KHZ800); void setup() { Serial.begin(115200); strip.begin(); } void loop() { // analog pot_speed = map(aRead(A3), 0, 1023, 1, 500); unsigned long m = millis(); if (m - next_time > 1000L) { next_time = m; sprintf(output, "spd: %d", pot_speed); Serial.println(output); } // value - 0-255 for (int i = 0; i < CNT; i++) strip.setPixelColor((i + position) % CNT, getPixelColorHsv(i, 0, 255, strip.gamma8(i * (255 / CNT)))); strip.show(); position++; position %= CNT; delay(pot_speed); } int aRead(int anl) { long tmp = 0, t; // discard first X measurements for (int i = 0; i < 1; i++) analogRead(anl); for (int i = 0; i < 4; i++) { t = analogRead(anl); tmp += t; } return tmp / 4; } |
You need to include the below header file with the name hsv.h
in Arduino IDE:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | uint32_t getPixelColorHsv( uint16_t n, uint16_t h, uint8_t s, uint8_t v) { uint8_t r, g, b; if (!s) { // Monochromatic, all components are V r = g = b = v; } else { uint8_t sextant = h >> 8; if (sextant > 5) sextant = 5; // Limit hue sextants to defined space g = v; // Top level // Perform actual calculations /* Bottom level: --> (v * (255 - s) + error_corr + 1) / 256 */ uint16_t ww; // Intermediate result ww = v * (uint8_t)(~s); ww += 1; // Error correction ww += ww >> 8; // Error correction b = ww >> 8; uint8_t h_fraction = h & 0xff; // Position within sextant uint32_t d; // Intermediate result if (!(sextant & 1)) { // r = ...slope_up... // --> r = (v * ((255 << 8) - s * (256 - h)) + error_corr1 + error_corr2) / 65536 d = v * (uint32_t)(0xff00 - (uint16_t)(s * (256 - h_fraction))); d += d >> 8; // Error correction d += v; // Error correction r = d >> 16; } else { // r = ...slope_down... // --> r = (v * ((255 << 8) - s * h) + error_corr1 + error_corr2) / 65536 d = v * (uint32_t)(0xff00 - (uint16_t)(s * h_fraction)); d += d >> 8; // Error correction d += v; // Error correction r = d >> 16; } // Swap RGB values according to sextant. This is done in reverse order with // respect to the original because the swaps are done after the // assignments. if (!(sextant & 6)) { if (!(sextant & 1)) { uint8_t tmp = r; r = g; g = tmp; } } else { if (sextant & 1) { uint8_t tmp = r; r = g; g = tmp; } } if (sextant & 4) { uint8_t tmp = g; g = b; b = tmp; } if (sextant & 2) { uint8_t tmp = r; r = b; b = tmp; } } return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } |
As for TinkerCAD, I had to make it a single .ino
file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | /** Modified by Abhishek Ghosh, 2023 Distributed with a GNU GPL 3.0 license Copyright (C) 2018 Robert Ulbricht https://www.arduinoslovakia.eu This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ uint32_t getPixelColorHsv( uint16_t n, uint16_t h, uint8_t s, uint8_t v) { uint8_t r, g, b; if (!s) { // Monochromatic, all components are V r = g = b = v; } else { uint8_t sextant = h >> 8; if (sextant > 5) sextant = 5; // Limit hue sextants to defined space g = v; // Top level // Perform actual calculations /* Bottom level: --> (v * (255 - s) + error_corr + 1) / 256 */ uint16_t ww; // Intermediate result ww = v * (uint8_t)(~s); ww += 1; // Error correction ww += ww >> 8; // Error correction b = ww >> 8; uint8_t h_fraction = h & 0xff; // Position within sextant uint32_t d; // Intermediate result if (!(sextant & 1)) { // r = ...slope_up... // --> r = (v * ((255 << 8) - s * (256 - h)) + error_corr1 + error_corr2) / 65536 d = v * (uint32_t)(0xff00 - (uint16_t)(s * (256 - h_fraction))); d += d >> 8; // Error correction d += v; // Error correction r = d >> 16; } else { // r = ...slope_down... // --> r = (v * ((255 << 8) - s * h) + error_corr1 + error_corr2) / 65536 d = v * (uint32_t)(0xff00 - (uint16_t)(s * h_fraction)); d += d >> 8; // Error correction d += v; // Error correction r = d >> 16; } // Swap RGB values according to sextant. This is done in reverse order with // respect to the original because the swaps are done after the // assignments. if (!(sextant & 6)) { if (!(sextant & 1)) { uint8_t tmp = r; r = g; g = tmp; } } else { if (sextant & 1) { uint8_t tmp = r; r = g; g = tmp; } } if (sextant & 4) { uint8_t tmp = g; g = b; b = tmp; } if (sextant & 2) { uint8_t tmp = r; r = b; b = tmp; } } return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } #include <Adafruit_NeoPixel.h> // data pin #define PIN 6 // led count #define CNT 24 // max Hue #define MAXHUE 256*6 int position = 0; int pot_speed; // A3 char output[128]; unsigned long next_time = 0; Adafruit_NeoPixel strip = Adafruit_NeoPixel(CNT, PIN, NEO_GRB + NEO_KHZ800); void setup() { Serial.begin(115200); strip.begin(); } void loop() { // analog pot_speed = map(aRead(A3), 0, 1023, 1, 500); unsigned long m = millis(); if (m - next_time > 1000L) { next_time = m; sprintf(output, "spd: %d", pot_speed); Serial.println(output); } // value - 0-255 for (int i = 0; i < CNT; i++) strip.setPixelColor((i + position) % CNT, getPixelColorHsv(i, 0, 255, strip.gamma8(i * (255 / CNT)))); strip.show(); position++; position %= CNT; delay(pot_speed); } int aRead(int anl) { long tmp = 0, t; // discard first X measurements for (int i = 0; i < 1; i++) analogRead(anl); for (int i = 0; i < 4; i++) { t = analogRead(anl); tmp += t; } return tmp / 4; } |
Like the previous article, the major part of the code is from Robo Ulbricht’s repo on GitHub. I have changed the number of the potentiometer, the color to show and its function.