More Colours
We can also leave the PWM-based control of the LEDs directly to the microcontroller.
For sat.cfg:
board chocolate 0.2 rascal +allpwmled
!device
has_custom_hooks y
build_files custom.cpp
This time we leave out the components option. The code running on the microcontroller in custom.cpp to produce the cycling rainbow pattern is:
#include <sat/satx.hpp>
#include <math.h>
using namespace sat;
using namespace sat::resource;
namespace
{
// Number of RGB LEDs.
constexpr const uint NUM_LEDS = 5;
// Maximum brightness.
constexpr const float MAX_BRIGHTNESS = 0.02f;
// Duty resolution.
constexpr const uint DUTY_RESOLUTION = 32768;
// How far each adjacent LED is in the colour cycle ahead of the previous
// one.
constexpr const float COLOUR_LEAD = 0.04f;
// Full cycle time in milliseconds.
constexpr const float FULL_CYCLE_TIME = 8192.0f;
struct LED
{
LED() {}
LED(PWM* _r, PWM* _g, PWM* _b) : r(_r), g(_g), b(_b) {}
PWM* r = nullptr;
PWM* g = nullptr;
PWM* b = nullptr;
};
LED leds[NUM_LEDS];
}
void Init()
{
leds[0] = LED{led0r, led0g, led0b};
leds[1] = LED{led1r, led1g, led1b};
leds[2] = LED{led3r, led3g, led3b};
leds[3] = LED{led4r, led4g, led4b};
leds[4] = LED{led2r, led2g, led2b};
for (uint i=0; i<NUM_LEDS; i++)
{
LED& led(leds[i]);
led.r->setDutyResolution(DUTY_RESOLUTION);
led.g->setDutyResolution(DUTY_RESOLUTION);
led.b->setDutyResolution(DUTY_RESOLUTION);
}
}
void Update()
{
uint ticks = sys->ticks();
for (uint i=0; i<NUM_LEDS; i++)
{
LED& led(leds[i]);
float r = fmodf((float)ticks / FULL_CYCLE_TIME + COLOUR_LEAD*(float)i, 1.0f) * 6.0f;
float cr = 0.0f;
float cg = 0.0f;
float cb = 0.0f;
if (r < 1.0f)
{
cr = 1.0f;
cg = r;
cb = 0.0f;
}
else if (r < 2.0f)
{
cr = 1.0f - (r - 1.0f);
cg = 1.0f;
cb = 0.0f;
}
else if (r < 3.0f)
{
cr = 0.0f;
cg = 1.0f;
cb = r - 2.0f;
}
else if (r < 4.0f)
{
cr = 0.0f;
cg = 1.0f - (r - 3.0f);
cb = 1.0f;
}
else if (r < 5.0f)
{
cr = r - 4.0f;
cg = 0.0f;
cb = 1.0f;
}
else
{
cr = 1.0f;
cg = 0.0f;
cb = 1.0f - (r - 5.0f);
}
led.r->setDuty((int)(cr * (float)DUTY_RESOLUTION * MAX_BRIGHTNESS + 0.5f));
led.g->setDuty((int)(cg * (float)DUTY_RESOLUTION * MAX_BRIGHTNESS + 0.5f));
led.b->setDuty((int)(cb * (float)DUTY_RESOLUTION * MAX_BRIGHTNESS + 0.5f));
}
}