forked from Makuna/NeoPixelBus
Seven segment (#293)
This commit is contained in:
36
examples/sevensegment/NeoSegmentBus/NeoSegmentBus.ino
Normal file
36
examples/sevensegment/NeoSegmentBus/NeoSegmentBus.ino
Normal file
@@ -0,0 +1,36 @@
|
||||
// NeoSegmentBus
|
||||
// This example will demonstrate using the NeoSegmentBus which provides support for a
|
||||
// seven segment LED digit driven by three WS2811; connected in series with other digits
|
||||
//
|
||||
// See https://shop.idlehandsdev.com/products/addressable-7-segment-display for a hardware example
|
||||
//
|
||||
// This example will print the string "3.14" and then rotate it through the available digits
|
||||
//
|
||||
|
||||
#include <NeoPixelSegmentBus.h>
|
||||
|
||||
const uint16_t DigitCount = 4; // Max Digits, not segments, not pixels
|
||||
const uint8_t BusPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
|
||||
|
||||
#define brightness 128
|
||||
|
||||
NeoPixelSegmentBus<SevenSegmentFeature, Neo800KbpsMethod> strip(DigitCount, BusPin);
|
||||
|
||||
void setup()
|
||||
{
|
||||
strip.Begin();
|
||||
strip.Show(); // clears all digits by default
|
||||
|
||||
delay(500);
|
||||
strip.SetString(0, "3.14", brightness);
|
||||
strip.Show();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(2000);
|
||||
|
||||
strip.RotateLeft(1);
|
||||
strip.Show();
|
||||
}
|
||||
|
144
examples/sevensegment/NeoSegmentFade/NeoSegmentFade.ino
Normal file
144
examples/sevensegment/NeoSegmentFade/NeoSegmentFade.ino
Normal file
@@ -0,0 +1,144 @@
|
||||
// NeoSegmentBus
|
||||
// This example will demonstrate using the NeoSegmentBus which provides support for a
|
||||
// seven segment LED digit driven by three WS2811; connected in series with other digits
|
||||
//
|
||||
// See https://shop.idlehandsdev.com/products/addressable-7-segment-display for a hardware example
|
||||
//
|
||||
// This example will print current seconds since start of the Arduino
|
||||
// with a digit animating a circling path for each second
|
||||
//
|
||||
|
||||
#include <NeoPixelSegmentBus.h>
|
||||
#include <NeoPixelAnimator.h>
|
||||
|
||||
const uint16_t DigitCount = 5; // Max Digits, not segments, not pixels
|
||||
const uint8_t BusPin = 2; // make sure to set this to the correct pin, ignored for Esp8266
|
||||
const uint16_t CycleDigit = 0;
|
||||
const uint16_t SecondsDigit = 1;
|
||||
|
||||
#define brightness 128
|
||||
|
||||
NeoPixelSegmentBus<SevenSegmentFeature, Neo800KbpsMethod> strip(DigitCount, BusPin);
|
||||
|
||||
enum Animation
|
||||
{
|
||||
Animation_Cycle, // animation for the cycle indicator
|
||||
Animation_Fade, // animation for fade of seconds
|
||||
Animation_COUNT
|
||||
};
|
||||
|
||||
NeoPixelAnimator animations(Animation_COUNT);
|
||||
|
||||
void CycleAnimation(const AnimationParam& param)
|
||||
{
|
||||
// calculate which segment should be on using the animation progress
|
||||
uint8_t bitfield = 1 << (uint8_t)(param.progress * LedSegment_F);
|
||||
// instant a digit with that segment on
|
||||
SevenSegDigit digit(bitfield, brightness);
|
||||
// apply it to the strip
|
||||
strip.SetPixelColor(CycleDigit, digit);
|
||||
}
|
||||
|
||||
// for the animation of fading the new number in, we use
|
||||
// two digit DIBs (Device Independant Bitmaps) of SevenSegDigit to blend with;
|
||||
// each sized one less than the strip due to the first is a used for the cycle
|
||||
// animation.
|
||||
typedef NeoDib<SevenSegDigit> SevenSegDib;
|
||||
|
||||
SevenSegDib StartingDigits(DigitCount - 1);
|
||||
SevenSegDib EndingDigits(DigitCount - 1);
|
||||
|
||||
// shader class that will do the "string" blending
|
||||
//
|
||||
class DigitBlendShader
|
||||
{
|
||||
public:
|
||||
// this shader always renders and doesn't track a dirty state
|
||||
bool IsDirty() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetDirty()
|
||||
{
|
||||
}
|
||||
|
||||
SevenSegDigit Apply(uint16_t indexDigit, SevenSegDigit digit)
|
||||
{
|
||||
// since we call EndingDigits.Render below, the digit argument is
|
||||
// from the EndingDigits so no need to call GetPixelColor to get it
|
||||
// create a digit that is a blend between the last seconds
|
||||
// value and the next seconds value using the BlendAmount
|
||||
SevenSegDigit blendDigit = SevenSegDigit::LinearBlend(
|
||||
StartingDigits.GetPixelColor(indexDigit),
|
||||
digit,
|
||||
BlendAmount);
|
||||
|
||||
return blendDigit;
|
||||
}
|
||||
|
||||
float BlendAmount;
|
||||
};
|
||||
|
||||
// the instance of our shader class
|
||||
DigitBlendShader blendShader;
|
||||
|
||||
void FadeAnimation(const AnimationParam& param)
|
||||
{
|
||||
// set the shader property BlendAmount to the animation progress
|
||||
blendShader.BlendAmount = param.progress;
|
||||
// apply it to the strip at the SecondsDigit location
|
||||
EndingDigits.Render<SevenSegmentFeature, DigitBlendShader>(strip,
|
||||
blendShader,
|
||||
SecondsDigit);
|
||||
}
|
||||
|
||||
uint32_t lastSeconds;
|
||||
|
||||
void setup()
|
||||
{
|
||||
lastSeconds = millis() / 1000;
|
||||
|
||||
strip.Begin();
|
||||
strip.Show();
|
||||
|
||||
// init animation Dibs as cleared
|
||||
StartingDigits.ClearTo(0);
|
||||
EndingDigits.ClearTo(0);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t seconds = millis() / 1000;
|
||||
|
||||
// when the seconds change, start animations for the update
|
||||
//
|
||||
if (seconds != lastSeconds)
|
||||
{
|
||||
// copy last animation ending digits as starting digits
|
||||
StartingDigits = EndingDigits;
|
||||
|
||||
// format and display new value in ending digits dib
|
||||
String display(seconds);
|
||||
SevenSegDigit::SetString<SevenSegDib>(EndingDigits,
|
||||
0,
|
||||
display.c_str(),
|
||||
brightness);
|
||||
|
||||
// start the seconds fade animation
|
||||
animations.StartAnimation(Animation_Fade, 1000, FadeAnimation);
|
||||
|
||||
// start the cycle animation for the next second
|
||||
animations.StartAnimation(Animation_Cycle, 1000, CycleAnimation);
|
||||
|
||||
lastSeconds = seconds;
|
||||
}
|
||||
|
||||
if (animations.IsAnimating())
|
||||
{
|
||||
// the normal loop just needs these two to run the active animations
|
||||
animations.UpdateAnimations();
|
||||
strip.Show();
|
||||
}
|
||||
}
|
||||
|
@@ -153,7 +153,6 @@ private:
|
||||
_duration = duration;
|
||||
_remaining = duration;
|
||||
_fnCallback = animUpdate;
|
||||
|
||||
}
|
||||
|
||||
void StopAnimation()
|
||||
|
@@ -43,10 +43,12 @@ License along with NeoPixel. If not, see
|
||||
#include "internal/HsbColor.h"
|
||||
#include "internal/HtmlColor.h"
|
||||
#include "internal/RgbwColor.h"
|
||||
#include "internal/SegmentDigit.h"
|
||||
|
||||
#include "internal/NeoColorFeatures.h"
|
||||
#include "internal/DotStarColorFeatures.h"
|
||||
#include "internal/Lpd8806ColorFeatures.h"
|
||||
#include "internal/NeoSegmentFeatures.h"
|
||||
|
||||
#include "internal/Layouts.h"
|
||||
#include "internal/NeoTopology.h"
|
||||
|
67
src/NeoPixelSegmentBus.h
Normal file
67
src/NeoPixelSegmentBus.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixelBus library wrapper template class that provides enhanced methods
|
||||
for writing to segment based strips
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NeoPixelBus.h"
|
||||
|
||||
template<typename T_COLOR_FEATURE, typename T_METHOD> class NeoPixelSegmentBus :
|
||||
public NeoPixelBus<T_COLOR_FEATURE, T_METHOD>
|
||||
{
|
||||
public:
|
||||
NeoPixelSegmentBus(uint16_t countPixels, uint8_t pin) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels, pin)
|
||||
{
|
||||
}
|
||||
|
||||
NeoPixelSegmentBus(uint16_t countPixels) :
|
||||
NeoPixelBus<T_COLOR_FEATURE, T_METHOD>(countPixels)
|
||||
{
|
||||
}
|
||||
|
||||
void SetString(uint16_t indexDigit,
|
||||
const char* str,
|
||||
uint8_t brightness,
|
||||
uint8_t defaultBrightness = 0)
|
||||
{
|
||||
T_COLOR_FEATURE::ColorObject::SetString(*this,
|
||||
indexDigit,
|
||||
str,
|
||||
brightness,
|
||||
defaultBrightness);
|
||||
}
|
||||
|
||||
void SetString(uint16_t indexDigit,
|
||||
const String& str,
|
||||
uint8_t brightness,
|
||||
uint8_t defaultBrightness = 0)
|
||||
{
|
||||
SetString(indexDigit, str.c_str(), brightness, defaultBrightness);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -45,9 +45,10 @@ public:
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[0];
|
||||
*pPixelDest++ = pPixelSrc[1];
|
||||
*pPixelDest++ = pPixelSrc[2];
|
||||
for (uint8_t iElement = 0; iElement < PixelSize; iElement++)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[iElement];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +58,6 @@ public:
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +68,6 @@ public:
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +78,6 @@ public:
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -94,6 +94,25 @@ public:
|
||||
free((uint8_t*)_pixels);
|
||||
}
|
||||
|
||||
NeoDib& operator=(const NeoDib& other)
|
||||
{
|
||||
// check for self-assignment
|
||||
if (&other == this)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint16_t copyCount = other.PixelCount() < PixelCount() ? other.PixelCount() : PixelCount();
|
||||
|
||||
for (uint16_t pixel = 0; pixel < copyCount; pixel++)
|
||||
{
|
||||
_pixels[pixel] = other.Pixels()[pixel];
|
||||
}
|
||||
|
||||
Dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
T_COLOR_OBJECT* Pixels() const
|
||||
{
|
||||
return _pixels;
|
||||
@@ -144,8 +163,8 @@ public:
|
||||
Dirty();
|
||||
};
|
||||
|
||||
template <typename T_COLOR_FEATURE, typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
|
||||
T_SHADER& shader)
|
||||
template <typename T_COLOR_FEATURE, typename T_SHADER>
|
||||
void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer, T_SHADER& shader, uint16_t destIndexPixel = 0)
|
||||
{
|
||||
if (IsDirty() || shader.IsDirty())
|
||||
{
|
||||
@@ -159,7 +178,7 @@ public:
|
||||
for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++)
|
||||
{
|
||||
T_COLOR_OBJECT color = shader.Apply(indexPixel, _pixels[indexPixel]);
|
||||
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexPixel, color);
|
||||
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, destIndexPixel + indexPixel, color);
|
||||
}
|
||||
|
||||
shader.ResetDirty();
|
||||
|
130
src/internal/NeoSegmentFeatures.h
Normal file
130
src/internal/NeoSegmentFeatures.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoSegmentFeatures provides feature classes to describe seven segment display
|
||||
elements for NeoPixelBus template class
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
class Neo9Elements
|
||||
{
|
||||
public:
|
||||
static const size_t PixelSize = 9; // three 3 element
|
||||
|
||||
static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
return pPixels + indexPixel * PixelSize;
|
||||
}
|
||||
|
||||
static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
for (uint8_t iElement = 0; iElement < PixelSize; iElement++)
|
||||
{
|
||||
*pPixelDest++ = pPixelSrc[iElement];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = *pPixelSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pEnd = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrc = (const uint8_t*)pPixelSrc;
|
||||
while (pPixelDest < pEnd)
|
||||
{
|
||||
*pPixelDest++ = pgm_read_byte(pSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count)
|
||||
{
|
||||
uint8_t* pDestBack = pPixelDest + (count * PixelSize);
|
||||
const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize);
|
||||
while (pDestBack > pPixelDest)
|
||||
{
|
||||
*--pDestBack = *--pSrcBack;
|
||||
}
|
||||
}
|
||||
|
||||
typedef SevenSegDigit ColorObject;
|
||||
};
|
||||
|
||||
// Abcdefg byte order
|
||||
class NeoAbcdefgSegmentFeature : public Neo9Elements
|
||||
{
|
||||
public:
|
||||
static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color)
|
||||
{
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
|
||||
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
|
||||
{
|
||||
*p++ = color.Segment[iSegment];
|
||||
}
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor(uint8_t* pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
uint8_t* p = getPixelAddress(pPixels, indexPixel);
|
||||
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
|
||||
{
|
||||
color.Segment[iSegment] = *p++;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel)
|
||||
{
|
||||
ColorObject color;
|
||||
const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel);
|
||||
uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++)
|
||||
{
|
||||
color.Segment[iSegment] = pgm_read_byte(p++);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef NeoAbcdefgSegmentFeature SevenSegmentFeature; // Abcdefg order is default
|
153
src/internal/SegmentDigit.cpp
Normal file
153
src/internal/SegmentDigit.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
SegmentDigit provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include "SegmentDigit.h"
|
||||
|
||||
//
|
||||
// https://en.wikichip.org/wiki/seven-segment_display/representing_letters
|
||||
//
|
||||
const uint8_t SevenSegDigit::DecodeNumbers[] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F };
|
||||
|
||||
const uint8_t SevenSegDigit::DecodeAlphaCaps[] = {
|
||||
// A B C D E F G
|
||||
0x77, 0x00, 0x39, 0x00, 0x79, 0x71, 0x3D,
|
||||
// H I J K L M N
|
||||
0x76, 0x30, 0x1E, 0x00, 0x38, 0x00, 0x00,
|
||||
// O P Q R S
|
||||
0x3F, 0x73, 0x00, 0x00, 0x6D,
|
||||
// T U V W X Y Z
|
||||
0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const uint8_t SevenSegDigit::DecodeAlpha[] = {
|
||||
// a b c d e f g
|
||||
0x00, 0x7C, 0x58, 0x5E, 0x00, 0x00, 0x00,
|
||||
// h i j k l m n
|
||||
0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
|
||||
// o p q r s
|
||||
0x5C, 0x00, 0x67, 0x50, 0x00,
|
||||
// t u v w x y z
|
||||
0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00 };
|
||||
|
||||
const uint8_t SevenSegDigit::DecodeSpecial[] = {
|
||||
// , - . /
|
||||
0x80, 0x40, 0x80, 0x40 };
|
||||
|
||||
void SevenSegDigit::init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness)
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
Segment[iSegment] = (bitmask & 0x01) ? brightness : defaultBrightness;
|
||||
bitmask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
SevenSegDigit::SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness)
|
||||
{
|
||||
init(bitmask, brightness, defaultBrightness);
|
||||
};
|
||||
|
||||
SevenSegDigit::SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness)
|
||||
{
|
||||
if (letter >= '0' && letter <= '9')
|
||||
{
|
||||
init(DecodeNumbers[letter - '0'], brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= 'a' && letter <= 'z')
|
||||
{
|
||||
init(DecodeAlpha[letter - 'a'], brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= 'A' && letter <= 'Z')
|
||||
{
|
||||
init(DecodeAlphaCaps[letter - 'A'], brightness, defaultBrightness);
|
||||
}
|
||||
else if (letter >= ',' && letter <= '/')
|
||||
{
|
||||
init(DecodeSpecial[letter - ','], brightness, defaultBrightness);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(Segment, defaultBrightness, sizeof(Segment));
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t SevenSegDigit::CalculateBrightness() const
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
sum += Segment[iSegment];
|
||||
}
|
||||
|
||||
return (uint8_t)(sum / SegmentCount);
|
||||
}
|
||||
|
||||
void SevenSegDigit::Darken(uint8_t delta)
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
uint8_t element = Segment[iSegment];
|
||||
if (element > delta)
|
||||
{
|
||||
element -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = 0;
|
||||
}
|
||||
Segment[iSegment] = element;
|
||||
}
|
||||
}
|
||||
|
||||
void SevenSegDigit::Lighten(uint8_t delta)
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
uint8_t element = Segment[iSegment];
|
||||
if (element < 255 - delta)
|
||||
{
|
||||
element += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = 255;
|
||||
}
|
||||
Segment[iSegment] = element;
|
||||
}
|
||||
}
|
||||
|
||||
SevenSegDigit SevenSegDigit::LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress)
|
||||
{
|
||||
SevenSegDigit result;
|
||||
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
result.Segment[iSegment] = left.Segment[iSegment] + ((right.Segment[iSegment] - left.Segment[iSegment]) * progress);
|
||||
}
|
||||
return result;
|
||||
}
|
202
src/internal/SegmentDigit.h
Normal file
202
src/internal/SegmentDigit.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
SegmentDigit provides a color object that can be directly consumed by NeoPixelBus
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
enum LedSegment
|
||||
{
|
||||
LedSegment_A,
|
||||
LedSegment_B,
|
||||
LedSegment_C,
|
||||
LedSegment_D,
|
||||
LedSegment_E,
|
||||
LedSegment_F,
|
||||
LedSegment_G,
|
||||
LedSegment_Decimal,
|
||||
LedSegment_COUNT
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// SevenSegDigit represents a color object that is represented by the segments
|
||||
// of a 7 segment LED display digit. It contains helpful routines to manipulate
|
||||
// and set the elements.
|
||||
//
|
||||
// The order represents the physical LED location starting at A, through to G, then
|
||||
// ending at the decimal point
|
||||
// "abcdefg."
|
||||
// ------------------------------------------------------------------------
|
||||
struct SevenSegDigit
|
||||
{
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// the default brightness to apply to all segments
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(uint8_t defaultBrightness)
|
||||
{
|
||||
memset(Segment, defaultBrightness, sizeof(Segment));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// a bitmask for the segment (bit order is ".gfedcba")
|
||||
// the brightness to apply to them, (0-255)
|
||||
// the default brightness to apply to those not set in the bitmask (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness = 0);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit using
|
||||
// a char that will get mapped to the segments,
|
||||
// the brightness to apply to them, (0-255)
|
||||
// the default brightness to apply to those not set in the bitmask (0-255)
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness = 0);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Construct a SevenSegDigit that will have its values set in latter operations
|
||||
// CAUTION: The members are not initialized and may not be consistent
|
||||
// ------------------------------------------------------------------------
|
||||
SevenSegDigit()
|
||||
{
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Comparison operators
|
||||
// ------------------------------------------------------------------------
|
||||
bool operator==(const SevenSegDigit& other) const
|
||||
{
|
||||
for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++)
|
||||
{
|
||||
if (Segment[iSegment] != other.Segment[iSegment])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool operator!=(const SevenSegDigit& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// CalculateBrightness will calculate the overall brightness
|
||||
// NOTE: This is a simple linear brightness
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t CalculateBrightness() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Darken will adjust the color by the given delta toward black
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to dim the segment
|
||||
// ------------------------------------------------------------------------
|
||||
void Darken(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Lighten will adjust the color by the given delta toward white
|
||||
// NOTE: This is a simple linear change
|
||||
// delta - (0-255) the amount to lighten the segment
|
||||
// ------------------------------------------------------------------------
|
||||
void Lighten(uint8_t delta);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// LinearBlend between two colors by the amount defined by progress variable
|
||||
// left - the segment to start the blend at
|
||||
// right - the segment to end the blend at
|
||||
// progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right
|
||||
// and a value between will blend the brightness of each element
|
||||
// weighted linearly between them
|
||||
// ------------------------------------------------------------------------
|
||||
static SevenSegDigit LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress);
|
||||
|
||||
template <typename T_SET_TARGET>
|
||||
static void SetString(T_SET_TARGET& target, uint16_t indexDigit, const char* str, uint8_t brightness, uint8_t defaultBrightness = 0)
|
||||
{
|
||||
if (str == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pFirst = str;
|
||||
const char* pIter = str;
|
||||
|
||||
// digits are right to left
|
||||
// so find the end
|
||||
while (*pIter != '\0')
|
||||
{
|
||||
pIter++;
|
||||
}
|
||||
pIter--;
|
||||
|
||||
|
||||
while (pIter >= pFirst)
|
||||
{
|
||||
bool decimal = false;
|
||||
char value = *pIter;
|
||||
|
||||
// check if merging a decimal is required
|
||||
if (pIter > pFirst && (*pIter == '.' || *pIter == ','))
|
||||
{
|
||||
// merge a decimal as long as they aren't the same
|
||||
if (*(pIter - 1) != *pIter)
|
||||
{
|
||||
decimal = true;
|
||||
pIter--;
|
||||
value = *pIter; // use the next char
|
||||
}
|
||||
}
|
||||
|
||||
SevenSegDigit digit(value, brightness, defaultBrightness);
|
||||
if (decimal)
|
||||
{
|
||||
digit.Segment[LedSegment_Decimal] = brightness;
|
||||
}
|
||||
target.SetPixelColor(indexDigit, digit);
|
||||
indexDigit++;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// segment members (0-255) where each represents the segment location
|
||||
// and the value defines the brightnes (0) is off and (255) is full brightness
|
||||
// ------------------------------------------------------------------------
|
||||
static const uint8_t SegmentCount = 9;
|
||||
uint8_t Segment[SegmentCount];
|
||||
|
||||
|
||||
// segment decode maps from ascii relative first char in map to a bitmask of segments
|
||||
//
|
||||
static const uint8_t DecodeNumbers[10]; // 0-9
|
||||
static const uint8_t DecodeAlphaCaps[26]; // A-Z
|
||||
static const uint8_t DecodeAlpha[26]; // a-z
|
||||
static const uint8_t DecodeSpecial[4]; // , - . /
|
||||
|
||||
protected:
|
||||
void init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness);
|
||||
};
|
||||
|
Reference in New Issue
Block a user