kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Progress on encoder wheel C++ and MP
rodzic
928c28b677
commit
d4d6cd1936
|
@ -1,5 +1,6 @@
|
|||
#include "breakout_encoder_wheel.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
|
@ -13,7 +14,21 @@ namespace pimoroni {
|
|||
|
||||
ioe.setup_rotary_encoder(ENC_CHANNEL, ENC_TERM_A, ENC_TERM_B);
|
||||
|
||||
success = true;
|
||||
if(led_ring.init()) {
|
||||
led_ring.enable({
|
||||
0b00000000, 0b10111111,
|
||||
0b00111110, 0b00111110,
|
||||
0b00111111, 0b10111110,
|
||||
0b00000111, 0b10000110,
|
||||
0b00110000, 0b00110000,
|
||||
0b00111111, 0b10111110,
|
||||
0b00111111, 0b10111110,
|
||||
0b01111111, 0b11111110,
|
||||
0b01111111, 0b00000000
|
||||
}, 0);
|
||||
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -55,22 +70,127 @@ namespace pimoroni {
|
|||
ioe.clear_interrupt_flag();
|
||||
}
|
||||
|
||||
BreakoutEncoderWheel::Direction BreakoutEncoderWheel::get_encoder_direction() {
|
||||
//return direction;
|
||||
return DEFAULT_DIRECTION;
|
||||
bool BreakoutEncoderWheel::pressed(uint button) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::set_encoder_direction(Direction direction) {
|
||||
//this->direction = direction;
|
||||
int BreakoutEncoderWheel::count() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::set_pixel(uint8_t index, uint8_t r, uint8_t g, uint8_t b) {
|
||||
int BreakoutEncoderWheel::delta() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::step() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::turn() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::zero() {
|
||||
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::revolutions() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::degrees() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::radians() {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
Direction BreakoutEncoderWheel::direction() {
|
||||
return enc_direction;
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::direction(Direction direction) {
|
||||
enc_direction = direction;
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::set_rgb(int index, int r, int g, int b) {
|
||||
RGBLookup rgb = lookup_table[index];
|
||||
led_ring.set(rgb.r, r);
|
||||
led_ring.set(rgb.g, g);
|
||||
led_ring.set(rgb.b, b);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::set_hsv(int index, float h, float s, float v) {
|
||||
int r, g, b;
|
||||
if(h < 0.0f) {
|
||||
h = 1.0f + fmod(h, 1.0f);
|
||||
}
|
||||
|
||||
int i = int(h * 6);
|
||||
float f = h * 6 - i;
|
||||
|
||||
v = v * 255.0f;
|
||||
|
||||
float sv = s * v;
|
||||
float fsv = f * sv;
|
||||
|
||||
auto p = uint8_t(-sv + v);
|
||||
auto q = uint8_t(-fsv + v);
|
||||
auto t = uint8_t(fsv - sv + v);
|
||||
|
||||
uint8_t bv = uint8_t(v);
|
||||
|
||||
switch (i % 6) {
|
||||
default:
|
||||
case 0: r = bv; g = t; b = p; break;
|
||||
case 1: r = q; g = bv; b = p; break;
|
||||
case 2: r = p; g = bv; b = t; break;
|
||||
case 3: r = p; g = q; b = bv; break;
|
||||
case 4: r = t; g = p; b = bv; break;
|
||||
case 5: r = bv; g = p; b = q; break;
|
||||
}
|
||||
|
||||
set_rgb(index, r, g, b);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::clear() {
|
||||
led_ring.clear();
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::show() {
|
||||
led_ring.update();
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::gpio_pin_mode(int gpio) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::gpio_pin_mode(int gpio, int mode) {
|
||||
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::gpio_pin_value(int gpio) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::gpio_pin_value_as_voltage(int gpio) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::gpio_pin_value(int gpio, int value, bool load, bool wait_for_load) {
|
||||
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::gpio_pwm_load(bool wait_for_load) {
|
||||
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::gpio_pwm_frequency(float frequency, bool load, bool wait_for_load) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
/*
|
||||
bool BreakoutEncoderWheel::wheel_available() {
|
||||
return (ioe.get_interrupt_flag() > 0);
|
||||
}
|
||||
|
@ -84,8 +204,5 @@ namespace pimoroni {
|
|||
//return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::clear_wheel() {
|
||||
ioe.clear_rotary_encoder(ENC_CHANNEL);
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -13,15 +13,6 @@ namespace pimoroni {
|
|||
uint8_t b;
|
||||
};
|
||||
|
||||
//--------------------------------------------------
|
||||
// Enums
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
enum Direction : bool {
|
||||
DIRECTION_CW = true,
|
||||
DIRECTION_CCW = false
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Constants
|
||||
|
@ -29,22 +20,21 @@ namespace pimoroni {
|
|||
public:
|
||||
static const uint8_t DEFAULT_IOE_I2C_ADDRESS = 0x13;
|
||||
static const uint8_t DEFAULT_LED_I2C_ADDRESS = 0x77;
|
||||
static const uint8_t LED_I2C_ADDRESS_ALTERNATE = 0x74;
|
||||
static const uint8_t ALTERNATE_LED_I2C_ADDRESS = 0x74;
|
||||
|
||||
static const Direction DEFAULT_DIRECTION = DIRECTION_CW;
|
||||
static const Direction DEFAULT_DIRECTION = NORMAL_DIR;
|
||||
static const uint32_t DEFAULT_TIMEOUT = 1;
|
||||
|
||||
private:
|
||||
static const uint8_t SWITCH_CENTRE = 1;
|
||||
static const uint8_t SWITCH_UP = 13;
|
||||
static const uint8_t SWITCH_LEFT = 11;
|
||||
static const uint8_t SWITCH_DOWN = 4;
|
||||
static const uint8_t SWITCH_RIGHT = 2;
|
||||
|
||||
static const uint8_t ENC_CHANNEL = 1;
|
||||
static const uint8_t ENC_TERM_A = 12;
|
||||
static const uint8_t ENC_TERM_B = 3;
|
||||
|
||||
static const uint8_t ENC_CHANNEL = 1;
|
||||
static const uint8_t SW_UP = 13;
|
||||
static const uint8_t SW_DOWN = 4;
|
||||
static const uint8_t SW_LEFT = 11;
|
||||
static const uint8_t SW_RIGHT = 2;
|
||||
static const uint8_t SW_CENTRE = 1;
|
||||
|
||||
// This wonderful lookup table maps the LEDs on the encoder wheel
|
||||
// from their 3x24 (remember, they're RGB) configuration to
|
||||
|
@ -85,7 +75,7 @@ namespace pimoroni {
|
|||
IS31FL3731 led_ring;
|
||||
//Direction direction = DEFAULT_DIRECTION;
|
||||
uint interrupt_pin = PIN_UNUSED; // A local copy of the value passed to the IOExpander, used in initialisation
|
||||
|
||||
Direction enc_direction = DEFAULT_DIRECTION;
|
||||
|
||||
//--------------------------------------------------
|
||||
// Constructors/Destructor
|
||||
|
@ -118,17 +108,29 @@ namespace pimoroni {
|
|||
void clear_interrupt_flag();
|
||||
|
||||
// Encoder breakout specific
|
||||
Direction get_encoder_direction();
|
||||
void set_encoder_direction(Direction direction);
|
||||
bool pressed(uint button);
|
||||
int count();
|
||||
int delta();
|
||||
int step();
|
||||
int turn();
|
||||
void zero();
|
||||
float revolutions();
|
||||
float degrees();
|
||||
float radians();
|
||||
Direction direction();
|
||||
void direction(Direction direction);
|
||||
void set_rgb(int index, int r, int g, int b);
|
||||
void set_hsv(int index, float h, float s = 1.0f, float v = 1.0f);
|
||||
void clear();
|
||||
void show();
|
||||
|
||||
void set_pixel(uint8_t index, uint8_t r, uint8_t g, uint8_t b);
|
||||
//void update(uint8_t frame = 0);
|
||||
//void clear();
|
||||
|
||||
bool wheel_available();
|
||||
int16_t read_wheel();
|
||||
void clear_wheel();
|
||||
bool read_switch();
|
||||
int gpio_pin_mode(int gpio);
|
||||
void gpio_pin_mode(int gpio, int mode);
|
||||
int gpio_pin_value(int gpio);
|
||||
float gpio_pin_value_as_voltage(int gpio);
|
||||
void gpio_pin_value(int gpio, int value, bool load = true, bool wait_for_load = false);
|
||||
void gpio_pwm_load(bool wait_for_load = false);
|
||||
int gpio_pwm_frequency(float frequency, bool load = true, bool wait_for_load = false);
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import time
|
||||
from datetime import datetime
|
||||
from machine import RTC
|
||||
|
||||
from pimoroni_i2c import PimoroniI2C
|
||||
from breakout_encoder_wheel import BreakoutEncoderWheel, NUM_LEDS
|
||||
|
@ -13,6 +13,12 @@ Press Ctrl+C to stop the program.
|
|||
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
|
||||
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
|
||||
|
||||
# Datetime Indices
|
||||
HOUR = 4
|
||||
MINUTE = 5
|
||||
SECOND = 6
|
||||
MICROSECOND = 7
|
||||
|
||||
# Constants
|
||||
BRIGHTNESS = 1.0 # The brightness of the LEDs
|
||||
UPDATES = 50 # How many times the LEDs will be updated per second
|
||||
|
@ -27,12 +33,13 @@ MILLIS_PER_HALF_DAY = MILLIS_PER_HOUR * 12
|
|||
# Create a new BreakoutEncoderWheel
|
||||
i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)
|
||||
wheel = BreakoutEncoderWheel(i2c)
|
||||
rtc = machine.RTC()
|
||||
|
||||
|
||||
# Sleep until a specific time in the future. Use this instead of time.sleep() to correct for
|
||||
# inconsistent timings when dealing with complex operations or external communication
|
||||
def sleep_until(end_time):
|
||||
time_to_sleep = end_time - time.monotonic()
|
||||
time_to_sleep = end_time - (time.ticks_ms() / 1000)
|
||||
if time_to_sleep > 0.0:
|
||||
time.sleep(time_to_sleep)
|
||||
|
||||
|
@ -58,22 +65,22 @@ def led_brightness_at(led, position, half_width=1, span=1):
|
|||
elif lower < 0.0:
|
||||
brightness = clamp((led - (lower + NUM_LEDS)) / span, brightness, 1.0)
|
||||
|
||||
return brightness * BRIGHTNESS * 255
|
||||
return int(brightness * BRIGHTNESS * 255)
|
||||
|
||||
|
||||
# Make rainbows
|
||||
while True:
|
||||
|
||||
# Record the start time of this loop
|
||||
start_time = time.monotonic()
|
||||
start_time = time.ticks_ms() / 1000
|
||||
|
||||
# Get the current system time
|
||||
now = datetime.now()
|
||||
now = rtc.datetime()
|
||||
|
||||
# Convert the seconds, minutes, and hours into milliseconds (this is done to give a smoother animation, particularly for the seconds hand)
|
||||
sec_as_millis = (now.second * MILLIS_PER_SECOND) + (now.microsecond // MILLIS_PER_SECOND)
|
||||
min_as_millis = (now.minute * MILLIS_PER_MINUTE) + sec_as_millis
|
||||
hour_as_millis = ((now.hour % 12) * MILLIS_PER_HOUR) + min_as_millis
|
||||
sec_as_millis = (now[SECOND] * MILLIS_PER_SECOND) + (now[MICROSECOND] // MILLIS_PER_SECOND)
|
||||
min_as_millis = (now[MINUTE] * MILLIS_PER_MINUTE) + sec_as_millis
|
||||
hour_as_millis = ((now[HOUR] % 12) * MILLIS_PER_HOUR) + min_as_millis
|
||||
|
||||
# Calculate the position on the LED ring that the, second, minute, and hour hands should be
|
||||
sec_pos = min(sec_as_millis / MILLIS_PER_MINUTE, 1.0) * NUM_LEDS
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import time
|
||||
from colorsys import hsv_to_rgb
|
||||
|
||||
from pimoroni_i2c import PimoroniI2C
|
||||
from breakout_encoder_wheel import BreakoutEncoderWheel, UP, DOWN, LEFT, RIGHT, CENTRE, NUM_LEDS
|
||||
|
@ -38,6 +37,30 @@ changed = True
|
|||
last_centre_pressed = False
|
||||
|
||||
|
||||
# From CPython Lib/colorsys.py
|
||||
def hsv_to_rgb(h, s, v):
|
||||
if s == 0.0:
|
||||
return v, v, v
|
||||
i = int(h * 6.0)
|
||||
f = (h * 6.0) - i
|
||||
p = v * (1.0 - s)
|
||||
q = v * (1.0 - s * f)
|
||||
t = v * (1.0 - s * (1.0 - f))
|
||||
i = i % 6
|
||||
if i == 0:
|
||||
return v, t, p
|
||||
if i == 1:
|
||||
return q, v, p
|
||||
if i == 2:
|
||||
return p, v, t
|
||||
if i == 3:
|
||||
return p, q, v
|
||||
if i == 4:
|
||||
return t, p, v
|
||||
if i == 5:
|
||||
return v, p, q
|
||||
|
||||
|
||||
# Simple function to clamp a value between 0.0 and 1.0
|
||||
def clamp01(value):
|
||||
return max(min(value, 1.0), 0.0)
|
||||
|
@ -46,14 +69,14 @@ def clamp01(value):
|
|||
# Sleep until a specific time in the future. Use this instead of time.sleep() to correct for
|
||||
# inconsistent timings when dealing with complex operations or external communication
|
||||
def sleep_until(end_time):
|
||||
time_to_sleep = end_time - time.monotonic()
|
||||
time_to_sleep = end_time - (time.ticks_ms() / 1000)
|
||||
if time_to_sleep > 0.0:
|
||||
time.sleep(time_to_sleep)
|
||||
|
||||
|
||||
while True:
|
||||
# Record the start time of this loop
|
||||
start_time = time.monotonic()
|
||||
start_time = time.ticks_ms() / 1000
|
||||
|
||||
# If up is pressed, increase the brightness
|
||||
if wheel.pressed(UP):
|
||||
|
@ -95,7 +118,7 @@ while True:
|
|||
if changed:
|
||||
# Print the colour at the current hue, saturation, and brightness
|
||||
r, g, b = [int(c * 255) for c in hsv_to_rgb(position / NUM_LEDS, saturation, brightness)]
|
||||
print("Colour Code = #", hex(r)[2:].zfill(2), hex(g)[2:].zfill(2), hex(b)[2:].zfill(2), sep="")
|
||||
print("Colour Code = #", '{:02x}'.format(r), '{:02x}'.format(g), '{:02x}'.format(b), sep="")
|
||||
|
||||
# Set the LED at the current position to either the actual colour,
|
||||
# or an inverted version to show a "selection marker"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import math
|
||||
import time
|
||||
|
||||
from ioexpander import PWM
|
||||
from breakout_ioexpander import BreakoutIOExpander
|
||||
from pimoroni_i2c import PimoroniI2C
|
||||
from breakout_encoder_wheel import BreakoutEncoderWheel, CENTRE, GPIOS, NUM_GPIOS
|
||||
|
||||
|
@ -28,7 +28,7 @@ period = wheel.gpio_pwm_frequency(FREQUENCY)
|
|||
|
||||
# Set the GPIO pins to PWM outputs
|
||||
for g in GPIOS:
|
||||
wheel.gpio_pin_mode(g, PWM)
|
||||
wheel.gpio_pin_mode(g, BreakoutIOExpander.PIN_PWM)
|
||||
|
||||
offset = 0.0
|
||||
|
||||
|
@ -36,7 +36,7 @@ offset = 0.0
|
|||
# Sleep until a specific time in the future. Use this instead of time.sleep() to correct for
|
||||
# inconsistent timings when dealing with complex operations or external communication
|
||||
def sleep_until(end_time):
|
||||
time_to_sleep = end_time - time.monotonic()
|
||||
time_to_sleep = end_time - (time.ticks_ms() / 1000)
|
||||
if time_to_sleep > 0.0:
|
||||
time.sleep(time_to_sleep)
|
||||
|
||||
|
@ -45,7 +45,7 @@ def sleep_until(end_time):
|
|||
while not wheel.pressed(CENTRE):
|
||||
|
||||
# Record the start time of this loop
|
||||
start_time = time.monotonic()
|
||||
start_time = time.ticks_ms() / 1000
|
||||
|
||||
offset += SPEED / 1000.0
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ offset = 0.0
|
|||
# Sleep until a specific time in the future. Use this instead of time.sleep() to correct for
|
||||
# inconsistent timings when dealing with complex operations or external communication
|
||||
def sleep_until(end_time):
|
||||
time_to_sleep = end_time - time.monotonic()
|
||||
time_to_sleep = end_time - (time.ticks_ms() / 1000)
|
||||
if time_to_sleep > 0.0:
|
||||
time.sleep(time_to_sleep)
|
||||
|
||||
|
@ -38,7 +38,7 @@ def sleep_until(end_time):
|
|||
while True:
|
||||
|
||||
# Record the start time of this loop
|
||||
start_time = time.monotonic()
|
||||
start_time = time.ticks_ms() / 1000
|
||||
|
||||
offset += SPEED / 1000.0
|
||||
|
||||
|
|
|
@ -49,13 +49,13 @@ def clamp(n, smallest, largest):
|
|||
# Sleep until a specific time in the future. Use this instead of time.sleep() to correct for
|
||||
# inconsistent timings when dealing with complex operations or external communication
|
||||
def sleep_until(end_time):
|
||||
time_to_sleep = end_time - time.monotonic()
|
||||
time_to_sleep = end_time - (time.ticks_ms() / 1000)
|
||||
if time_to_sleep > 0.0:
|
||||
time.sleep(time_to_sleep)
|
||||
|
||||
|
||||
# Record the current time
|
||||
current_time = time.monotonic()
|
||||
current_time = (time.ticks_ms() / 1000)
|
||||
|
||||
# Run the update loop forever
|
||||
while True:
|
||||
|
|
|
@ -104,7 +104,7 @@ STATIC const mp_rom_map_elem_t breakout_encoder_wheel_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_INT(1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LEFT), MP_ROM_INT(2) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RIGHT), MP_ROM_INT(3) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_CENTRE), MP_ROM_INT(5) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_CENTRE), MP_ROM_INT(4) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_INT(7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_INT(8) },
|
||||
|
|
|
@ -81,7 +81,7 @@ extern mp_obj_t BreakoutEncoderWheel_pressed(mp_obj_t self_in, mp_obj_t button_i
|
|||
int button = mp_obj_get_int(button_in);
|
||||
|
||||
if(button < 0 || button >= 5) {
|
||||
mp_raise_ValueError("button out of range. Expected 0 to 4")
|
||||
mp_raise_ValueError("button out of range. Expected 0 to 4");
|
||||
}
|
||||
|
||||
return mp_obj_new_bool(self->breakout->pressed(button));
|
||||
|
@ -195,9 +195,9 @@ extern mp_obj_t BreakoutEncoderWheel_set_hsv(size_t n_args, const mp_obj_t *pos_
|
|||
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_QSTR_h, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_s, MP_ARG_INT, { .u_obj = mp_const_none }},
|
||||
{ MP_QSTR_v, MP_ARG_INT, { .u_obj = mp_const_none }},
|
||||
{ MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_s, MP_ARG_OBJ, { .u_obj = mp_const_none }},
|
||||
{ MP_QSTR_v, MP_ARG_OBJ, { .u_obj = mp_const_none }},
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
|
|
Ładowanie…
Reference in New Issue