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) {
|
||||
int8_t result;
|
||||
int8_t result = 0;
|
||||
|
||||
conf.filter = filter;
|
||||
conf.odr = odr;
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
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) {
|
||||
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_pindirs_with_mask(pio, sm, ~0u, (1u << pin_clk) | (1u << pin_dat));
|
||||
pio_gpio_init(pio, pin_clk);
|
||||
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_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);
|
||||
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);
|
||||
|
||||
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) {
|
||||
this->buffer = new RGB[num_leds];
|
||||
managed_buffer = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,9 +60,17 @@ namespace plasma {
|
|||
clear();
|
||||
update(true);
|
||||
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);
|
||||
#endif
|
||||
if(managed_buffer) {
|
||||
// Only delete buffers we have allocated ourselves.
|
||||
delete[] buffer;
|
||||
}
|
||||
}
|
||||
bool start(uint fps=60);
|
||||
bool stop();
|
||||
void update(bool blocking=false);
|
||||
|
@ -78,7 +86,9 @@ namespace plasma {
|
|||
uint32_t fps;
|
||||
PIO pio;
|
||||
uint sm;
|
||||
uint pio_program_offset;
|
||||
int dma_channel;
|
||||
struct repeating_timer timer;
|
||||
bool managed_buffer = false;
|
||||
};
|
||||
}
|
|
@ -3,12 +3,12 @@
|
|||
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) {
|
||||
uint offset = pio_add_program(pio, &ws2812_program);
|
||||
pio_program_offset = pio_add_program(pio, &ws2812_program);
|
||||
|
||||
pio_gpio_init(pio, pin);
|
||||
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_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);
|
||||
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);
|
||||
|
||||
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) {
|
||||
this->buffer = new RGB[num_leds];
|
||||
managed_buffer = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,15 +63,23 @@ namespace plasma {
|
|||
uint32_t num_leds;
|
||||
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() {
|
||||
stop();
|
||||
clear();
|
||||
update(true);
|
||||
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);
|
||||
#endif
|
||||
if(managed_buffer) {
|
||||
// Only delete buffers we have allocated ourselves.
|
||||
delete[] buffer;
|
||||
}
|
||||
}
|
||||
bool start(uint fps=60);
|
||||
bool stop();
|
||||
void update(bool blocking=false);
|
||||
|
@ -87,7 +95,9 @@ namespace plasma {
|
|||
uint32_t fps;
|
||||
PIO pio;
|
||||
uint sm;
|
||||
uint pio_program_offset;
|
||||
int dma_channel;
|
||||
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_rotary.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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,16 +56,16 @@ int main() {
|
|||
|
||||
uint count = 0;
|
||||
while(true) {
|
||||
bool sw = user_sw.read();
|
||||
bool a = button_a.read();
|
||||
bool b = button_b.read();
|
||||
bool sw_pressed = user_sw.read();
|
||||
bool a_pressed = button_a.read();
|
||||
bool b_pressed = button_b.read();
|
||||
|
||||
if(sw) {
|
||||
if(sw_pressed) {
|
||||
speed = DEFAULT_SPEED;
|
||||
}
|
||||
else {
|
||||
if(a) speed--;
|
||||
if(b) speed++;
|
||||
if(a_pressed) speed--;
|
||||
if(b_pressed) speed++;
|
||||
}
|
||||
speed = std::min((int)255, std::max((int)1, speed));
|
||||
|
||||
|
|
|
@ -11,15 +11,34 @@
|
|||
#include "rgbled.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 plasma;
|
||||
|
||||
// Set how many LEDs you have
|
||||
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
|
||||
const uint UPDATES = 60;
|
||||
|
||||
|
||||
// Pick *one* LED type by uncommenting the relevant line below:
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
|
||||
Button button_a(plasma2040::BUTTON_A);
|
||||
Button button_b(plasma2040::BUTTON_B);
|
||||
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);
|
||||
|
||||
|
@ -42,32 +61,57 @@ enum ENCODER_MODE {
|
|||
COLOUR,
|
||||
ANGLE,
|
||||
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) {
|
||||
t /= 200.0f;
|
||||
|
||||
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||
float offset = (M_PI * i) / led_strip.num_leds;
|
||||
offset = sinf(offset + t) * angle;
|
||||
led_strip.set_hsv(i, (hue + offset) / 360.0f, 1.0f, 1.0f);
|
||||
float percent_along = (float)i / led_strip.num_leds;
|
||||
float offset = sinf((percent_along + 0.5f + t) * M_PI) * angle;
|
||||
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;
|
||||
|
||||
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||
if(i < light_pixels) {
|
||||
led_strip.set_rgb(i, 0, 255, 0);
|
||||
} else {
|
||||
}
|
||||
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() {
|
||||
stdio_init_all();
|
||||
|
||||
|
@ -76,17 +120,20 @@ int main() {
|
|||
bool encoder_detected = enc.init();
|
||||
enc.clear_interrupt_flag();
|
||||
|
||||
int speed = 50;
|
||||
float hue = 0;
|
||||
int angle = 120;
|
||||
int8_t brightness = 16;
|
||||
//Initialise the default values
|
||||
int16_t speed = DEFAULT_SPEED;
|
||||
int16_t hue = DEFAULT_HUE;
|
||||
int16_t angle = DEFAULT_ANGLE;
|
||||
int16_t brightness = DEFAULT_BRIGHTNESS;
|
||||
|
||||
bool cycle = true;
|
||||
ENCODER_MODE mode = ENCODER_MODE::COLOUR;
|
||||
uint32_t start_time = millis();
|
||||
while(true) {
|
||||
uint32_t t = millis();
|
||||
uint32_t t = millis() - start_time;
|
||||
if(encoder_detected) {
|
||||
if(enc.get_interrupt_flag()) {
|
||||
int count = enc.read();
|
||||
int16_t count = enc.read();
|
||||
enc.clear_interrupt_flag();
|
||||
enc.clear();
|
||||
|
||||
|
@ -94,60 +141,75 @@ int main() {
|
|||
switch(mode) {
|
||||
case ENCODER_MODE::COLOUR:
|
||||
hue += count;
|
||||
brightness = std::min((int8_t)359, brightness);
|
||||
brightness = std::max((int8_t)0, brightness);
|
||||
colour_cycle(hue, 0, (float)angle);
|
||||
hue = std::min((int16_t)359, std::max((int16_t)0, hue));
|
||||
colour_cycle((float)hue, 0, (float)angle);
|
||||
break;
|
||||
|
||||
case ENCODER_MODE::ANGLE:
|
||||
angle += count;
|
||||
angle = std::min((int)359, angle);
|
||||
angle = std::max((int)0, angle);
|
||||
colour_cycle(hue, 0, (float)angle);
|
||||
angle = std::min((int16_t)359, std::max((int16_t)0, angle));
|
||||
colour_cycle((float)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);
|
||||
brightness = std::min((int16_t)31, std::max((int16_t)0, brightness));
|
||||
led_strip.set_brightness((uint8_t)brightness);
|
||||
brightness_gauge(brightness, 31);
|
||||
break;
|
||||
case ENCODER_MODE::TIME:
|
||||
|
||||
case ENCODER_MODE::SPEED:
|
||||
speed += count;
|
||||
speed = std::min((int)100, speed);
|
||||
speed = std::max((int)0, speed);
|
||||
gauge(speed, 100);
|
||||
speed = std::min((int16_t)100, std::max((int16_t)0, speed));
|
||||
speed_gauge(speed, 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool sw_pressed = user_sw.read();
|
||||
bool a_pressed = button_a.read();
|
||||
bool b_pressed = button_b.read();
|
||||
|
||||
if(b_pressed) cycle = true;
|
||||
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::TIME;
|
||||
if(a_pressed) mode = ENCODER_MODE::SPEED;
|
||||
break;
|
||||
case ENCODER_MODE::TIME:
|
||||
|
||||
case ENCODER_MODE::SPEED:
|
||||
led.set_rgb(0, 0, 255);
|
||||
if(a_pressed) mode = ENCODER_MODE::COLOUR;
|
||||
break;
|
||||
}
|
||||
|
||||
if(cycle) colour_cycle(hue, t * speed / 100, (float)angle);
|
||||
if(cycle)
|
||||
colour_cycle(hue, (float)(t * speed) / 100.0f, (float)angle);
|
||||
|
||||
auto first_led = led_strip.get(0);
|
||||
enc.set_led(first_led.r, first_led.g, first_led.b);
|
||||
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
|
||||
|
|
|
@ -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_1(BreakoutEncoder_available_obj, BreakoutEncoder_available);
|
||||
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 *****/
|
||||
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_available), MP_ROM_PTR(&BreakoutEncoder_available_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_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);
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -16,3 +16,4 @@ extern mp_obj_t BreakoutEncoder_set_brightness(size_t n_args, const mp_obj_t *po
|
|||
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_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_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_get_obj, 2, PlasmaAPA102_get);
|
||||
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_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_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);
|
||||
|
||||
/***** 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_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_get), MP_ROM_PTR(&PlasmaAPA102_get_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&PlasmaAPA102_clear_obj) },
|
||||
};
|
||||
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_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_get), MP_ROM_PTR(&PlasmaWS2812_get_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_DAT), MP_ROM_INT(15) },
|
||||
{ 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_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_buffer, MP_ARG_OBJ, {.u_obj = nullptr} },
|
||||
{ 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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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 **********/
|
||||
|
||||
/***** 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 freq = args[ARG_freq].u_int;
|
||||
|
||||
void *buffer = nullptr;
|
||||
APA102::RGB *buffer = nullptr;
|
||||
|
||||
if (args[ARG_buffer].u_obj) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
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)) {
|
||||
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->base.type = &PlasmaAPA102_type;
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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_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_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 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_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_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 bool Pimoroni_mp_obj_to_i2c(mp_obj_t in, void *out);
|
Loading…
Reference in New Issue