Added exponential brightness to PWM conversion
This commit is contained in:
parent
aa3bcf5eaf
commit
b3d980c2ac
|
@ -87,14 +87,14 @@ Modes
|
|||
Sets all steps to the same brightness.
|
||||
|
||||
Parameters:<br>
|
||||
**brightness** (word): value in range 0 (off) to 4096 (fully on).
|
||||
**brightness** (word): value in range 0 (off) to 4095 (fully on).
|
||||
|
||||
|
||||
### Custom
|
||||
Sets the brightness for each of the steps individually.
|
||||
|
||||
Parameters:<br>
|
||||
**brightness** (word[stepCount]): array of brightness values in range 0 - 4096. The number of values must be equal to the number of steps are reported in the Ping response. Bottom step first.
|
||||
**brightness** (word[stepCount]): array of brightness values in range 0 - 4095. The number of values must be equal to the number of steps are reported in the Ping response. Bottom step first.
|
||||
|
||||
|
||||
### Alternate
|
||||
|
@ -102,7 +102,7 @@ Alternates between even and odd steps being lit. Bring out our next contestant!
|
|||
|
||||
Parameters:<br>
|
||||
**interval** (word): The time each set of steps is lit in milliseconds.<br>
|
||||
**brightness** (word): value in range 0 (off) to 4096 (fully on).
|
||||
**brightness** (word): value in range 0 (off) to 4095 (fully on).
|
||||
|
||||
|
||||
### Slide
|
||||
|
|
|
@ -20,7 +20,7 @@ class PCA9685
|
|||
|
||||
public:
|
||||
static const uint16_t Off = 0;
|
||||
static const uint16_t On = 4096;
|
||||
static const uint16_t On = 4095;
|
||||
|
||||
static const uint8_t RegisterMode1 = 0x0;
|
||||
static const uint8_t RegisterPrescale = 0xFE;
|
||||
|
|
26
src/main.cpp
26
src/main.cpp
|
@ -47,18 +47,18 @@ void setup()
|
|||
|
||||
|
||||
// Run a little startup test sequence
|
||||
pwmDriver->setAll(PCA9685::Off);
|
||||
pwmDriver->setPWM(0, PCA9685::On);
|
||||
stairs->setAll(IStairs::Off);
|
||||
stairs->set(0, IStairs::On);
|
||||
delay(300);
|
||||
|
||||
for (int step = 1; step < StepCount; step++)
|
||||
{
|
||||
pwmDriver->setPWM(step - 1, PCA9685::Off);
|
||||
pwmDriver->setPWM(step, PCA9685::On);
|
||||
stairs->set(step - 1, IStairs::Off);
|
||||
stairs->set(step, IStairs::On);
|
||||
delay(300);
|
||||
}
|
||||
|
||||
pwmDriver->setPWM(StepCount - 1, PCA9685::Off);
|
||||
stairs->set(StepCount - 1, IStairs::Off);
|
||||
|
||||
|
||||
// Pulsate the bottom step while WiFi is connecting
|
||||
|
@ -71,7 +71,7 @@ void setup()
|
|||
if (brightness <= 0 || brightness >= 1024)
|
||||
speed = -speed;
|
||||
|
||||
pwmDriver->setPWM(0, brightness);
|
||||
stairs->set(0, brightness);
|
||||
delay(16);
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,15 @@ void setup()
|
|||
|
||||
|
||||
uint32_t currentTime;
|
||||
uint8_t packet[51];
|
||||
|
||||
// Note: the packet size must at least be able to accomodate the
|
||||
// command with the largest parameter list, there is no overflow
|
||||
// checking in the mode classes!
|
||||
//
|
||||
// At the time of writing, CustomMode is the largest:
|
||||
// Set Mode (1) + Custom (1) + StepCount * Word (2)
|
||||
// = 30 for 14 steps
|
||||
uint8_t packet[50];
|
||||
uint8_t* packetRef;
|
||||
|
||||
void loop()
|
||||
|
@ -101,12 +109,11 @@ void checkRequest()
|
|||
int packetSize = udpServer.parsePacket();
|
||||
if (packetSize)
|
||||
{
|
||||
memset(packet, 0, sizeof(packet));
|
||||
int length = udpServer.read(packet, 50);
|
||||
if (length && packet[0])
|
||||
{
|
||||
packet[length] = 0;
|
||||
packetRef = packet;
|
||||
|
||||
handleRequest(packetRef);
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +154,7 @@ void handleRequest(uint8_t* packet)
|
|||
newMode->read(packet);
|
||||
|
||||
udpServer.write(Command::SetMode);
|
||||
udpServer.write(newIdentifier);
|
||||
newMode->write(&udpServer);
|
||||
|
||||
setCurrentMode(newMode, newIdentifier);
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
class IStairs
|
||||
{
|
||||
public:
|
||||
static const uint16_t Off = 0;
|
||||
static const uint16_t On = 4095;
|
||||
|
||||
virtual uint8_t getCount() = 0;
|
||||
virtual void set(uint8_t step, uint16_t value) = 0;
|
||||
virtual void setAll(uint16_t value) = 0;
|
||||
|
|
|
@ -23,7 +23,7 @@ class AlternateMode : public BaseMode<AlternateModeParameters>
|
|||
AlternateMode()
|
||||
{
|
||||
parameters.interval = 500;
|
||||
parameters.brightness = 4096;
|
||||
parameters.brightness = IStairs::On;
|
||||
}
|
||||
|
||||
void init(IStairs* stairs, uint32_t currentTime);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#include "custom.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
void CustomMode::read(uint8_t* data)
|
||||
{
|
||||
// The packet is zeroed before we get our hands on it and
|
||||
// the size should also be larger as noted in main.cpp,
|
||||
// so a straight-up copy should be safe.
|
||||
memcpy(this->values, data, sizeof(this->values));
|
||||
}
|
||||
|
||||
|
||||
void CustomMode::write(Stream* stream)
|
||||
{
|
||||
stream->write(reinterpret_cast<uint8_t*>(&this->values), sizeof(this->values));
|
||||
}
|
||||
|
||||
|
||||
void CustomMode::init(IStairs* stairs, uint32_t currentTime)
|
||||
{
|
||||
for (uint8_t step = 0; step < StepCount; step++)
|
||||
stairs->set(step, this->values[step]);
|
||||
}
|
||||
|
||||
|
||||
void CustomMode::tick(IStairs* stairs, uint32_t currentTime)
|
||||
{
|
||||
}
|
|
@ -9,6 +9,13 @@ class CustomMode : public IMode
|
|||
{
|
||||
private:
|
||||
uint16_t values[StepCount];
|
||||
|
||||
public:
|
||||
void read(uint8_t* data);
|
||||
void write(Stream* stream);
|
||||
|
||||
void init(IStairs* stairs, uint32_t currentTime);
|
||||
void tick(IStairs* stairs, uint32_t currentTime);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,6 +1,11 @@
|
|||
#include <Math.h>
|
||||
#include "stairs.h"
|
||||
#include "config.h"
|
||||
|
||||
|
||||
static const float brightnessFactor = ((IStairs::On - IStairs::Off) + 1) * log10(2) / log10(PCA9685::On);
|
||||
|
||||
|
||||
void Stairs::init(PCA9685* pwmDriver)
|
||||
{
|
||||
this->pwmDriver = pwmDriver;
|
||||
|
@ -13,13 +18,24 @@ uint8_t Stairs::getCount()
|
|||
}
|
||||
|
||||
|
||||
void Stairs::set(uint8_t step, uint16_t value)
|
||||
void Stairs::set(uint8_t step, uint16_t brightness)
|
||||
{
|
||||
pwmDriver->setPWM(step, value);
|
||||
pwmDriver->setPWM(step, this->getPWMValue(brightness));
|
||||
}
|
||||
|
||||
|
||||
void Stairs::setAll(uint16_t value)
|
||||
void Stairs::setAll(uint16_t brightness)
|
||||
{
|
||||
pwmDriver->setAll(value);
|
||||
pwmDriver->setAll(this->getPWMValue(brightness));
|
||||
}
|
||||
|
||||
|
||||
uint16_t Stairs::getPWMValue(uint16_t brightness)
|
||||
{
|
||||
if (brightness == IStairs::Off || brightness == IStairs::On)
|
||||
return brightness;
|
||||
|
||||
// Correct for the exponential perception of brightness
|
||||
// Source: https://diarmuid.ie/blog/pwm-exponential-led-fading-on-arduino-or-other-platforms/
|
||||
return pow(2, (brightness / brightnessFactor)) - 1;
|
||||
}
|
|
@ -9,12 +9,15 @@ class Stairs : public IStairs
|
|||
private:
|
||||
PCA9685* pwmDriver;
|
||||
|
||||
protected:
|
||||
uint16_t getPWMValue(uint16_t brightness);
|
||||
|
||||
public:
|
||||
void init(PCA9685* pwmDriver);
|
||||
|
||||
uint8_t getCount();
|
||||
void set(uint8_t step, uint16_t value);
|
||||
void setAll(uint16_t value);
|
||||
void set(uint8_t step, uint16_t brightness);
|
||||
void setAll(uint16_t brightness);
|
||||
};
|
||||
|
||||
#endif
|
41
web/app.js
41
web/app.js
|
@ -9,6 +9,32 @@ function lsb(value) { return value & 0xFF; }
|
|||
function msb(value) { return (value >> 8) & 0xFF; }
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Alternating
|
||||
|
||||
var message = new Buffer([protocol.Command.SetMode, protocol.Mode.Alternate, lsb(500), msb(500), lsb(128), msb(128)]);
|
||||
client.send(message, 0, message.length, 3126, '10.138.2.12', function(err, bytes) {
|
||||
if (err) throw err;
|
||||
console.log('UDP message sent');
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
var client = dgram.createSocket('udp4');
|
||||
client.on('listening', function()
|
||||
{
|
||||
var address = client.address();
|
||||
console.log('UDP client listening on ' + address.address + ":" + address.port);
|
||||
});
|
||||
|
||||
client.on('message', function (message, remote)
|
||||
{
|
||||
console.log('< ' + remote.address + ':' + remote.port +' - ' + message.toString('hex'));
|
||||
});
|
||||
|
||||
|
||||
setInterval(function()
|
||||
{
|
||||
// 0x00, 0x10 = 4096
|
||||
|
@ -17,21 +43,8 @@ setInterval(function()
|
|||
speed = -speed;
|
||||
|
||||
var message = new Buffer([protocol.Command.SetMode, protocol.Mode.Static, lsb(on), msb(on)]);
|
||||
var client = dgram.createSocket('udp4');
|
||||
client.on('listening', function()
|
||||
{
|
||||
var address = client.address();
|
||||
console.log('UDP client listening on ' + address.address + ":" + address.port);
|
||||
});
|
||||
|
||||
client.on('message', function (message, remote)
|
||||
{
|
||||
console.log(remote.address + ':' + remote.port +' - ' + message.toString('hex'));
|
||||
client.close();
|
||||
});
|
||||
|
||||
client.send(message, 0, message.length, 3126, '10.138.2.12', function(err, bytes) {
|
||||
if (err) throw err;
|
||||
console.log('UDP message sent');
|
||||
console.log('> ' + '10.138.2.12' + ':' + '3126' + ' - ' + message.toString('hex'));
|
||||
});
|
||||
}, 200);
|
Loading…
Reference in New Issue