Merge pull request #194 from pimoroni/patch_plasma2040_examples
Extra examples and bug fixes for Plasma2040
This commit is contained in:
commit
07f3d65a14
|
@ -33,7 +33,7 @@ namespace pimoroni {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BME68X::configure(uint8_t filter, uint8_t odr, uint8_t os_humidity, uint8_t os_pressure, uint8_t os_temp) {
|
bool BME68X::configure(uint8_t filter, uint8_t odr, uint8_t os_humidity, uint8_t os_pressure, uint8_t os_temp) {
|
||||||
int8_t result;
|
int8_t result = 0;
|
||||||
|
|
||||||
conf.filter = filter;
|
conf.filter = filter;
|
||||||
conf.odr = odr;
|
conf.odr = odr;
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
namespace plasma {
|
namespace plasma {
|
||||||
|
|
||||||
APA102::APA102(uint num_leds, PIO pio, uint sm, uint pin_dat, uint pin_clk, uint freq, RGB* buffer) : buffer(buffer), num_leds(num_leds), pio(pio), sm(sm) {
|
APA102::APA102(uint num_leds, PIO pio, uint sm, uint pin_dat, uint pin_clk, uint freq, RGB* buffer) : buffer(buffer), num_leds(num_leds), pio(pio), sm(sm) {
|
||||||
uint offset = pio_add_program(pio, &apa102_program);
|
pio_program_offset = pio_add_program(pio, &apa102_program);
|
||||||
|
|
||||||
pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_clk) | (1u << pin_dat));
|
pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_clk) | (1u << pin_dat));
|
||||||
pio_sm_set_pindirs_with_mask(pio, sm, ~0u, (1u << pin_clk) | (1u << pin_dat));
|
pio_sm_set_pindirs_with_mask(pio, sm, ~0u, (1u << pin_clk) | (1u << pin_dat));
|
||||||
pio_gpio_init(pio, pin_clk);
|
pio_gpio_init(pio, pin_clk);
|
||||||
pio_gpio_init(pio, pin_dat);
|
pio_gpio_init(pio, pin_dat);
|
||||||
|
|
||||||
pio_sm_config c = apa102_program_get_default_config(offset);
|
pio_sm_config c = apa102_program_get_default_config(pio_program_offset);
|
||||||
sm_config_set_out_pins(&c, pin_dat, 1);
|
sm_config_set_out_pins(&c, pin_dat, 1);
|
||||||
sm_config_set_sideset_pins(&c, pin_clk);
|
sm_config_set_sideset_pins(&c, pin_clk);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ APA102::APA102(uint num_leds, PIO pio, uint sm, uint pin_dat, uint pin_clk, uint
|
||||||
float div = (float)clock_get_hz(clk_sys) / (2 * freq);
|
float div = (float)clock_get_hz(clk_sys) / (2 * freq);
|
||||||
sm_config_set_clkdiv(&c, div);
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
|
||||||
pio_sm_init(pio, sm, offset, &c);
|
pio_sm_init(pio, sm, pio_program_offset, &c);
|
||||||
pio_sm_set_enabled(pio, sm, true);
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
|
||||||
dma_channel = dma_claim_unused_channel(true);
|
dma_channel = dma_claim_unused_channel(true);
|
||||||
|
@ -34,6 +34,7 @@ APA102::APA102(uint num_leds, PIO pio, uint sm, uint pin_dat, uint pin_clk, uint
|
||||||
|
|
||||||
if(this->buffer == nullptr) {
|
if(this->buffer == nullptr) {
|
||||||
this->buffer = new RGB[num_leds];
|
this->buffer = new RGB[num_leds];
|
||||||
|
managed_buffer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,16 @@ namespace plasma {
|
||||||
clear();
|
clear();
|
||||||
update(true);
|
update(true);
|
||||||
dma_channel_unclaim(dma_channel);
|
dma_channel_unclaim(dma_channel);
|
||||||
|
pio_sm_set_enabled(pio, sm, false);
|
||||||
|
pio_remove_program(pio, &apa102_program, pio_program_offset);
|
||||||
|
#ifndef MICROPY_BUILD_TYPE
|
||||||
|
// pio_sm_unclaim seems to hardfault in MicroPython
|
||||||
pio_sm_unclaim(pio, sm);
|
pio_sm_unclaim(pio, sm);
|
||||||
delete[] buffer;
|
#endif
|
||||||
|
if(managed_buffer) {
|
||||||
|
// Only delete buffers we have allocated ourselves.
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool start(uint fps=60);
|
bool start(uint fps=60);
|
||||||
bool stop();
|
bool stop();
|
||||||
|
@ -78,7 +86,9 @@ namespace plasma {
|
||||||
uint32_t fps;
|
uint32_t fps;
|
||||||
PIO pio;
|
PIO pio;
|
||||||
uint sm;
|
uint sm;
|
||||||
|
uint pio_program_offset;
|
||||||
int dma_channel;
|
int dma_channel;
|
||||||
struct repeating_timer timer;
|
struct repeating_timer timer;
|
||||||
|
bool managed_buffer = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -3,12 +3,12 @@
|
||||||
namespace plasma {
|
namespace plasma {
|
||||||
|
|
||||||
WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, bool rgbw, COLOR_ORDER color_order, RGB* buffer) : buffer(buffer), num_leds(num_leds), color_order(color_order), pio(pio), sm(sm) {
|
WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, bool rgbw, COLOR_ORDER color_order, RGB* buffer) : buffer(buffer), num_leds(num_leds), color_order(color_order), pio(pio), sm(sm) {
|
||||||
uint offset = pio_add_program(pio, &ws2812_program);
|
pio_program_offset = pio_add_program(pio, &ws2812_program);
|
||||||
|
|
||||||
pio_gpio_init(pio, pin);
|
pio_gpio_init(pio, pin);
|
||||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
|
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
|
||||||
|
|
||||||
pio_sm_config c = ws2812_program_get_default_config(offset);
|
pio_sm_config c = ws2812_program_get_default_config(pio_program_offset);
|
||||||
sm_config_set_sideset_pins(&c, pin);
|
sm_config_set_sideset_pins(&c, pin);
|
||||||
|
|
||||||
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24); // Discard first (APA102 global brightness) byte. TODO support RGBW WS281X LEDs
|
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24); // Discard first (APA102 global brightness) byte. TODO support RGBW WS281X LEDs
|
||||||
|
@ -18,7 +18,7 @@ WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, bool rgbw,
|
||||||
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
|
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
|
||||||
sm_config_set_clkdiv(&c, div);
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
|
||||||
pio_sm_init(pio, sm, offset, &c);
|
pio_sm_init(pio, sm, pio_program_offset, &c);
|
||||||
pio_sm_set_enabled(pio, sm, true);
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
|
||||||
dma_channel = dma_claim_unused_channel(true);
|
dma_channel = dma_claim_unused_channel(true);
|
||||||
|
@ -33,6 +33,7 @@ WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, bool rgbw,
|
||||||
|
|
||||||
if(!this->buffer) {
|
if(!this->buffer) {
|
||||||
this->buffer = new RGB[num_leds];
|
this->buffer = new RGB[num_leds];
|
||||||
|
managed_buffer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,14 +63,22 @@ namespace plasma {
|
||||||
uint32_t num_leds;
|
uint32_t num_leds;
|
||||||
COLOR_ORDER color_order;
|
COLOR_ORDER color_order;
|
||||||
|
|
||||||
WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq=DEFAULT_SERIAL_FREQ, bool rgbw=false, COLOR_ORDER color_order=COLOR_ORDER::RGB, RGB* buffer=nullptr);
|
WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq=DEFAULT_SERIAL_FREQ, bool rgbw=false, COLOR_ORDER color_order=COLOR_ORDER::GRB, RGB* buffer=nullptr);
|
||||||
~WS2812() {
|
~WS2812() {
|
||||||
stop();
|
stop();
|
||||||
clear();
|
clear();
|
||||||
update(true);
|
update(true);
|
||||||
dma_channel_unclaim(dma_channel);
|
dma_channel_unclaim(dma_channel);
|
||||||
|
pio_sm_set_enabled(pio, sm, false);
|
||||||
|
pio_remove_program(pio, &ws2812_program, pio_program_offset);
|
||||||
|
#ifndef MICROPY_BUILD_TYPE
|
||||||
|
// pio_sm_unclaim seems to hardfault in MicroPython
|
||||||
pio_sm_unclaim(pio, sm);
|
pio_sm_unclaim(pio, sm);
|
||||||
delete[] buffer;
|
#endif
|
||||||
|
if(managed_buffer) {
|
||||||
|
// Only delete buffers we have allocated ourselves.
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool start(uint fps=60);
|
bool start(uint fps=60);
|
||||||
bool stop();
|
bool stop();
|
||||||
|
@ -87,7 +95,9 @@ namespace plasma {
|
||||||
uint32_t fps;
|
uint32_t fps;
|
||||||
PIO pio;
|
PIO pio;
|
||||||
uint sm;
|
uint sm;
|
||||||
|
uint pio_program_offset;
|
||||||
int dma_channel;
|
int dma_channel;
|
||||||
struct repeating_timer timer;
|
struct repeating_timer timer;
|
||||||
|
bool managed_buffer = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
include(plasma2040_rotary.cmake)
|
include(plasma2040_level.cmake)
|
||||||
|
include(plasma2040_monitor.cmake)
|
||||||
include(plasma2040_rainbow.cmake)
|
include(plasma2040_rainbow.cmake)
|
||||||
|
include(plasma2040_rotary.cmake)
|
||||||
include(plasma2040_stacker.cmake)
|
include(plasma2040_stacker.cmake)
|
|
@ -0,0 +1,17 @@
|
||||||
|
set(OUTPUT_NAME plasma2040_level)
|
||||||
|
add_executable(${OUTPUT_NAME} plasma2040_level.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(${OUTPUT_NAME}
|
||||||
|
pico_stdlib
|
||||||
|
plasma2040
|
||||||
|
breakout_msa301
|
||||||
|
hardware_i2c
|
||||||
|
pimoroni_i2c
|
||||||
|
rgbled
|
||||||
|
button
|
||||||
|
)
|
||||||
|
|
||||||
|
# enable usb output
|
||||||
|
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||||
|
|
||||||
|
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,245 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "plasma2040.hpp"
|
||||||
|
|
||||||
|
#include "common/pimoroni_common.hpp"
|
||||||
|
#include "breakout_msa301.hpp"
|
||||||
|
#include "rgbled.hpp"
|
||||||
|
#include "button.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
A simple balancing game, where you use the MSA301 accelerometer to line up a band with a goal on the strip.
|
||||||
|
This can either be done using:
|
||||||
|
- Angle mode: Where position on the strip directly matches the accelerometer's angle
|
||||||
|
- Velocity mode: Where tilting the accelerometer changes the speed the band moves at
|
||||||
|
When the goal position is reached, a new position is randomly selected
|
||||||
|
|
||||||
|
Press "A" to change the game mode.
|
||||||
|
Press "B" to start or stop the game mode.
|
||||||
|
Press "Boot" to invert the direction of the accelerometer tilt
|
||||||
|
*/
|
||||||
|
|
||||||
|
using namespace pimoroni;
|
||||||
|
using namespace plasma;
|
||||||
|
|
||||||
|
// Set how many LEDs you have
|
||||||
|
const uint N_LEDS = 30;
|
||||||
|
|
||||||
|
// How many times the LEDs will be updated per second
|
||||||
|
const uint UPDATES = 60;
|
||||||
|
|
||||||
|
// The sensitivity of the accelerometer input
|
||||||
|
constexpr float ANGLE_SENSITIVITY = 0.05f;
|
||||||
|
constexpr float VELOCITY_SENSITIVITY = 0.2f / UPDATES;
|
||||||
|
|
||||||
|
// The band colour hues to show in Angle mode
|
||||||
|
constexpr float ANGLE_MODE_GOAL_HUE = 0.333f;
|
||||||
|
constexpr float ANGLE_MODE_EDGE_HUE = 0.0f;
|
||||||
|
|
||||||
|
// The band colour hues to show in Velocity mode
|
||||||
|
constexpr float VELOCITY_MODE_GOAL_HUE = 0.667f;
|
||||||
|
constexpr float VELOCITY_MODE_EDGE_HUE = 1.0f;
|
||||||
|
|
||||||
|
// The width and colour settings for the band
|
||||||
|
constexpr float BAND_PIXEL_WIDTH = 2.0f;
|
||||||
|
constexpr float BAND_SATURATION = 1.0f;
|
||||||
|
constexpr float BAND_IN_GOAL_SATURATION = 0.5f;
|
||||||
|
constexpr float BAND_BRIGHTNESS = 1.0f;
|
||||||
|
|
||||||
|
// The width and colour settings for the goal
|
||||||
|
// Goal should be wider than the band by a small amount
|
||||||
|
constexpr float GOAL_PIXEL_WIDTH = BAND_PIXEL_WIDTH + 2.0f;
|
||||||
|
constexpr float GOAL_BRIGHTNESS = 0.1f;
|
||||||
|
|
||||||
|
// The percentage of the new angle (between 0.0 and 1.0) to apply to the last angle
|
||||||
|
// Has the effect of smoothing out the reading, at the cost of making it slower to react
|
||||||
|
constexpr float SMOOTHING_FACTOR = 0.1f;
|
||||||
|
|
||||||
|
|
||||||
|
// Pick *one* LED type by uncommenting the relevant line below:
|
||||||
|
|
||||||
|
// APA102-style LEDs with Data/Clock lines. AKA DotStar
|
||||||
|
//APA102 led_strip(N_LEDS, pio0, 0, plasma2040::DAT, plasma2040::CLK);
|
||||||
|
|
||||||
|
// WS28X-style LEDs with a single signal line. AKA NeoPixel
|
||||||
|
WS2812 led_strip(N_LEDS, pio0, 0, plasma2040::DAT);
|
||||||
|
|
||||||
|
|
||||||
|
Button user_sw(plasma2040::USER_SW, Polarity::ACTIVE_LOW, 0);
|
||||||
|
Button button_a(plasma2040::BUTTON_A, Polarity::ACTIVE_LOW, 0);
|
||||||
|
Button button_b(plasma2040::BUTTON_B, Polarity::ACTIVE_LOW, 0);
|
||||||
|
|
||||||
|
RGBLED led(plasma2040::LED_R, plasma2040::LED_G, plasma2040::LED_B);
|
||||||
|
|
||||||
|
I2C i2c(BOARD::PICO_EXPLORER);
|
||||||
|
BreakoutMSA301 msa(&i2c);
|
||||||
|
|
||||||
|
enum LEVEL_MODE {
|
||||||
|
ANGLE,
|
||||||
|
VELOCITY
|
||||||
|
};
|
||||||
|
|
||||||
|
// Maps a value from one range to another
|
||||||
|
float map(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows a band and goal with the given widths at the positions on the strip
|
||||||
|
void colour_band(float centre_position, float width, float goal_position, float goal_width, float hue) {
|
||||||
|
if((centre_position >= 0.0f) && (width > 0.0) && (goal_width > 0.0)) {
|
||||||
|
float band_pixels_start = centre_position - (width / 2);
|
||||||
|
float band_pixels_end = centre_position + (width / 2);
|
||||||
|
|
||||||
|
float goal_pixels_start = goal_position - (goal_width / 2);
|
||||||
|
float goal_pixels_end = goal_position + (goal_width / 2);
|
||||||
|
|
||||||
|
// Go through each led in the strip
|
||||||
|
uint i2;
|
||||||
|
float saturation, brightness, sat, val;
|
||||||
|
for(uint i = 0; i < led_strip.num_leds; i++) {
|
||||||
|
// Set saturation and brightness values for if the led is inside or outside of the goal
|
||||||
|
saturation = BAND_SATURATION;
|
||||||
|
brightness = 0.0f;
|
||||||
|
if((i >= goal_pixels_start) && (i < goal_pixels_end)) {
|
||||||
|
saturation = BAND_IN_GOAL_SATURATION;
|
||||||
|
brightness = GOAL_BRIGHTNESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2 = i + 1;
|
||||||
|
if(i2 <= band_pixels_end) {
|
||||||
|
if(i2 <= band_pixels_start) {
|
||||||
|
// Outside of the band
|
||||||
|
led_strip.set_hsv(i, hue, 0.0, brightness);
|
||||||
|
}
|
||||||
|
else if(i <= band_pixels_start) {
|
||||||
|
// Transition into the band
|
||||||
|
val = map(band_pixels_start, (float)i, (float)i2, BAND_BRIGHTNESS, brightness);
|
||||||
|
sat = map(band_pixels_start, (float)i, (float)i2, BAND_SATURATION, saturation);
|
||||||
|
led_strip.set_hsv(i, hue, sat, val);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Inside the band
|
||||||
|
led_strip.set_hsv(i, hue, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(i <= band_pixels_end) {
|
||||||
|
// Transition out of the band
|
||||||
|
val = map(band_pixels_end, (float)i, (float)i2, brightness, BAND_BRIGHTNESS);
|
||||||
|
sat = map(band_pixels_end, (float)i, (float)i2, saturation, BAND_SATURATION);
|
||||||
|
led_strip.set_hsv(i, hue, sat, val);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Outside of the band
|
||||||
|
led_strip.set_hsv(i, hue, 0.0, brightness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
stdio_init_all();
|
||||||
|
|
||||||
|
led_strip.start(UPDATES);
|
||||||
|
|
||||||
|
bool accel_detected = msa.init();
|
||||||
|
|
||||||
|
float band_position = 0.0f;
|
||||||
|
float goal_position = 0.0f;
|
||||||
|
float measured_angle = 0.0f;
|
||||||
|
bool invert = false;
|
||||||
|
bool game_mode = false;
|
||||||
|
|
||||||
|
LEVEL_MODE mode = LEVEL_MODE::ANGLE;
|
||||||
|
while(true) {
|
||||||
|
if(accel_detected) {
|
||||||
|
// Read the x and y axes of the accelerometer
|
||||||
|
float x = msa.get_x_axis();
|
||||||
|
float y = msa.get_y_axis();
|
||||||
|
|
||||||
|
// Convert those values to an angle in degrees, and invert if selected
|
||||||
|
float new_measured_angle = (atan2(x, -y) * 180.0f) / M_PI;
|
||||||
|
if(invert)
|
||||||
|
new_measured_angle = -new_measured_angle;
|
||||||
|
printf("Angle: %f deg\n", new_measured_angle);
|
||||||
|
|
||||||
|
// Smooth out the measured angle
|
||||||
|
measured_angle = ((new_measured_angle - measured_angle) * SMOOTHING_FACTOR) + measured_angle;
|
||||||
|
|
||||||
|
float hue = 0.0;
|
||||||
|
float position_diff;
|
||||||
|
switch(mode) {
|
||||||
|
case LEVEL_MODE::ANGLE:
|
||||||
|
// Apply the measured angle directly to the band position, clamping it between -1 and +1
|
||||||
|
band_position = measured_angle * ANGLE_SENSITIVITY;
|
||||||
|
band_position = std::min(1.0f, std::max(-1.0f, band_position));
|
||||||
|
|
||||||
|
// Convert the difference between the band and goal positions into a colour hue
|
||||||
|
position_diff = std::min(abs(band_position - goal_position), 1.0f);
|
||||||
|
hue = map(position_diff, 0.0f, 1.0f, ANGLE_MODE_GOAL_HUE, ANGLE_MODE_EDGE_HUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LEVEL_MODE::VELOCITY:
|
||||||
|
// Apply the measured angle as a velocity to the band position, clamping it between -1 and +1
|
||||||
|
band_position += measured_angle * VELOCITY_SENSITIVITY;
|
||||||
|
band_position = std::min(1.0f, std::max(-1.0f, band_position));
|
||||||
|
|
||||||
|
// Convert the difference between the band and goal positions into a colour hue
|
||||||
|
position_diff = std::min(abs(band_position - goal_position), 1.0f);
|
||||||
|
hue = map(position_diff, 0.0f, 1.0f, VELOCITY_MODE_GOAL_HUE, VELOCITY_MODE_EDGE_HUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the band and goal positions to positions on the LED strip
|
||||||
|
float strip_band_position = map(band_position, -1.0f, 1.0f, 0.0f, float(led_strip.num_leds));
|
||||||
|
float strip_goal_position = map(goal_position, -1.0f, 1.0f, 0.0f, float(led_strip.num_leds));
|
||||||
|
|
||||||
|
// Draw the band and goal
|
||||||
|
colour_band(strip_band_position, BAND_PIXEL_WIDTH, strip_goal_position, GOAL_PIXEL_WIDTH, hue);
|
||||||
|
|
||||||
|
bool sw_pressed = user_sw.read();
|
||||||
|
bool a_pressed = button_a.read();
|
||||||
|
bool b_pressed = button_b.read();
|
||||||
|
|
||||||
|
if(b_pressed)
|
||||||
|
game_mode = !game_mode;
|
||||||
|
|
||||||
|
if(sw_pressed)
|
||||||
|
invert = !invert;
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case ANGLE:
|
||||||
|
if(game_mode)
|
||||||
|
led.set_rgb(255, 255, 0);
|
||||||
|
else
|
||||||
|
led.set_rgb(0, 255, 0);
|
||||||
|
if(a_pressed)
|
||||||
|
mode = VELOCITY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VELOCITY:
|
||||||
|
if(game_mode)
|
||||||
|
led.set_rgb(255, 0, 255);
|
||||||
|
else
|
||||||
|
led.set_rgb(0, 0, 255);
|
||||||
|
if(a_pressed)
|
||||||
|
mode = ANGLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(game_mode) {
|
||||||
|
// Check if the band is within the goal, and if so, set a new goal
|
||||||
|
bool above_lower = strip_band_position >= strip_goal_position - (GOAL_PIXEL_WIDTH - BAND_PIXEL_WIDTH) / 2;
|
||||||
|
bool below_upper = strip_band_position <= strip_goal_position + (GOAL_PIXEL_WIDTH - BAND_PIXEL_WIDTH) / 2;
|
||||||
|
if(above_lower && below_upper)
|
||||||
|
goal_position = map((float)rand(), 0.0f, (float)RAND_MAX, -1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sleep time controls the rate at which the LED buffer is updated
|
||||||
|
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
||||||
|
sleep_ms(1000 / UPDATES);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
set(OUTPUT_NAME plasma2040_monitor)
|
||||||
|
add_executable(${OUTPUT_NAME} plasma2040_monitor.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(${OUTPUT_NAME}
|
||||||
|
pico_stdlib
|
||||||
|
plasma2040
|
||||||
|
bme68x
|
||||||
|
hardware_i2c
|
||||||
|
pimoroni_i2c
|
||||||
|
rgbled
|
||||||
|
button
|
||||||
|
)
|
||||||
|
|
||||||
|
# enable usb output
|
||||||
|
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||||
|
|
||||||
|
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,188 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "plasma2040.hpp"
|
||||||
|
|
||||||
|
#include "common/pimoroni_common.hpp"
|
||||||
|
#include "bme68x.hpp"
|
||||||
|
#include "rgbled.hpp"
|
||||||
|
#include "button.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Uses a BME68x to monitor the ambient temperature, pressure and humidity, and show them as bars on an LED strip.
|
||||||
|
Press "A" to cycle to the next mode.
|
||||||
|
Press "B" to cycle to the previous mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using namespace pimoroni;
|
||||||
|
using namespace plasma;
|
||||||
|
|
||||||
|
// Set how many LEDs you have
|
||||||
|
const uint N_LEDS = 30;
|
||||||
|
|
||||||
|
// How many times the LEDs will be updated per second
|
||||||
|
const uint UPDATES = 60;
|
||||||
|
|
||||||
|
// The temperature range to show (in degrees celsius)
|
||||||
|
constexpr float TEMPERATURE_C_MIN = 20.0f;
|
||||||
|
constexpr float TEMPERATURE_C_MAX = 35.0f;
|
||||||
|
|
||||||
|
// The pressure range to show (in pascals)
|
||||||
|
constexpr float PRESSURE_PA_MIN = 87000.0f;
|
||||||
|
constexpr float PRESSURE_PA_MAX = 108500.0f;
|
||||||
|
|
||||||
|
// The humidity range to show (in percent)
|
||||||
|
constexpr float HUMIDITY_MIN = 0.0f;
|
||||||
|
constexpr float HUMIDITY_MAX = 100.0f;
|
||||||
|
|
||||||
|
|
||||||
|
// The start and end hues for the temperature range
|
||||||
|
constexpr float TEMPERATURE_HUE_START = 0.667f;
|
||||||
|
constexpr float TEMPERATURE_HUE_END = 1.0f;
|
||||||
|
|
||||||
|
// The start and end hues for the pressure range
|
||||||
|
constexpr float PRESSURE_HUE_START = 0.333f;
|
||||||
|
constexpr float PRESSURE_HUE_END = 0.0f;
|
||||||
|
|
||||||
|
// The start and end hues for the humidity range
|
||||||
|
constexpr float HUMIDITY_HUE_START = 0.333f;
|
||||||
|
constexpr float HUMIDITY_HUE_END = 0.667f;
|
||||||
|
|
||||||
|
|
||||||
|
// Pick *one* LED type by uncommenting the relevant line below:
|
||||||
|
|
||||||
|
// APA102-style LEDs with Data/Clock lines. AKA DotStar
|
||||||
|
//APA102 led_strip(N_LEDS, pio0, 0, plasma2040::DAT, plasma2040::CLK);
|
||||||
|
|
||||||
|
// WS28X-style LEDs with a single signal line. AKA NeoPixel
|
||||||
|
WS2812 led_strip(N_LEDS, pio0, 0, plasma2040::DAT);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Button button_a(plasma2040::BUTTON_A, ACTIVE_LOW, 0);
|
||||||
|
Button button_b(plasma2040::BUTTON_B, ACTIVE_LOW, 0);
|
||||||
|
|
||||||
|
RGBLED led(plasma2040::LED_R, plasma2040::LED_G, plasma2040::LED_B);
|
||||||
|
|
||||||
|
I2C i2c(BOARD::PICO_EXPLORER);
|
||||||
|
BME68X bme68x(&i2c);
|
||||||
|
|
||||||
|
enum DisplayMode {
|
||||||
|
ALL,
|
||||||
|
TEMPERATURE,
|
||||||
|
PRESSURE,
|
||||||
|
HUMIDITY
|
||||||
|
};
|
||||||
|
|
||||||
|
// Maps a value from one range to another
|
||||||
|
float map(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets a section of the led strip to show a hue gradient based on the provided percent
|
||||||
|
void colour_gauge(float percent, uint start_led, uint end_led, float start_hue, float end_hue) {
|
||||||
|
if(end_led > start_led) {
|
||||||
|
uint range = end_led - start_led;
|
||||||
|
float light_pixels = percent * range;
|
||||||
|
|
||||||
|
for(uint i = 0; i < range; i++) {
|
||||||
|
float h = map(i, 0.0f, (float)range - 1, start_hue, end_hue);
|
||||||
|
|
||||||
|
uint i2 = i + 1;
|
||||||
|
if(i2 <= light_pixels) {
|
||||||
|
led_strip.set_hsv(i + start_led, h, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
else if(i <= light_pixels) {
|
||||||
|
float scale = map(light_pixels, (float)i, (float)i2, 0.0f, 1.0f);
|
||||||
|
led_strip.set_hsv(i + start_led, h, 1.0f, scale);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
led_strip.set_hsv(i + start_led, 0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
stdio_init_all();
|
||||||
|
|
||||||
|
led_strip.start(UPDATES);
|
||||||
|
|
||||||
|
bool bme_detected = bme68x.init();
|
||||||
|
|
||||||
|
|
||||||
|
uint first_third = led_strip.num_leds / 3;
|
||||||
|
uint second_third = (led_strip.num_leds * 2) / 3;
|
||||||
|
|
||||||
|
float t = 0.0f;
|
||||||
|
DisplayMode mode = DisplayMode::ALL;
|
||||||
|
while(true) {
|
||||||
|
if(bme_detected) {
|
||||||
|
bme68x_data data;
|
||||||
|
|
||||||
|
auto result = bme68x.read_forced(&data);
|
||||||
|
(void)result;
|
||||||
|
|
||||||
|
printf("%.2fc, %.2fPa, %.2f%%\n", data.temperature, data.pressure, data.humidity);
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case DisplayMode::ALL:
|
||||||
|
t = map(data.temperature, TEMPERATURE_C_MIN, TEMPERATURE_C_MAX, 0.0f, 1.0f);
|
||||||
|
colour_gauge(t, 0, first_third, TEMPERATURE_HUE_START, TEMPERATURE_HUE_END);
|
||||||
|
|
||||||
|
t = map(data.pressure, PRESSURE_PA_MIN, PRESSURE_PA_MAX, 0.0f, 1.0f);
|
||||||
|
colour_gauge(t, first_third, second_third, PRESSURE_HUE_START, PRESSURE_HUE_END);
|
||||||
|
|
||||||
|
t = map(data.humidity, HUMIDITY_MIN, HUMIDITY_MAX, 0.0f, 1.0f);
|
||||||
|
colour_gauge(t, second_third, led_strip.num_leds, HUMIDITY_HUE_START, HUMIDITY_HUE_END);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisplayMode::TEMPERATURE:
|
||||||
|
t = map(data.temperature, TEMPERATURE_C_MIN, TEMPERATURE_C_MAX, 0.0f, 1.0f);
|
||||||
|
colour_gauge(t, 0, led_strip.num_leds, TEMPERATURE_HUE_START, TEMPERATURE_HUE_END);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisplayMode::PRESSURE:
|
||||||
|
t = map(data.pressure, PRESSURE_PA_MIN, PRESSURE_PA_MAX, 0.0f, 1.0f);
|
||||||
|
colour_gauge(t, 0, led_strip.num_leds, PRESSURE_HUE_START, PRESSURE_HUE_END);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisplayMode::HUMIDITY:
|
||||||
|
t = map(data.humidity, HUMIDITY_MIN, HUMIDITY_MAX, 0.0f, 1.0f);
|
||||||
|
colour_gauge(t, 0, led_strip.num_leds, HUMIDITY_HUE_START, HUMIDITY_HUE_END);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool a_pressed = button_a.read();
|
||||||
|
bool b_pressed = button_b.read();
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case DisplayMode::ALL:
|
||||||
|
led.set_rgb(127, 127, 127);
|
||||||
|
if(a_pressed) mode = DisplayMode::TEMPERATURE;
|
||||||
|
else if(b_pressed) mode = DisplayMode::HUMIDITY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisplayMode::TEMPERATURE:
|
||||||
|
led.set_rgb(255, 0, 255);
|
||||||
|
if(a_pressed) mode = DisplayMode::PRESSURE;
|
||||||
|
else if(b_pressed) mode = DisplayMode::ALL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisplayMode::PRESSURE:
|
||||||
|
led.set_rgb(255, 255, 0);
|
||||||
|
if(a_pressed) mode = DisplayMode::HUMIDITY;
|
||||||
|
else if(b_pressed) mode = DisplayMode::TEMPERATURE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisplayMode::HUMIDITY:
|
||||||
|
led.set_rgb(0, 255, 255);
|
||||||
|
if(a_pressed) mode = DisplayMode::ALL;
|
||||||
|
else if(b_pressed) mode = DisplayMode::PRESSURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,46 +47,46 @@ Analog sense(plasma2040::CURRENT_SENSE, plasma2040::ADC_GAIN, plasma2040::SHUNT_
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
led_strip.start(UPDATES);
|
led_strip.start(UPDATES);
|
||||||
|
|
||||||
int speed = DEFAULT_SPEED;
|
int speed = DEFAULT_SPEED;
|
||||||
float offset = 0.0f;
|
float offset = 0.0f;
|
||||||
|
|
||||||
uint count = 0;
|
uint count = 0;
|
||||||
while (true) {
|
while(true) {
|
||||||
bool sw = user_sw.read();
|
bool sw_pressed = user_sw.read();
|
||||||
bool a = button_a.read();
|
bool a_pressed = button_a.read();
|
||||||
bool b = button_b.read();
|
bool b_pressed = button_b.read();
|
||||||
|
|
||||||
if(sw) {
|
if(sw_pressed) {
|
||||||
speed = DEFAULT_SPEED;
|
speed = DEFAULT_SPEED;
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(a) speed--;
|
|
||||||
if(b) speed++;
|
|
||||||
}
|
|
||||||
speed = std::min((int)255, std::max((int)1, speed));
|
|
||||||
|
|
||||||
offset += float(speed) / 2000.0f;
|
|
||||||
|
|
||||||
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
|
||||||
float hue = float(i) / led_strip.num_leds;
|
|
||||||
led_strip.set_hsv(i, hue + offset, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
led.set_rgb(speed, 0, 255 - speed);
|
|
||||||
|
|
||||||
count += 1;
|
|
||||||
if(count >= UPDATES) {
|
|
||||||
// Display the current value once every second
|
|
||||||
printf("Current = %f A\n", sense.read_current());
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sleep time controls the rate at which the LED buffer is updated
|
|
||||||
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
|
||||||
sleep_ms(1000 / UPDATES);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if(a_pressed) speed--;
|
||||||
|
if(b_pressed) speed++;
|
||||||
|
}
|
||||||
|
speed = std::min((int)255, std::max((int)1, speed));
|
||||||
|
|
||||||
|
offset += float(speed) / 2000.0f;
|
||||||
|
|
||||||
|
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||||
|
float hue = float(i) / led_strip.num_leds;
|
||||||
|
led_strip.set_hsv(i, hue + offset, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
led.set_rgb(speed, 0, 255 - speed);
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
if(count >= UPDATES) {
|
||||||
|
// Display the current value once every second
|
||||||
|
printf("Current = %f A\n", sense.read_current());
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sleep time controls the rate at which the LED buffer is updated
|
||||||
|
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
||||||
|
sleep_ms(1000 / UPDATES);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,34 @@
|
||||||
#include "rgbled.hpp"
|
#include "rgbled.hpp"
|
||||||
#include "button.hpp"
|
#include "button.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Press "B" to enable cycling.
|
||||||
|
Press "A" to change the encoder mode.
|
||||||
|
Press "Boot" to reset the effects back to default.
|
||||||
|
*/
|
||||||
|
|
||||||
using namespace pimoroni;
|
using namespace pimoroni;
|
||||||
using namespace plasma;
|
using namespace plasma;
|
||||||
|
|
||||||
// Set how many LEDs you have
|
// Set how many LEDs you have
|
||||||
const uint N_LEDS = 30;
|
const uint N_LEDS = 30;
|
||||||
|
|
||||||
|
// The speed that the LEDs will start cycling at
|
||||||
|
const int16_t DEFAULT_SPEED = 20;
|
||||||
|
|
||||||
|
// The hue (in degrees) that the LEDs will start at
|
||||||
|
const int16_t DEFAULT_HUE = 0;
|
||||||
|
|
||||||
|
// The angle (in degrees) from the hue, that the LEDs will end at
|
||||||
|
const int16_t DEFAULT_ANGLE = 120;
|
||||||
|
|
||||||
|
// The brightness (between 0 and 31) to set the LEDs to
|
||||||
|
const int16_t DEFAULT_BRIGHTNESS = 16;
|
||||||
|
|
||||||
// How many times the LEDs will be updated per second
|
// How many times the LEDs will be updated per second
|
||||||
const uint UPDATES = 60;
|
const uint UPDATES = 60;
|
||||||
|
|
||||||
|
|
||||||
// Pick *one* LED type by uncommenting the relevant line below:
|
// Pick *one* LED type by uncommenting the relevant line below:
|
||||||
|
|
||||||
// APA102-style LEDs with Data/Clock lines. AKA DotStar
|
// APA102-style LEDs with Data/Clock lines. AKA DotStar
|
||||||
|
@ -29,9 +48,9 @@ const uint UPDATES = 60;
|
||||||
WS2812 led_strip(N_LEDS, pio0, 0, plasma2040::DAT);
|
WS2812 led_strip(N_LEDS, pio0, 0, plasma2040::DAT);
|
||||||
|
|
||||||
|
|
||||||
|
Button user_sw(plasma2040::USER_SW, Polarity::ACTIVE_LOW, 0);
|
||||||
Button button_a(plasma2040::BUTTON_A);
|
Button button_a(plasma2040::BUTTON_A, Polarity::ACTIVE_LOW, 0);
|
||||||
Button button_b(plasma2040::BUTTON_B);
|
Button button_b(plasma2040::BUTTON_B, Polarity::ACTIVE_LOW, 0);
|
||||||
|
|
||||||
RGBLED led(plasma2040::LED_R, plasma2040::LED_G, plasma2040::LED_B);
|
RGBLED led(plasma2040::LED_R, plasma2040::LED_G, plasma2040::LED_B);
|
||||||
|
|
||||||
|
@ -39,118 +58,161 @@ I2C i2c(BOARD::PICO_EXPLORER);
|
||||||
BreakoutEncoder enc(&i2c);
|
BreakoutEncoder enc(&i2c);
|
||||||
|
|
||||||
enum ENCODER_MODE {
|
enum ENCODER_MODE {
|
||||||
COLOUR,
|
COLOUR,
|
||||||
ANGLE,
|
ANGLE,
|
||||||
BRIGHTNESS,
|
BRIGHTNESS,
|
||||||
TIME
|
SPEED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float wrap(float v, float min, float max) {
|
||||||
|
if(v <= min)
|
||||||
|
v += (max - min);
|
||||||
|
|
||||||
|
if(v > max)
|
||||||
|
v -= (max - min);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void colour_cycle(float hue, float t, float angle) {
|
void colour_cycle(float hue, float t, float angle) {
|
||||||
t /= 200.0f;
|
t /= 200.0f;
|
||||||
|
|
||||||
for (auto i = 0u; i < led_strip.num_leds; ++i) {
|
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||||
float offset = (M_PI * i) / led_strip.num_leds;
|
float percent_along = (float)i / led_strip.num_leds;
|
||||||
offset = sinf(offset + t) * angle;
|
float offset = sinf((percent_along + 0.5f + t) * M_PI) * angle;
|
||||||
led_strip.set_hsv(i, (hue + offset) / 360.0f, 1.0f, 1.0f);
|
float h = wrap((hue + offset) / 360.0f, 0.0f, 1.0f);
|
||||||
}
|
led_strip.set_hsv(i, h, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gauge(uint v, uint vmax = 100) {
|
void speed_gauge(uint v, uint vmax = 100) {
|
||||||
uint light_pixels = led_strip.num_leds * v / vmax;
|
uint light_pixels = led_strip.num_leds * v / vmax;
|
||||||
|
|
||||||
for (auto i = 0u; i < led_strip.num_leds; ++i) {
|
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||||
if(i < light_pixels) {
|
if(i < light_pixels) {
|
||||||
led_strip.set_rgb(i, 0, 255, 0);
|
led_strip.set_rgb(i, 0, 255, 0);
|
||||||
} else {
|
|
||||||
led_strip.set_rgb(i, 255, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
led_strip.set_rgb(i, 255, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void brightness_gauge(uint v, uint vmax = 100) {
|
||||||
|
uint light_pixels = led_strip.num_leds * v / vmax;
|
||||||
|
|
||||||
|
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||||
|
if(i < light_pixels) {
|
||||||
|
led_strip.set_rgb(i, 64, 64, 64);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
led_strip.set_rgb(i, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
led_strip.start(UPDATES);
|
led_strip.start(UPDATES);
|
||||||
|
|
||||||
bool encoder_detected = enc.init();
|
bool encoder_detected = enc.init();
|
||||||
enc.clear_interrupt_flag();
|
enc.clear_interrupt_flag();
|
||||||
|
|
||||||
int speed = 50;
|
//Initialise the default values
|
||||||
float hue = 0;
|
int16_t speed = DEFAULT_SPEED;
|
||||||
int angle = 120;
|
int16_t hue = DEFAULT_HUE;
|
||||||
int8_t brightness = 16;
|
int16_t angle = DEFAULT_ANGLE;
|
||||||
bool cycle = true;
|
int16_t brightness = DEFAULT_BRIGHTNESS;
|
||||||
ENCODER_MODE mode = ENCODER_MODE::COLOUR;
|
|
||||||
while (true) {
|
|
||||||
uint32_t t = millis();
|
|
||||||
if(encoder_detected) {
|
|
||||||
if(enc.get_interrupt_flag()) {
|
|
||||||
int count = enc.read();
|
|
||||||
enc.clear_interrupt_flag();
|
|
||||||
enc.clear();
|
|
||||||
|
|
||||||
cycle = false;
|
bool cycle = true;
|
||||||
switch(mode) {
|
ENCODER_MODE mode = ENCODER_MODE::COLOUR;
|
||||||
case ENCODER_MODE::COLOUR:
|
uint32_t start_time = millis();
|
||||||
hue += count;
|
while(true) {
|
||||||
brightness = std::min((int8_t)359, brightness);
|
uint32_t t = millis() - start_time;
|
||||||
brightness = std::max((int8_t)0, brightness);
|
if(encoder_detected) {
|
||||||
colour_cycle(hue, 0, (float)angle);
|
if(enc.get_interrupt_flag()) {
|
||||||
break;
|
int16_t count = enc.read();
|
||||||
case ENCODER_MODE::ANGLE:
|
enc.clear_interrupt_flag();
|
||||||
angle += count;
|
enc.clear();
|
||||||
angle = std::min((int)359, angle);
|
|
||||||
angle = std::max((int)0, angle);
|
|
||||||
colour_cycle(hue, 0, (float)angle);
|
|
||||||
break;
|
|
||||||
case ENCODER_MODE::BRIGHTNESS:
|
|
||||||
brightness += count;
|
|
||||||
brightness = std::min((int8_t)31, brightness);
|
|
||||||
brightness = std::max((int8_t)0, brightness);
|
|
||||||
led_strip.set_brightness(brightness);
|
|
||||||
gauge(brightness, 31);
|
|
||||||
break;
|
|
||||||
case ENCODER_MODE::TIME:
|
|
||||||
speed += count;
|
|
||||||
speed = std::min((int)100, speed);
|
|
||||||
speed = std::max((int)0, speed);
|
|
||||||
gauge(speed, 100);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool a_pressed = button_a.read();
|
|
||||||
bool b_pressed = button_b.read();
|
|
||||||
|
|
||||||
if(b_pressed) cycle = true;
|
|
||||||
|
|
||||||
|
cycle = false;
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
case ENCODER_MODE::COLOUR:
|
case ENCODER_MODE::COLOUR:
|
||||||
led.set_rgb(255, 0, 0);
|
hue += count;
|
||||||
if(a_pressed) mode = ENCODER_MODE::ANGLE;
|
hue = std::min((int16_t)359, std::max((int16_t)0, hue));
|
||||||
break;
|
colour_cycle((float)hue, 0, (float)angle);
|
||||||
case ENCODER_MODE::ANGLE:
|
break;
|
||||||
led.set_rgb(255, 255, 0);
|
|
||||||
if(a_pressed) mode = ENCODER_MODE::BRIGHTNESS;
|
case ENCODER_MODE::ANGLE:
|
||||||
break;
|
angle += count;
|
||||||
case ENCODER_MODE::BRIGHTNESS:
|
angle = std::min((int16_t)359, std::max((int16_t)0, angle));
|
||||||
led.set_rgb(0, 255, 0);
|
colour_cycle((float)hue, 0, (float)angle);
|
||||||
if(a_pressed) mode = ENCODER_MODE::TIME;
|
break;
|
||||||
break;
|
|
||||||
case ENCODER_MODE::TIME:
|
case ENCODER_MODE::BRIGHTNESS:
|
||||||
led.set_rgb(0, 0, 255);
|
brightness += count;
|
||||||
if(a_pressed) mode = ENCODER_MODE::COLOUR;
|
brightness = std::min((int16_t)31, std::max((int16_t)0, brightness));
|
||||||
break;
|
led_strip.set_brightness((uint8_t)brightness);
|
||||||
|
brightness_gauge(brightness, 31);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENCODER_MODE::SPEED:
|
||||||
|
speed += count;
|
||||||
|
speed = std::min((int16_t)100, std::max((int16_t)0, speed));
|
||||||
|
speed_gauge(speed, 100);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if(cycle) colour_cycle(hue, t * speed / 100, (float)angle);
|
|
||||||
|
|
||||||
auto first_led = led_strip.get(0);
|
|
||||||
enc.set_led(first_led.r, first_led.g, first_led.b);
|
|
||||||
|
|
||||||
// Sleep time controls the rate at which the LED buffer is updated
|
|
||||||
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
|
||||||
sleep_ms(1000 / UPDATES);
|
|
||||||
}
|
}
|
||||||
|
bool sw_pressed = user_sw.read();
|
||||||
|
bool a_pressed = button_a.read();
|
||||||
|
bool b_pressed = button_b.read();
|
||||||
|
|
||||||
|
if(sw_pressed) {
|
||||||
|
speed = DEFAULT_SPEED;
|
||||||
|
hue = DEFAULT_HUE;
|
||||||
|
angle = DEFAULT_ANGLE;
|
||||||
|
brightness = DEFAULT_BRIGHTNESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b_pressed) {
|
||||||
|
if(!cycle)
|
||||||
|
start_time = millis();
|
||||||
|
cycle = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case ENCODER_MODE::COLOUR:
|
||||||
|
led.set_rgb(255, 0, 0);
|
||||||
|
if(a_pressed) mode = ENCODER_MODE::ANGLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENCODER_MODE::ANGLE:
|
||||||
|
led.set_rgb(255, 255, 0);
|
||||||
|
if(a_pressed) mode = ENCODER_MODE::BRIGHTNESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENCODER_MODE::BRIGHTNESS:
|
||||||
|
led.set_rgb(0, 255, 0);
|
||||||
|
if(a_pressed) mode = ENCODER_MODE::SPEED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENCODER_MODE::SPEED:
|
||||||
|
led.set_rgb(0, 0, 255);
|
||||||
|
if(a_pressed) mode = ENCODER_MODE::COLOUR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cycle)
|
||||||
|
colour_cycle(hue, (float)(t * speed) / 100.0f, (float)angle);
|
||||||
|
|
||||||
|
auto mid_led = led_strip.get(led_strip.num_leds / 2);
|
||||||
|
enc.set_led(mid_led.r, mid_led.g, mid_led.b);
|
||||||
|
|
||||||
|
// Sleep time controls the rate at which the LED buffer is updated
|
||||||
|
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
||||||
|
sleep_ms(1000 / UPDATES);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
import plasma
|
||||||
|
from plasma import plasma2040
|
||||||
|
import time
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Import helpers for RGB LEDs and Buttons
|
||||||
|
from pimoroni import RGBLED, Button
|
||||||
|
|
||||||
|
# Import msa301 and I2C helper
|
||||||
|
from breakout_msa301 import BreakoutMSA301
|
||||||
|
from pimoroni_i2c import PimoroniI2C
|
||||||
|
|
||||||
|
# A simple balancing game, where you use the MSA301 accelerometer to line up a band with a goal on the strip.
|
||||||
|
# This can either be done using:
|
||||||
|
# - Angle mode: Where position on the strip directly matches the accelerometer's angle
|
||||||
|
# - Velocity mode: Where tilting the accelerometer changes the speed the band moves at
|
||||||
|
# When the goal position is reached, a new position is randomly selected
|
||||||
|
|
||||||
|
# Press "A" to change the game mode.
|
||||||
|
# Press "B" to start or stop the game mode.
|
||||||
|
# Press "Boot" to invert the direction of the accelerometer tilt
|
||||||
|
|
||||||
|
# Set how many LEDs you have
|
||||||
|
NUM_LEDS = 30
|
||||||
|
|
||||||
|
# How many times the LEDs will be updated per second
|
||||||
|
UPDATES = 60
|
||||||
|
|
||||||
|
# The sensitivity of the accelerometer input
|
||||||
|
ANGLE_SENSITIVITY = 0.05
|
||||||
|
VELOCITY_SENSITIVITY = 0.2 / UPDATES
|
||||||
|
|
||||||
|
# The band colour hues to show in Angle mode
|
||||||
|
ANGLE_MODE_GOAL_HUE = 0.333
|
||||||
|
ANGLE_MODE_EDGE_HUE = 0.0
|
||||||
|
|
||||||
|
# The band colour hues to show in Velocity mode
|
||||||
|
VELOCITY_MODE_GOAL_HUE = 0.667
|
||||||
|
VELOCITY_MODE_EDGE_HUE = 1.0
|
||||||
|
|
||||||
|
# The width and colour settings for the band
|
||||||
|
BAND_PIXEL_WIDTH = 2.0
|
||||||
|
BAND_SATURATION = 1.0
|
||||||
|
BAND_IN_GOAL_SATURATION = 0.5
|
||||||
|
BAND_BRIGHTNESS = 1.0
|
||||||
|
|
||||||
|
# The width and colour settings for the goal
|
||||||
|
# Goal should be wider than the band by a small amount
|
||||||
|
GOAL_PIXEL_WIDTH = BAND_PIXEL_WIDTH + 2.0
|
||||||
|
GOAL_BRIGHTNESS = 0.1
|
||||||
|
|
||||||
|
# The percentage of the new angle (between 0.0 and 1.0) to apply to the last angle
|
||||||
|
# Has the effect of smoothing out the reading, at the cost of making it slower to react
|
||||||
|
SMOOTHING_FACTOR = 0.1
|
||||||
|
|
||||||
|
|
||||||
|
# Pick *one* LED type by uncommenting the relevant line below:
|
||||||
|
|
||||||
|
# APA102 / DotStar™ LEDs
|
||||||
|
led_strip = plasma.APA102(NUM_LEDS, 0, 0, plasma2040.DAT, plasma2040.CLK)
|
||||||
|
|
||||||
|
# WS2812 / NeoPixel™ LEDs
|
||||||
|
# led_strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma2040.DAT)
|
||||||
|
|
||||||
|
user_sw = Button(plasma2040.USER_SW, repeat_time=0)
|
||||||
|
button_a = Button(plasma2040.BUTTON_A, repeat_time=0)
|
||||||
|
button_b = Button(plasma2040.BUTTON_B, repeat_time=0)
|
||||||
|
led = RGBLED(plasma2040.LED_R, plasma2040.LED_G, plasma2040.LED_B)
|
||||||
|
|
||||||
|
PINS_PLASMA2040 = {"sda": plasma2040.SDA, "scl": plasma2040.SCL}
|
||||||
|
|
||||||
|
i2c = PimoroniI2C(**PINS_PLASMA2040)
|
||||||
|
msa = BreakoutMSA301(i2c)
|
||||||
|
|
||||||
|
|
||||||
|
ANGLE, VELOCITY = range(2)
|
||||||
|
|
||||||
|
|
||||||
|
# Maps a value from one range to another
|
||||||
|
def map(x, in_min, in_max, out_min, out_max):
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
|
||||||
|
|
||||||
|
|
||||||
|
# Shows a band and goal with the given widths at the positions on the strip
|
||||||
|
def colour_band(centre_position, width, goal_position, goal_width, hue):
|
||||||
|
if centre_position >= 0.0 and width > 0.0 and goal_width > 0.0:
|
||||||
|
band_pixels_start = centre_position - (width / 2)
|
||||||
|
band_pixels_end = centre_position + (width / 2)
|
||||||
|
|
||||||
|
goal_pixels_start = goal_position - (goal_width / 2)
|
||||||
|
goal_pixels_end = goal_position + (goal_width / 2)
|
||||||
|
|
||||||
|
# Go through each led in the strip
|
||||||
|
for i in range(NUM_LEDS):
|
||||||
|
# Set saturation and brightness values for if the led is inside or outside of the goal
|
||||||
|
saturation = BAND_SATURATION
|
||||||
|
brightness = 0.0
|
||||||
|
if i >= goal_pixels_start and i < goal_pixels_end:
|
||||||
|
saturation = BAND_IN_GOAL_SATURATION
|
||||||
|
brightness = GOAL_BRIGHTNESS
|
||||||
|
|
||||||
|
i2 = i + 1
|
||||||
|
if i2 <= band_pixels_end:
|
||||||
|
if i2 <= band_pixels_start:
|
||||||
|
# Outside of the band
|
||||||
|
led_strip.set_hsv(i, hue, 0.0, brightness)
|
||||||
|
elif i <= band_pixels_start:
|
||||||
|
# Transition into the band
|
||||||
|
val = map(band_pixels_start, float(i), float(i2), BAND_BRIGHTNESS, brightness)
|
||||||
|
sat = map(band_pixels_start, float(i), float(i2), BAND_SATURATION, saturation)
|
||||||
|
led_strip.set_hsv(i, hue, sat, val)
|
||||||
|
else:
|
||||||
|
# Inside the band
|
||||||
|
led_strip.set_hsv(i, hue, 1.0, 1.0)
|
||||||
|
|
||||||
|
elif i <= band_pixels_end:
|
||||||
|
# Transition out of the band
|
||||||
|
val = map(band_pixels_end, float(i), float(i2), brightness, BAND_BRIGHTNESS)
|
||||||
|
sat = map(band_pixels_end, float(i), float(i2), saturation, BAND_SATURATION)
|
||||||
|
led_strip.set_hsv(i, hue, sat, val)
|
||||||
|
else:
|
||||||
|
# Outside of the band
|
||||||
|
led_strip.set_hsv(i, hue, 0.0, brightness)
|
||||||
|
|
||||||
|
|
||||||
|
mode = ANGLE
|
||||||
|
|
||||||
|
goal_position = 0.0
|
||||||
|
measured_angle = 0.0
|
||||||
|
invert = False
|
||||||
|
game_mode = False
|
||||||
|
|
||||||
|
# Start updating the LED strip
|
||||||
|
led_strip.start()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Read the x and y axes of the accelerometer
|
||||||
|
x = msa.get_x_axis()
|
||||||
|
y = msa.get_y_axis()
|
||||||
|
|
||||||
|
# Convert those values to an angle in degrees, and invert if selected
|
||||||
|
new_measured_angle = (math.atan2(x, -y) * 180.0) / math.pi
|
||||||
|
if invert:
|
||||||
|
new_measured_angle = -new_measured_angle
|
||||||
|
print("Angle:", new_measured_angle, "deg")
|
||||||
|
|
||||||
|
# Smooth out the measured angle
|
||||||
|
measured_angle = ((new_measured_angle - measured_angle) * SMOOTHING_FACTOR) + measured_angle
|
||||||
|
|
||||||
|
if mode == ANGLE:
|
||||||
|
# Apply the measured angle directly to the band position, clamping it between -1 and +1
|
||||||
|
band_position = measured_angle * ANGLE_SENSITIVITY
|
||||||
|
band_position = min(1.0, max(-1.0, band_position))
|
||||||
|
|
||||||
|
# Convert the difference between the band and goal positions into a colour hue
|
||||||
|
position_diff = min(abs(band_position - goal_position), 1.0)
|
||||||
|
hue = map(position_diff, 0.0, 1.0, ANGLE_MODE_GOAL_HUE, ANGLE_MODE_EDGE_HUE)
|
||||||
|
|
||||||
|
elif mode == VELOCITY:
|
||||||
|
# Apply the measured angle as a velocity to the band position, clamping it between -1 and +1
|
||||||
|
band_position += measured_angle * VELOCITY_SENSITIVITY
|
||||||
|
band_position = min(1.0, max(-1.0, band_position))
|
||||||
|
|
||||||
|
# Convert the difference between the band and goal positions into a colour hue
|
||||||
|
position_diff = min(abs(band_position - goal_position), 1.0)
|
||||||
|
hue = map(position_diff, 0.0, 1.0, VELOCITY_MODE_GOAL_HUE, VELOCITY_MODE_EDGE_HUE)
|
||||||
|
|
||||||
|
# Convert the band and goal positions to positions on the LED strip
|
||||||
|
strip_band_position = map(band_position, -1.0, 1.0, 0.0, float(NUM_LEDS))
|
||||||
|
strip_goal_position = map(goal_position, -1.0, 1.0, 0.0, float(NUM_LEDS))
|
||||||
|
|
||||||
|
# Draw the band and goal
|
||||||
|
colour_band(strip_band_position, BAND_PIXEL_WIDTH, strip_goal_position, GOAL_PIXEL_WIDTH, hue)
|
||||||
|
|
||||||
|
sw_pressed = user_sw.read()
|
||||||
|
a_pressed = button_a.read()
|
||||||
|
b_pressed = button_b.read()
|
||||||
|
|
||||||
|
if b_pressed:
|
||||||
|
game_mode = not game_mode
|
||||||
|
|
||||||
|
if sw_pressed:
|
||||||
|
invert = not invert
|
||||||
|
|
||||||
|
if mode == ANGLE:
|
||||||
|
if game_mode:
|
||||||
|
led.set_rgb(255, 255, 0)
|
||||||
|
else:
|
||||||
|
led.set_rgb(0, 255, 0)
|
||||||
|
if a_pressed:
|
||||||
|
mode = VELOCITY
|
||||||
|
|
||||||
|
elif mode == VELOCITY:
|
||||||
|
if game_mode:
|
||||||
|
led.set_rgb(255, 0, 255)
|
||||||
|
else:
|
||||||
|
led.set_rgb(0, 0, 255)
|
||||||
|
if a_pressed:
|
||||||
|
mode = ANGLE
|
||||||
|
|
||||||
|
if game_mode:
|
||||||
|
# Check if the band is within the goal, and if so, set a new goal
|
||||||
|
above_lower = strip_band_position >= strip_goal_position - (GOAL_PIXEL_WIDTH - BAND_PIXEL_WIDTH) / 2
|
||||||
|
below_upper = strip_band_position <= strip_goal_position + (GOAL_PIXEL_WIDTH - BAND_PIXEL_WIDTH) / 2
|
||||||
|
if above_lower and below_upper:
|
||||||
|
goal_position = random.uniform(-1.0, 1.0)
|
||||||
|
|
||||||
|
time.sleep(1.0 / UPDATES)
|
|
@ -0,0 +1,157 @@
|
||||||
|
import plasma
|
||||||
|
from plasma import plasma2040
|
||||||
|
|
||||||
|
# Import helpers for RGB LEDs and Buttons
|
||||||
|
from pimoroni import RGBLED, Button
|
||||||
|
|
||||||
|
# Import bme68x and I2C helper
|
||||||
|
from breakout_bme68x import BreakoutBME68X
|
||||||
|
from pimoroni_i2c import PimoroniI2C
|
||||||
|
|
||||||
|
# Uses a BME68x to monitor the ambient temperature, pressure and humidity, and show them as bars on an LED strip.
|
||||||
|
# Press "A" to cycle to the next mode.
|
||||||
|
# Press "B" to cycle to the previous mode.
|
||||||
|
|
||||||
|
# Set how many LEDs you have
|
||||||
|
NUM_LEDS = 30
|
||||||
|
|
||||||
|
# How many times the LEDs will be updated per second
|
||||||
|
UPDATES = 60
|
||||||
|
|
||||||
|
# The temperature range to show (in degrees celsius)
|
||||||
|
TEMPERATURE_C_MIN = 20.0
|
||||||
|
TEMPERATURE_C_MAX = 35.0
|
||||||
|
|
||||||
|
# The pressure range to show (in pascals)
|
||||||
|
PRESSURE_PA_MIN = 87000.0
|
||||||
|
PRESSURE_PA_MAX = 108500.0
|
||||||
|
|
||||||
|
# The humidity range to show (in percent)
|
||||||
|
HUMIDITY_MIN = 0.0
|
||||||
|
HUMIDITY_MAX = 100.0
|
||||||
|
|
||||||
|
|
||||||
|
# The start and end hues for the temperature range
|
||||||
|
TEMPERATURE_HUE_START = 0.667
|
||||||
|
TEMPERATURE_HUE_END = 1.0
|
||||||
|
|
||||||
|
# The start and end hues for the pressure range
|
||||||
|
PRESSURE_HUE_START = 0.333
|
||||||
|
PRESSURE_HUE_END = 0.0
|
||||||
|
|
||||||
|
# The start and end hues for the humidity range
|
||||||
|
HUMIDITY_HUE_START = 0.333
|
||||||
|
HUMIDITY_HUE_END = 0.667
|
||||||
|
|
||||||
|
|
||||||
|
# Pick *one* LED type by uncommenting the relevant line below:
|
||||||
|
|
||||||
|
# APA102 / DotStar™ LEDs
|
||||||
|
# led_strip = plasma.APA102(NUM_LEDS, 0, 0, plasma2040.DAT, plasma2040.CLK)
|
||||||
|
|
||||||
|
# WS2812 / NeoPixel™ LEDs
|
||||||
|
led_strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma2040.DAT)
|
||||||
|
|
||||||
|
|
||||||
|
button_a = Button(plasma2040.BUTTON_A, repeat_time=0)
|
||||||
|
button_b = Button(plasma2040.BUTTON_B, repeat_time=0)
|
||||||
|
led = RGBLED(plasma2040.LED_R, plasma2040.LED_G, plasma2040.LED_B)
|
||||||
|
|
||||||
|
PINS_PLASMA2040 = {"sda": plasma2040.SDA, "scl": plasma2040.SCL}
|
||||||
|
|
||||||
|
i2c = PimoroniI2C(**PINS_PLASMA2040)
|
||||||
|
bme = BreakoutBME68X(i2c)
|
||||||
|
|
||||||
|
|
||||||
|
ALL, TEMPERATURE, PRESSURE, HUMIDITY = range(4)
|
||||||
|
|
||||||
|
|
||||||
|
# Maps a value from one range to another
|
||||||
|
def map(x, in_min, in_max, out_min, out_max):
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
|
||||||
|
|
||||||
|
|
||||||
|
# Sets a section of the led strip to show a hue gradient based on the provided percent
|
||||||
|
def colour_gauge(percent, start_led, end_led, start_hue, end_hue):
|
||||||
|
if end_led > start_led:
|
||||||
|
length = end_led - start_led
|
||||||
|
light_pixels = percent * float(length)
|
||||||
|
|
||||||
|
for i in range(length):
|
||||||
|
h = map(i, 0.0, float(length - 1), start_hue, end_hue)
|
||||||
|
|
||||||
|
i2 = i + 1
|
||||||
|
if i2 <= light_pixels:
|
||||||
|
led_strip.set_hsv(i + start_led, h, 1.0, 1.0)
|
||||||
|
elif i <= light_pixels:
|
||||||
|
scale = map(light_pixels, float(i), float(i2), 0.0, 1.0)
|
||||||
|
led_strip.set_hsv(i + start_led, h, 1.0, scale)
|
||||||
|
else:
|
||||||
|
led_strip.set_hsv(i + start_led, 0.0, 0.0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
first_third = int(NUM_LEDS / 3)
|
||||||
|
second_third = int((NUM_LEDS * 2) / 3)
|
||||||
|
|
||||||
|
mode = ALL
|
||||||
|
|
||||||
|
# Start updating the LED strip
|
||||||
|
led_strip.start()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
temperature, pressure, humidity, _, _, _, _ = bme.read()
|
||||||
|
print("{:0.2f}c, {:0.2f}Pa, {:0.2f}%".format(
|
||||||
|
temperature, pressure, humidity))
|
||||||
|
|
||||||
|
if mode == ALL:
|
||||||
|
t = map(temperature, TEMPERATURE_C_MIN, TEMPERATURE_C_MAX, 0.0, 1.0)
|
||||||
|
colour_gauge(t, 0, first_third, TEMPERATURE_HUE_START, TEMPERATURE_HUE_END)
|
||||||
|
|
||||||
|
t = map(pressure, PRESSURE_PA_MIN, PRESSURE_PA_MAX, 0.0, 1.0)
|
||||||
|
colour_gauge(t, first_third, second_third, PRESSURE_HUE_START, PRESSURE_HUE_END)
|
||||||
|
|
||||||
|
t = map(humidity, HUMIDITY_MIN, HUMIDITY_MAX, 0.0, 1.0)
|
||||||
|
colour_gauge(t, second_third, NUM_LEDS, HUMIDITY_HUE_START, HUMIDITY_HUE_END)
|
||||||
|
|
||||||
|
elif mode == TEMPERATURE:
|
||||||
|
t = map(temperature, TEMPERATURE_C_MIN, TEMPERATURE_C_MAX, 0.0, 1.0)
|
||||||
|
colour_gauge(t, 0, NUM_LEDS, TEMPERATURE_HUE_START, TEMPERATURE_HUE_END)
|
||||||
|
|
||||||
|
elif mode == PRESSURE:
|
||||||
|
t = map(pressure, PRESSURE_PA_MIN, PRESSURE_PA_MAX, 0.0, 1.0)
|
||||||
|
colour_gauge(t, 0, NUM_LEDS, PRESSURE_HUE_START, PRESSURE_HUE_END)
|
||||||
|
|
||||||
|
elif mode == HUMIDITY:
|
||||||
|
t = map(humidity, HUMIDITY_MIN, HUMIDITY_MAX, 0.0, 1.0)
|
||||||
|
colour_gauge(t, 0, NUM_LEDS, HUMIDITY_HUE_START, HUMIDITY_HUE_END)
|
||||||
|
|
||||||
|
a_pressed = button_a.read()
|
||||||
|
b_pressed = button_b.read()
|
||||||
|
|
||||||
|
if mode == ALL:
|
||||||
|
led.set_rgb(127, 127, 127)
|
||||||
|
if a_pressed:
|
||||||
|
mode = TEMPERATURE
|
||||||
|
elif b_pressed:
|
||||||
|
mode = HUMIDITY
|
||||||
|
|
||||||
|
elif mode == TEMPERATURE:
|
||||||
|
led.set_rgb(255, 0, 255)
|
||||||
|
if a_pressed:
|
||||||
|
mode = PRESSURE
|
||||||
|
elif b_pressed:
|
||||||
|
mode = ALL
|
||||||
|
|
||||||
|
elif mode == PRESSURE:
|
||||||
|
led.set_rgb(255, 255, 0)
|
||||||
|
if a_pressed:
|
||||||
|
mode = HUMIDITY
|
||||||
|
elif b_pressed:
|
||||||
|
mode = TEMPERATURE
|
||||||
|
|
||||||
|
elif mode == HUMIDITY:
|
||||||
|
led.set_rgb(0, 255, 255)
|
||||||
|
if a_pressed:
|
||||||
|
mode = ALL
|
||||||
|
elif b_pressed:
|
||||||
|
mode = PRESSURE
|
|
@ -0,0 +1,187 @@
|
||||||
|
import plasma
|
||||||
|
from plasma import plasma2040
|
||||||
|
import time
|
||||||
|
import math
|
||||||
|
|
||||||
|
# Import helpers for RGB LEDs and Buttons
|
||||||
|
from pimoroni import RGBLED, Button
|
||||||
|
|
||||||
|
# Import bme68x and I2C helper
|
||||||
|
from breakout_encoder import BreakoutEncoder
|
||||||
|
from pimoroni_i2c import PimoroniI2C
|
||||||
|
|
||||||
|
# Press "B" to enable cycling.
|
||||||
|
# Press "A" to change the encoder mode.
|
||||||
|
# Press "Boot" to reset the effects back to default.
|
||||||
|
|
||||||
|
# Set how many LEDs you have
|
||||||
|
NUM_LEDS = 30
|
||||||
|
|
||||||
|
# The speed that the LEDs will start cycling at
|
||||||
|
DEFAULT_SPEED = 20
|
||||||
|
|
||||||
|
# The hue (in degrees) that the LEDs will start at
|
||||||
|
DEFAULT_HUE = 0
|
||||||
|
|
||||||
|
# The angle (in degrees) from the hue, that the LEDs will end at
|
||||||
|
DEFAULT_ANGLE = 120
|
||||||
|
|
||||||
|
# The brightness (between 0 and 31) to set the LEDs to
|
||||||
|
DEFAULT_BRIGHTNESS = 16
|
||||||
|
|
||||||
|
# How many times the LEDs will be updated per second
|
||||||
|
UPDATES = 60
|
||||||
|
|
||||||
|
|
||||||
|
# Pick *one* LED type by uncommenting the relevant line below:
|
||||||
|
|
||||||
|
# APA102 / DotStar™ LEDs
|
||||||
|
led_strip = plasma.APA102(NUM_LEDS, 0, 0, plasma2040.DAT, plasma2040.CLK)
|
||||||
|
|
||||||
|
# WS2812 / NeoPixel™ LEDs
|
||||||
|
# led_strip = plasma.WS2812(NUM_LEDS, 0, 0, plasma2040.DAT)
|
||||||
|
|
||||||
|
user_sw = Button(plasma2040.USER_SW, repeat_time=0)
|
||||||
|
button_a = Button(plasma2040.BUTTON_A, repeat_time=0)
|
||||||
|
button_b = Button(plasma2040.BUTTON_B, repeat_time=0)
|
||||||
|
led = RGBLED(plasma2040.LED_R, plasma2040.LED_G, plasma2040.LED_B)
|
||||||
|
|
||||||
|
PINS_PLASMA2040 = {"sda": plasma2040.SDA, "scl": plasma2040.SCL}
|
||||||
|
|
||||||
|
i2c = PimoroniI2C(**PINS_PLASMA2040)
|
||||||
|
enc = BreakoutEncoder(i2c)
|
||||||
|
enc.set_brightness(1.0)
|
||||||
|
|
||||||
|
|
||||||
|
COLOUR, ANGLE, BRIGHTNESS, SPEED = range(4)
|
||||||
|
|
||||||
|
|
||||||
|
def wrap(v, mn, mx):
|
||||||
|
if v <= mn:
|
||||||
|
v += mx - mn
|
||||||
|
|
||||||
|
if v > mx:
|
||||||
|
v -= mx - mn
|
||||||
|
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def colour_cycle(hue, t, angle):
|
||||||
|
t /= 200.0
|
||||||
|
|
||||||
|
for i in range(NUM_LEDS):
|
||||||
|
percent_along = float(i) / NUM_LEDS
|
||||||
|
offset = math.sin((percent_along + 0.5 + t) * math.pi) * angle
|
||||||
|
h = wrap((hue + offset) / 360.0, 0.0, 1.0)
|
||||||
|
led_strip.set_hsv(i, h, 1.0, 1.0)
|
||||||
|
|
||||||
|
|
||||||
|
def speed_gauge(v, vmax=100):
|
||||||
|
light_pixels = NUM_LEDS * v / vmax
|
||||||
|
|
||||||
|
for i in range(NUM_LEDS):
|
||||||
|
if i < light_pixels:
|
||||||
|
led_strip.set_rgb(i, 0, 255, 0)
|
||||||
|
else:
|
||||||
|
led_strip.set_rgb(i, 255, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def brightness_gauge(v, vmax=100):
|
||||||
|
light_pixels = NUM_LEDS * v / vmax
|
||||||
|
|
||||||
|
for i in range(NUM_LEDS):
|
||||||
|
if i < light_pixels:
|
||||||
|
led_strip.set_rgb(i, 64, 64, 64)
|
||||||
|
else:
|
||||||
|
led_strip.set_rgb(i, 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
# Start updating the LED strip
|
||||||
|
led_strip.start()
|
||||||
|
|
||||||
|
enc.clear_interrupt_flag()
|
||||||
|
|
||||||
|
# Initialise the default values
|
||||||
|
speed = DEFAULT_SPEED
|
||||||
|
hue = DEFAULT_HUE
|
||||||
|
angle = DEFAULT_ANGLE
|
||||||
|
brightness = DEFAULT_BRIGHTNESS
|
||||||
|
|
||||||
|
cycle = True
|
||||||
|
mode = COLOUR
|
||||||
|
start_time = time.ticks_ms()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
t = time.ticks_ms() - start_time
|
||||||
|
|
||||||
|
if enc.get_interrupt_flag():
|
||||||
|
count = enc.read()
|
||||||
|
enc.clear_interrupt_flag()
|
||||||
|
enc.clear()
|
||||||
|
|
||||||
|
cycle = False
|
||||||
|
|
||||||
|
if mode == COLOUR:
|
||||||
|
hue += count
|
||||||
|
hue = min(359, max(0, hue))
|
||||||
|
colour_cycle(hue, 0, angle)
|
||||||
|
|
||||||
|
elif mode == ANGLE:
|
||||||
|
angle += count
|
||||||
|
angle = min(359, max(0, angle))
|
||||||
|
colour_cycle(hue, 0, angle)
|
||||||
|
|
||||||
|
elif mode == BRIGHTNESS:
|
||||||
|
brightness += count
|
||||||
|
brightness = min(31, max(0, brightness))
|
||||||
|
led_strip.set_brightness(brightness)
|
||||||
|
brightness_gauge(brightness, 31)
|
||||||
|
|
||||||
|
elif mode == SPEED:
|
||||||
|
speed += count
|
||||||
|
speed = min(100, max(0, speed))
|
||||||
|
speed_gauge(speed, 100)
|
||||||
|
|
||||||
|
sw_pressed = user_sw.read()
|
||||||
|
a_pressed = button_a.read()
|
||||||
|
b_pressed = button_b.read()
|
||||||
|
|
||||||
|
if sw_pressed:
|
||||||
|
speed = DEFAULT_SPEED
|
||||||
|
hue = DEFAULT_HUE
|
||||||
|
angle = DEFAULT_ANGLE
|
||||||
|
brightness = DEFAULT_BRIGHTNESS
|
||||||
|
|
||||||
|
if b_pressed:
|
||||||
|
if not cycle:
|
||||||
|
start_time = time.ticks_ms()
|
||||||
|
cycle = True
|
||||||
|
speed = min(255, max(1, speed))
|
||||||
|
|
||||||
|
if mode == COLOUR:
|
||||||
|
led.set_rgb(255, 0, 0)
|
||||||
|
if a_pressed:
|
||||||
|
mode = ANGLE
|
||||||
|
|
||||||
|
elif mode == ANGLE:
|
||||||
|
led.set_rgb(255, 255, 0)
|
||||||
|
if a_pressed:
|
||||||
|
mode = BRIGHTNESS
|
||||||
|
|
||||||
|
elif mode == BRIGHTNESS:
|
||||||
|
led.set_rgb(0, 255, 0)
|
||||||
|
if a_pressed:
|
||||||
|
mode = SPEED
|
||||||
|
|
||||||
|
elif mode == SPEED:
|
||||||
|
led.set_rgb(0, 0, 255)
|
||||||
|
if a_pressed:
|
||||||
|
mode = COLOUR
|
||||||
|
|
||||||
|
if cycle:
|
||||||
|
colour_cycle(hue, float(t * speed) / 100.0, angle)
|
||||||
|
|
||||||
|
mid_led = led_strip.get(int(NUM_LEDS / 2))
|
||||||
|
enc.set_led(int(mid_led[0]), int(mid_led[1]), int(mid_led[2]))
|
||||||
|
|
||||||
|
time.sleep(1.0 / UPDATES)
|
|
@ -14,6 +14,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_brightness_obj, 2, BreakoutEncode
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_led_obj, 4, BreakoutEncoder_set_led);
|
MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutEncoder_set_led_obj, 4, BreakoutEncoder_set_led);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_available_obj, BreakoutEncoder_available);
|
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_available_obj, BreakoutEncoder_available);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_read_obj, BreakoutEncoder_read);
|
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_read_obj, BreakoutEncoder_read);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(BreakoutEncoder_clear_obj, BreakoutEncoder_clear);
|
||||||
|
|
||||||
/***** Binding of Methods *****/
|
/***** Binding of Methods *****/
|
||||||
STATIC const mp_rom_map_elem_t BreakoutEncoder_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t BreakoutEncoder_locals_dict_table[] = {
|
||||||
|
@ -26,6 +27,7 @@ STATIC const mp_rom_map_elem_t BreakoutEncoder_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutEncoder_set_led_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&BreakoutEncoder_set_led_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_available), MP_ROM_PTR(&BreakoutEncoder_available_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_available), MP_ROM_PTR(&BreakoutEncoder_available_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutEncoder_read_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&BreakoutEncoder_read_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&BreakoutEncoder_clear_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_DIRECTION_CW), MP_ROM_INT(1) },
|
{ MP_ROM_QSTR(MP_QSTR_DIRECTION_CW), MP_ROM_INT(1) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_DIRECTION_CCW), MP_ROM_INT(0) },
|
{ MP_ROM_QSTR(MP_QSTR_DIRECTION_CCW), MP_ROM_INT(0) },
|
||||||
};
|
};
|
||||||
|
|
|
@ -199,4 +199,11 @@ mp_obj_t BreakoutEncoder_read(mp_obj_t self_in) {
|
||||||
breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t);
|
breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t);
|
||||||
return mp_obj_new_int(self->breakout->read());
|
return mp_obj_new_int(self->breakout->read());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_obj_t BreakoutEncoder_clear(mp_obj_t self_in) {
|
||||||
|
breakout_encoder_BreakoutEncoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_encoder_BreakoutEncoder_obj_t);
|
||||||
|
self->breakout->clear();
|
||||||
|
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -15,4 +15,5 @@ extern mp_obj_t BreakoutEncoder_set_direction(size_t n_args, const mp_obj_t *pos
|
||||||
extern mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t BreakoutEncoder_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t BreakoutEncoder_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t BreakoutEncoder_available(mp_obj_t self_in);
|
extern mp_obj_t BreakoutEncoder_available(mp_obj_t self_in);
|
||||||
extern mp_obj_t BreakoutEncoder_read(mp_obj_t self_in);
|
extern mp_obj_t BreakoutEncoder_read(mp_obj_t self_in);
|
||||||
|
extern mp_obj_t BreakoutEncoder_clear(mp_obj_t self_in);
|
|
@ -7,12 +7,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_rgb_obj, 5, PlasmaAPA102_set_rgb);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_hsv_obj, 3, PlasmaAPA102_set_hsv);
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_hsv_obj, 3, PlasmaAPA102_set_hsv);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_brightness_obj, 2, PlasmaAPA102_set_brightness);
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_brightness_obj, 2, PlasmaAPA102_set_brightness);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_start_obj, 1, PlasmaAPA102_start);
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_start_obj, 1, PlasmaAPA102_start);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_get_obj, 2, PlasmaAPA102_get);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaAPA102_clear_obj, PlasmaAPA102_clear);
|
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaAPA102_clear_obj, PlasmaAPA102_clear);
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaWS2812___del___obj, PlasmaWS2812___del__);
|
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaWS2812___del___obj, PlasmaWS2812___del__);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_set_rgb_obj, 5, PlasmaWS2812_set_rgb);
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_set_rgb_obj, 5, PlasmaWS2812_set_rgb);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_set_hsv_obj, 3, PlasmaWS2812_set_hsv);
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_set_hsv_obj, 3, PlasmaWS2812_set_hsv);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_start_obj, 1, PlasmaWS2812_start);
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_start_obj, 1, PlasmaWS2812_start);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_get_obj, 2, PlasmaAPA102_get);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaWS2812_clear_obj, PlasmaWS2812_clear);
|
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaWS2812_clear_obj, PlasmaWS2812_clear);
|
||||||
|
|
||||||
/***** Binding of Methods *****/
|
/***** Binding of Methods *****/
|
||||||
|
@ -22,6 +24,7 @@ STATIC const mp_rom_map_elem_t PlasmaAPA102_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_set_hsv), MP_ROM_PTR(&PlasmaAPA102_set_hsv_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_set_hsv), MP_ROM_PTR(&PlasmaAPA102_set_hsv_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&PlasmaAPA102_set_brightness_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&PlasmaAPA102_set_brightness_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&PlasmaAPA102_start_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&PlasmaAPA102_start_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&PlasmaAPA102_get_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&PlasmaAPA102_clear_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&PlasmaAPA102_clear_obj) },
|
||||||
};
|
};
|
||||||
STATIC const mp_rom_map_elem_t PlasmaWS2812_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t PlasmaWS2812_locals_dict_table[] = {
|
||||||
|
@ -29,6 +32,7 @@ STATIC const mp_rom_map_elem_t PlasmaWS2812_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_set_rgb), MP_ROM_PTR(&PlasmaWS2812_set_rgb_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_set_rgb), MP_ROM_PTR(&PlasmaWS2812_set_rgb_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_set_hsv), MP_ROM_PTR(&PlasmaWS2812_set_hsv_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_set_hsv), MP_ROM_PTR(&PlasmaWS2812_set_hsv_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&PlasmaWS2812_start_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&PlasmaWS2812_start_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&PlasmaWS2812_get_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&PlasmaWS2812_clear_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&PlasmaWS2812_clear_obj) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,6 +74,8 @@ STATIC const mp_map_elem_t plasma2040_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_CLK), MP_ROM_INT(14) },
|
{ MP_ROM_QSTR(MP_QSTR_CLK), MP_ROM_INT(14) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_DAT), MP_ROM_INT(15) },
|
{ MP_ROM_QSTR(MP_QSTR_DAT), MP_ROM_INT(15) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_CURRENT_SENSE), MP_ROM_INT(29) },
|
{ MP_ROM_QSTR(MP_QSTR_CURRENT_SENSE), MP_ROM_INT(29) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_INT(20) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_INT(21) },
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SHUNT_RESISTOR), MP_ROM_PTR(&shunt_resistor) },
|
{ MP_ROM_QSTR(MP_QSTR_SHUNT_RESISTOR), MP_ROM_PTR(&shunt_resistor) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ADC_GAIN), MP_ROM_INT(50) },
|
{ MP_ROM_QSTR(MP_QSTR_ADC_GAIN), MP_ROM_INT(50) },
|
||||||
|
|
|
@ -73,7 +73,7 @@ mp_obj_t PlasmaWS2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
||||||
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = WS2812::DEFAULT_SERIAL_FREQ} },
|
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = WS2812::DEFAULT_SERIAL_FREQ} },
|
||||||
{ MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = nullptr} },
|
{ MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = nullptr} },
|
||||||
{ MP_QSTR_rgbw, MP_ARG_BOOL, {.u_bool = false} },
|
{ MP_QSTR_rgbw, MP_ARG_BOOL, {.u_bool = false} },
|
||||||
{ MP_QSTR_color_order, MP_ARG_INT, {.u_int = (uint8_t)WS2812::COLOR_ORDER::RGB} },
|
{ MP_QSTR_color_order, MP_ARG_INT, {.u_int = (uint8_t)WS2812::COLOR_ORDER::GRB} },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse args.
|
// Parse args.
|
||||||
|
@ -182,6 +182,29 @@ mp_obj_t PlasmaWS2812_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_obj_t PlasmaWS2812_get(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
enum { ARG_self, ARG_index };
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||||
|
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||||
|
};
|
||||||
|
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
int index = args[ARG_index].u_int;
|
||||||
|
|
||||||
|
_PlasmaWS2812_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaWS2812_obj_t);
|
||||||
|
WS2812::RGB rgb = self->ws2812->get(index);
|
||||||
|
|
||||||
|
mp_obj_t tuple[4];
|
||||||
|
tuple[0] = mp_obj_new_int(rgb.r);
|
||||||
|
tuple[1] = mp_obj_new_float(rgb.g);
|
||||||
|
tuple[2] = mp_obj_new_float(rgb.b);
|
||||||
|
tuple[3] = mp_obj_new_float(rgb.w);
|
||||||
|
return mp_obj_new_tuple(4, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
/********** APA102 **********/
|
/********** APA102 **********/
|
||||||
|
|
||||||
/***** Variables Struct *****/
|
/***** Variables Struct *****/
|
||||||
|
@ -245,22 +268,29 @@ mp_obj_t PlasmaAPA102_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
||||||
int clk = args[ARG_clk].u_int;
|
int clk = args[ARG_clk].u_int;
|
||||||
int freq = args[ARG_freq].u_int;
|
int freq = args[ARG_freq].u_int;
|
||||||
|
|
||||||
void *buffer = nullptr;
|
APA102::RGB *buffer = nullptr;
|
||||||
|
|
||||||
if (args[ARG_buffer].u_obj) {
|
if (args[ARG_buffer].u_obj) {
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
|
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
|
||||||
buffer = bufinfo.buf;
|
buffer = (APA102::RGB *)bufinfo.buf;
|
||||||
if(bufinfo.len < (size_t)(num_leds * 4)) {
|
if(bufinfo.len < (size_t)(num_leds * 4)) {
|
||||||
mp_raise_ValueError("Supplied buffer is too small for LED count!");
|
mp_raise_ValueError("Supplied buffer is too small for LED count!");
|
||||||
}
|
}
|
||||||
|
// If a bytearray is supplied it'll be raw, uninitialized bytes
|
||||||
|
// iterate through the RGB elements and call "brightness"
|
||||||
|
// to set up the SOF bytes, otherwise a flickery mess will happen!
|
||||||
|
// Oh for such niceties as "placement new"...
|
||||||
|
for(auto i = 0; i < num_leds; i++) {
|
||||||
|
buffer[i].brightness(15);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self = m_new_obj_with_finaliser(_PlasmaAPA102_obj_t);
|
self = m_new_obj_with_finaliser(_PlasmaAPA102_obj_t);
|
||||||
self->base.type = &PlasmaAPA102_type;
|
self->base.type = &PlasmaAPA102_type;
|
||||||
self->buf = buffer;
|
self->buf = buffer;
|
||||||
|
|
||||||
self->apa102 = new APA102(num_leds, pio, sm, dat, clk, freq, (APA102::RGB *)buffer);
|
self->apa102 = new APA102(num_leds, pio, sm, dat, clk, freq, buffer);
|
||||||
|
|
||||||
return MP_OBJ_FROM_PTR(self);
|
return MP_OBJ_FROM_PTR(self);
|
||||||
}
|
}
|
||||||
|
@ -357,4 +387,27 @@ mp_obj_t PlasmaAPA102_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_obj_t PlasmaAPA102_get(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
enum { ARG_self, ARG_index };
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||||
|
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||||
|
};
|
||||||
|
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
int index = args[ARG_index].u_int;
|
||||||
|
|
||||||
|
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaAPA102_obj_t);
|
||||||
|
APA102::RGB rgb = self->apa102->get(index);
|
||||||
|
|
||||||
|
mp_obj_t tuple[4];
|
||||||
|
tuple[0] = mp_obj_new_int(rgb.r);
|
||||||
|
tuple[1] = mp_obj_new_float(rgb.g);
|
||||||
|
tuple[2] = mp_obj_new_float(rgb.b);
|
||||||
|
tuple[3] = mp_obj_new_float(rgb.sof);
|
||||||
|
return mp_obj_new_tuple(4, tuple);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ extern mp_obj_t PlasmaAPA102_start(size_t n_args, const mp_obj_t *pos_args, mp_m
|
||||||
extern mp_obj_t PlasmaAPA102_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t PlasmaAPA102_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t PlasmaAPA102_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t PlasmaAPA102_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t PlasmaAPA102_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t PlasmaAPA102_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
|
extern mp_obj_t PlasmaAPA102_get(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t PlasmaAPA102_clear(mp_obj_t self_in);
|
extern mp_obj_t PlasmaAPA102_clear(mp_obj_t self_in);
|
||||||
|
|
||||||
extern void PlasmaWS2812_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
extern void PlasmaWS2812_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||||
|
@ -21,6 +22,7 @@ extern mp_obj_t PlasmaWS2812___del__(mp_obj_t self_in);
|
||||||
extern mp_obj_t PlasmaWS2812_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t PlasmaWS2812_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t PlasmaWS2812_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t PlasmaWS2812_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t PlasmaWS2812_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
extern mp_obj_t PlasmaWS2812_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
|
extern mp_obj_t PlasmaWS2812_get(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
extern mp_obj_t PlasmaWS2812_clear(mp_obj_t self_in);
|
extern mp_obj_t PlasmaWS2812_clear(mp_obj_t self_in);
|
||||||
|
|
||||||
extern bool Pimoroni_mp_obj_to_i2c(mp_obj_t in, void *out);
|
extern bool Pimoroni_mp_obj_to_i2c(mp_obj_t in, void *out);
|
Loading…
Reference in New Issue