Updated Pixel() class to use more streamlined methods implemented in Dot() class

Pixel() and Dot() classes are now complete.  Tested DotStar RGB, NeoPixel RGB, and NeoPixel RGBW, all running at same time on a single ESP32.

Next up: Must update Pixel Example as well as Holiday Lights Project
To Do: Add documentation page for Pixel() and Dot()
This commit is contained in:
Gregg 2022-02-05 12:35:01 -06:00
parent a21cc0679d
commit d0a13e5417
3 changed files with 100 additions and 78 deletions

View File

@ -9,13 +9,16 @@
// Single-Wire RGB/RGBW NeoPixels //
////////////////////////////////////////////
Pixel::Pixel(int pin, pixel_type_t pType){
Pixel::Pixel(int pin, boolean isRGBW){
rf=new RFControl(pin,false,false); // set clock to 1/80 usec, no default driver
if(!*rf)
return;
this->pType=pType;
if(isRGBW)
this->lastBit=0;
else
this->lastBit=8;
setTiming(0.32, 0.88, 0.64, 0.56, 80.0); // set default timing parameters (suitable for most SK68 and WS28 RGB pixels)
@ -43,32 +46,13 @@ void Pixel::setTiming(float high0, float low0, float high1, float low1, uint32_t
///////////////////
void Pixel::setRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint32_t nPixels){
if(!*rf || nPixels==0)
return;
uint32_t data=getColorRGB(r,g,b,w);
setColors(&data,nPixels,false);
}
///////////////////
void Pixel::setHSV(float h, float s, float v, double w, uint32_t nPixels){
float r,g,b;
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
setRGB(r*255,g*255,b*255,w*2.555,nPixels);
}
///////////////////
void Pixel::setColors(const uint32_t *data, uint32_t nPixels, boolean multiColor){
void Pixel::set(Color *c, int nPixels, boolean multiColor){
if(!*rf || nPixels==0)
return;
status.nPixels=nPixels;
status.data=data;
status.color=c;
status.iMem=0;
status.iBit=32;
status.started=true;
@ -86,17 +70,21 @@ void Pixel::setColors(const uint32_t *data, uint32_t nPixels, boolean multiColor
///////////////////
uint32_t Pixel::getColorRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w){
// return(g<<16 | r<<8 | b);
return(g<<24 | r<<16 | b<<8 | w);
Pixel::Color Pixel::RGB(uint8_t red, uint8_t green, uint8_t blue, uint8_t white){
Color x;
x.red=red;
x.green=green;
x.blue=blue;
x.white=white;
return(x);
}
///////////////////
uint32_t Pixel::getColorHSV(float h, float s, float v, double w){
Pixel::Color Pixel::HSV(float h, float s, float v, double w){
float r,g,b;
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
return(getColorRGB(r*255,g*255,b*255,w*2.555));
return(RGB(r*255,g*255,b*255,w*2.555));
}
///////////////////
@ -117,11 +105,11 @@ void IRAM_ATTR Pixel::loadData(void *arg){
}
for(int i=0;i<8;i++)
RMTMEM.chan[status.px->rf->getChannel()].data32[status.iMem++].val=status.px->pattern[(*status.data>>(--status.iBit))&1];
RMTMEM.chan[status.px->rf->getChannel()].data32[status.iMem++].val=status.px->pattern[(status.color->val>>(--status.iBit))&1];
if(status.iBit==status.px->pType){
if(status.iBit==status.px->lastBit){
status.iBit=32;
status.data+=status.multiColor;
status.color+=status.multiColor;
status.nPixels--;
}
@ -190,8 +178,7 @@ void Dot::set(Color *c, int nPixels, boolean multiColor){
*clockSetReg=clockMask;
*clockClearReg=clockMask;
}
if(multiColor)
c++;
c+=multiColor;
}
*dataClearReg=dataMask; // send all zeros
@ -213,13 +200,12 @@ Dot::Color Dot::RGB(uint8_t red, uint8_t green, uint8_t blue, uint8_t drive){
return(x);
}
///////////////////
Dot::Color Dot::HSV(float h, float s, float v, float level){
Dot::Color Dot::HSV(float h, float s, float v, double level){
float r,g,b;
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
return(RGB(r*255,g*255,b*255,level/100*31.5));
return(RGB(r*255,g*255,b*255,level*0.315));
}
////////////////////////////////////////////

View File

@ -14,16 +14,23 @@
class Pixel {
public:
enum pixel_type_t {
RGB=8,
RGBW=0
};
public:
struct Color {
union{
struct {
uint8_t white:8;
uint8_t blue:8;
uint8_t red:8;
uint8_t green:8;
};
uint32_t val;
};
};
private:
struct pixel_status_t {
int nPixels;
const uint32_t *data;
Color *color;
int iBit;
int iMem;
boolean started;
@ -36,7 +43,7 @@ class Pixel {
uint32_t resetTime; // minimum time (in usec) between pulse trains
uint32_t txEndMask; // mask for end-of-transmission interrupt
uint32_t txThrMask; // mask for threshold interrupt
pixel_type_t pType; // type of Pixel (RGB or RGBW)
uint32_t lastBit; // 0=RGBW; 8=RGB
const int memSize=sizeof(RMTMEM.chan[0].data32)/4; // determine size (in pulses) of one channel
@ -44,19 +51,15 @@ class Pixel {
volatile static pixel_status_t status; // storage for volatile information modified in interupt handler
public:
Pixel(int pin, pixel_type_t pType=RGB); // creates addressable single-wire RGB or RGBW LED on pin (such as the SK68 or WS28)
void setTiming(float high0, float low0, float high1, float low1, uint32_t lowReset); // changes default timings for bit pulse - note parameters are in MICROSECONDS
void setRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w=0, uint32_t nPixels=1); // sets color of nPixels to RGB(W) values (0-255)
void setHSV(float h, float s, float v, double w=0, uint32_t nPixels=1); // sets color of nPixels to HSV(W) values where h=[0,360], s/v/w=[0,100]
void setColors(const uint32_t *data, uint32_t nPixels, bool multiColor=true); // sets colors of nPixels from array of colors stored in data
Pixel(int pin, boolean isRGBW=false); // creates addressable single-wire RGB (false) or RGBW (true) LED connected to pin (such as the SK68 or WS28)
static Color RGB(uint8_t red, uint8_t green, uint8_t blue, uint8_t white=0); // returns Color based on provided RGB(W) values where r/g/b/w=[0-255]
static Color HSV(float h, float s, float v, double w=0); // returns Color based on provided HSV(W) values where h=[0,360] and s/v/w=[0,100]
void set(Color *c, int nPixels, boolean multiColor=true); // sets colors of nPixels based on array of Colors c; setting multiColor to false repeats Color in c[0] for all nPixels
void set(Color c, int nPixels=1){set(&c,nPixels,false);} // sets color of nPixels to be equal to specific Color c
int getPin(){return(rf->getPin());} // returns pixel pin if valid, else returns -1
static uint32_t getColorRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w=0); // return pixel Color from RGB(W) values
static uint32_t getColorHSV(float h, float s, float v, double w=0); // return pixel Color from HSV(W) values
void setTiming(float high0, float low0, float high1, float low1, uint32_t lowReset); // changes default timings for bit pulse - note parameters are in MICROSECONDS
operator bool(){ // override boolean operator to return true/false if creation succeeded/failed
return(*rf);
}
@ -91,11 +94,11 @@ class Dot {
volatile uint32_t *clockClearReg;
public:
Dot(uint8_t dataPin, uint8_t clockPin);
void set(Color c, int nPixels=1){set(&c,nPixels,false);}
void set (Color *c, int nPixels, boolean multiColor=true);
static Color RGB(uint8_t red, uint8_t green, uint8_t blue, uint8_t drive=31);
static Color HSV(float h, float s, float v, float level=100);
Dot(uint8_t dataPin, uint8_t clockPin); // creates addressable two-wire RGB LED connected to dataPin and clockPin (such as the DotStar SK9822 or APA102)
static Color RGB(uint8_t red, uint8_t green, uint8_t blue, uint8_t drive=31); // returns Color based on provided RGB values where r/g/b=[0-255] and current-limiting drive=[0,31]
static Color HSV(float h, float s, float v, double level=100); // returns Color based on provided HSV values where h=[0,360], s/v=[0,100], and current-limiting drive=[0,100]
void set(Color *c, int nPixels, boolean multiColor=true); // sets colors of nPixels based on array of Colors c; setting multiColor to false repeats Color in c[0] for all nPixels
void set(Color c, int nPixels=1){set(&c,nPixels,false);} // sets color of nPixels to be equal to specific Color c
};
////////////////////////////////////////////

View File

@ -8,9 +8,11 @@ struct Effect1 {
int H=0;
uint32_t alarmTime=0;
uint32_t speed;
uint8_t nPixels;
Effect1(Pixel *px, uint32_t speed=20){
Effect1(Pixel *px, uint32_t speed, uint8_t nPixels){
this->px=px;
this->nPixels=nPixels;
this->speed=speed;
}
@ -18,9 +20,9 @@ struct Effect1 {
if(millis()<alarmTime)
return;
px->setHSV(H,100,100,0,60);
px->set(px->HSV(H,100,10),nPixels);
H=(H+1)%360;
alarmTime=millis()+speed;
}
};
@ -31,12 +33,14 @@ struct Effect2 {
int phase=0;
int dir=1;
int H=0;
uint32_t x[60];
Pixel::Color x[60];
uint32_t alarmTime=0;
uint32_t speed;
uint8_t nPixels;
Effect2(Pixel *px, uint32_t speed=20){
Effect2(Pixel *px, uint32_t speed, uint8_t nPixels){
this->px=px;
this->nPixels=nPixels;
this->speed=speed;
}
@ -44,23 +48,23 @@ struct Effect2 {
if(millis()<alarmTime)
return;
for(int i=0;i<60;i++){
for(int i=0;i<nPixels;i++){
if(i==phase)
x[i]=px->getColorHSV(H,100,100);
else if(i==59-phase)
x[i]=px->getColorHSV(H+180,100,100);
x[i]=px->HSV(H,100,100);
else if(i==nPixels-1-phase)
x[i]=px->HSV(H+180,100,100);
else
x[i]=0;
x[i]=Pixel::HSV(0,0,0);
}
px->setColors(x,60);
phase=(phase+dir)%60;
px->set(x,nPixels);
phase=(phase+dir)%nPixels;
if(phase==0){
dir=1;
H=(H+10)%360;
}
else if(phase==59){
else if(phase==nPixels-1){
dir=-1;
H=(H+10)%360;
}
@ -69,6 +73,31 @@ struct Effect2 {
}
};
struct Effect3 {
Dot *dot;
int H=0;
uint32_t alarmTime=0;
uint32_t speed;
uint8_t nPixels;
Effect3(Dot *dot, uint32_t speed, uint8_t nPixels){
this->dot=dot;
this->nPixels=nPixels;
this->speed=speed;
}
void update(){
if(millis()<alarmTime)
return;
dot->set(Dot::HSV(H,100,100),nPixels);
H=(H+1)%360;
alarmTime=millis()+speed;
}
};
#if defined(CONFIG_IDF_TARGET_ESP32C3)
#define PIXEL_PIN_1 8
@ -83,14 +112,17 @@ struct Effect2 {
#define PIXEL_PIN_1 23
#define PIXEL_PIN_2 21
Dot dot(32,5);
#endif
Pixel px1(PIXEL_PIN_1,Pixel::RGBW);
Pixel px2(PIXEL_PIN_2,Pixel::RGBW);
Pixel px1(PIXEL_PIN_1);
Pixel px2(PIXEL_PIN_2,true);
Effect1 effect1(&px1,20);
Effect2 effect2(&px2,20);
Effect1 effect1(&px1,20,8);
Effect2 effect2(&px2,20,60);
Effect3 effect3(&dot,20,30);
void setup() {
@ -105,4 +137,5 @@ void setup() {
void loop(){
effect1.update();
effect2.update();
effect3.update();
}