Ported most encoder wheel examples to C++
This commit is contained in:
parent
e3f9f14dcf
commit
9f925b5259
|
@ -1,5 +1,6 @@
|
|||
add_subdirectory(breakout_dotmatrix)
|
||||
add_subdirectory(breakout_encoder)
|
||||
add_subdirectory(breakout_encoder_wheel)
|
||||
add_subdirectory(breakout_ioexpander)
|
||||
add_subdirectory(breakout_ltr559)
|
||||
add_subdirectory(breakout_colourlcd160x80)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
add_subdirectory(buttons)
|
||||
add_subdirectory(chase_game)
|
||||
add_subdirectory(clock)
|
||||
add_subdirectory(colour_picker)
|
||||
add_subdirectory(encoder)
|
||||
#add_subdirectory(gpio_pwm)
|
||||
add_subdirectory(led_rainbow)
|
||||
add_subdirectory(stop_watch)
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_buttons)
|
||||
add_executable(${OUTPUT_NAME} buttons.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,95 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
A demonstration of reading the 5 buttons on Encoder Wheel.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
const std::string BUTTON_NAMES[] = {"Up", "Down", "Left", "Right", "Centre"};
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
bool last_pressed[NUM_BUTTONS] = {false, false, false, false, false};
|
||||
bool pressed[NUM_BUTTONS] = {false, false, false, false, false};
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Read all of the encoder wheel's buttons
|
||||
for(int b = 0 ; b < NUM_BUTTONS; b++) {
|
||||
pressed[b] = wheel.pressed(b);
|
||||
if(pressed[b] != last_pressed[b]) {
|
||||
printf("%s %s\n", BUTTON_NAMES[b].c_str(), pressed[b] ? "Pressed" : "Released");
|
||||
}
|
||||
last_pressed[b] = pressed[b];
|
||||
}
|
||||
|
||||
// Clear the LED ring
|
||||
wheel.clear();
|
||||
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
if(i % 6 == 3) {
|
||||
wheel.set_rgb(i, 64, 64, 64);
|
||||
}
|
||||
}
|
||||
|
||||
// If up is pressed, set the top LEDs to yellow
|
||||
if(pressed[UP]) {
|
||||
int mid = NUM_LEDS;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 255, 255, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If right is pressed, set the right LEDs to red
|
||||
if(pressed[RIGHT]) {
|
||||
int mid = NUM_LEDS / 4;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If down is pressed, set the bottom LEDs to green
|
||||
if(pressed[DOWN]) {
|
||||
int mid = NUM_LEDS / 2;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 0, 255, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If left is pressed, set the left LEDs to blue
|
||||
if(pressed[LEFT]) {
|
||||
int mid = (NUM_LEDS * 3) / 4;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 0, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
// If centre is pressed, set the diagonal LEDs to half white
|
||||
if(pressed[CENTRE]) {
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
if(i % 6 >= 2 && i % 6 <= 4) {
|
||||
wheel.set_rgb(i, 128, 128, 128);
|
||||
}
|
||||
}
|
||||
}
|
||||
wheel.show();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_chase_game)
|
||||
add_executable(${OUTPUT_NAME} chase_game.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,147 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
A simple alignment game. Use Encoder Wheel's rotary dial to align the coloured band
|
||||
to the white goal. The closer to the goal, the greener your coloured band will be.
|
||||
When you reach the goal, the goal will move to a new random position.
|
||||
*/
|
||||
|
||||
// The band colour hues to show in Angle mode
|
||||
constexpr float GOAL_HUE = 0.333f;
|
||||
constexpr float FAR_HUE = 0.0f;
|
||||
|
||||
// The width and colour settings for the band
|
||||
constexpr float BAND_WIDTH = 5.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_MARGIN = 1.0f;
|
||||
constexpr float GOAL_WIDTH = BAND_WIDTH + (2.0f * GOAL_MARGIN);
|
||||
constexpr float GOAL_BRIGHTNESS = 0.4f;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
float goal_position = 0.0f;
|
||||
int16_t band_position = 0;
|
||||
|
||||
|
||||
// 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.0f && goal_width > 0.0) {
|
||||
float band_start = centre_position - (width / 2);
|
||||
float band_end = centre_position + (width / 2);
|
||||
float band_centre = centre_position;
|
||||
|
||||
float goal_start = goal_position - (goal_width / 2);
|
||||
float goal_end = goal_position + (goal_width / 2);
|
||||
|
||||
// Go through each led in the strip
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
// Set saturation and brightness values for if the led is inside or outside of the goal
|
||||
float saturation = BAND_SATURATION;
|
||||
float brightness = 0.0f;
|
||||
|
||||
if(i >= goal_start && i < goal_end) {
|
||||
saturation = BAND_IN_GOAL_SATURATION;
|
||||
brightness = GOAL_BRIGHTNESS;
|
||||
}
|
||||
if(goal_end >= NUM_LEDS && i + NUM_LEDS < goal_end) {
|
||||
saturation = BAND_IN_GOAL_SATURATION;
|
||||
brightness = GOAL_BRIGHTNESS;
|
||||
}
|
||||
if(goal_start < 0 && i - NUM_LEDS >= goal_start) {
|
||||
saturation = BAND_IN_GOAL_SATURATION;
|
||||
brightness = GOAL_BRIGHTNESS;
|
||||
}
|
||||
|
||||
float val = brightness;
|
||||
float sat = 0.0f;
|
||||
if(i >= band_start && i < band_end) {
|
||||
// Inside the band
|
||||
if(i < band_centre) {
|
||||
// Transition into the band
|
||||
val = map(i, band_centre, band_start, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i, band_centre, band_start, BAND_SATURATION, saturation);
|
||||
}
|
||||
else {
|
||||
val = map(i, band_centre, band_end, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i, band_centre, band_end, BAND_SATURATION, saturation);
|
||||
}
|
||||
}
|
||||
else if(band_end >= NUM_LEDS && i + NUM_LEDS < band_end && i < band_centre) {
|
||||
val = map(i + NUM_LEDS, band_centre, band_end, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i + NUM_LEDS, band_centre, band_end, BAND_SATURATION, saturation);
|
||||
}
|
||||
else if(band_start < 0 && i - NUM_LEDS >= band_start && i >= band_centre) {
|
||||
val = map(i - NUM_LEDS, band_centre, band_start, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i - NUM_LEDS, band_centre, band_start, BAND_SATURATION, saturation);
|
||||
}
|
||||
//else {
|
||||
// Outside of the band
|
||||
//}
|
||||
wheel.set_hsv(i, hue, sat, val);
|
||||
}
|
||||
wheel.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
band_position = wheel.step();
|
||||
|
||||
// Convert the difference between the band and goal positions into a colour hue
|
||||
float diff1, diff2;
|
||||
if(band_position > goal_position) {
|
||||
diff1 = band_position - goal_position;
|
||||
diff2 = (goal_position + NUM_LEDS) - band_position;
|
||||
}
|
||||
else {
|
||||
diff1 = goal_position - band_position;
|
||||
diff2 = (band_position + NUM_LEDS) - goal_position;
|
||||
}
|
||||
|
||||
float position_diff = MIN(diff1, diff2);
|
||||
float hue = map(position_diff, 0, NUM_LEDS / 2.0f, GOAL_HUE, FAR_HUE);
|
||||
|
||||
// Convert the band and goal positions to positions on the LED strip
|
||||
float strip_band_position = map(band_position, 0, NUM_LEDS, 0.0f, (float)NUM_LEDS);
|
||||
float strip_goal_position = map(goal_position, 0, NUM_LEDS, 0.0f, (float)NUM_LEDS);
|
||||
|
||||
// Draw the band and goal
|
||||
colour_band(strip_band_position, BAND_WIDTH, strip_goal_position, GOAL_WIDTH, hue);
|
||||
|
||||
// Check if the band is within the goal, and if so, set a new goal
|
||||
if(band_position >= goal_position - GOAL_MARGIN && band_position <= goal_position + GOAL_MARGIN)
|
||||
goal_position = rand() % NUM_LEDS;
|
||||
if(band_position >= NUM_LEDS && band_position + NUM_LEDS < goal_position + GOAL_MARGIN)
|
||||
goal_position = rand() % NUM_LEDS;
|
||||
if(goal_position - GOAL_MARGIN < 0 && band_position - NUM_LEDS >= goal_position + GOAL_MARGIN)
|
||||
goal_position = rand() % NUM_LEDS;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
set(OUTPUT_NAME encoderwheel_clock)
|
||||
add_executable(${OUTPUT_NAME} clock.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
hardware_rtc
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,113 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
#include "hardware/rtc.h"
|
||||
#include "pico/util/datetime.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Displays a 12 hour clock on Encoder Wheel's LED ring, getting time from the system.
|
||||
*/
|
||||
|
||||
// Datetime Indices
|
||||
const uint HOUR = 4;
|
||||
const uint MINUTE = 5;
|
||||
const uint SECOND = 6;
|
||||
|
||||
// Constants
|
||||
constexpr float BRIGHTNESS = 1.0f; // The brightness of the LEDs
|
||||
const uint UPDATES = 50; // How many times the LEDs will be updated per second
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
// Handy values for the number of milliseconds
|
||||
constexpr float MILLIS_PER_SECOND = 1000;
|
||||
constexpr float MILLIS_PER_MINUTE = MILLIS_PER_SECOND * 60;
|
||||
constexpr float MILLIS_PER_HOUR = MILLIS_PER_MINUTE * 60;
|
||||
constexpr float MILLIS_PER_HALF_DAY = MILLIS_PER_HOUR * 12;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
|
||||
// Calculates the brightness of an LED based on its index and a position along the LED ring
|
||||
int led_brightness_at(int led, float position, float half_width = 1.0f, float span = 1.0f) {
|
||||
float brightness = 0.0f;
|
||||
float upper = position + half_width;
|
||||
float lower = position - half_width;
|
||||
if(led > position)
|
||||
brightness = CLAMP((upper - led) / span, 0.0f, 1.0f);
|
||||
else
|
||||
brightness = CLAMP((led - lower) / span, 0.0f, 1.0f);
|
||||
|
||||
// Handle the LEDs being in a circle
|
||||
if(upper >= NUM_LEDS)
|
||||
brightness = CLAMP(((upper - NUM_LEDS) - led) / span, brightness, 1.0f);
|
||||
else if(lower < 0.0f)
|
||||
brightness = CLAMP((led - (lower + NUM_LEDS)) / span, brightness, 1.0f);
|
||||
|
||||
return (int)(brightness * BRIGHTNESS * 255);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Start on Thursday 4th of May 2023 14:20:00
|
||||
datetime_t now = {
|
||||
.year = 2023,
|
||||
.month = 05,
|
||||
.day = 04,
|
||||
.dotw = 4, // 0 is Sunday, so 4 is Thursday
|
||||
.hour = 14,
|
||||
.min = 20,
|
||||
.sec = 00
|
||||
};
|
||||
|
||||
// Start the RTC
|
||||
rtc_init();
|
||||
rtc_set_datetime(&now);
|
||||
|
||||
// clk_sys is >2000x faster than clk_rtc, so datetime is not updated immediately when rtc_get_datetime() is called.
|
||||
// tbe delay is up to 3 RTC clock cycles (which is 64us with the default clock settings)
|
||||
sleep_us(64);
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
// Get the current system time
|
||||
rtc_get_datetime(&now);
|
||||
|
||||
// Convert the seconds, minutes, and hours into milliseconds (this is done to give a smoother animation, particularly for the seconds hand)
|
||||
uint sec_as_millis = (now.sec * MILLIS_PER_SECOND);
|
||||
uint min_as_millis = (now.min * MILLIS_PER_MINUTE) + sec_as_millis;
|
||||
uint 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
|
||||
float sec_pos = MIN(sec_as_millis / MILLIS_PER_MINUTE, 1.0f) * NUM_LEDS;
|
||||
float min_pos = MIN(min_as_millis / MILLIS_PER_HOUR, 1.0f) * NUM_LEDS;
|
||||
float hour_pos = MIN(hour_as_millis / MILLIS_PER_HALF_DAY, 1.0f) * NUM_LEDS;
|
||||
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
// Turn on the LEDs close to the position of the current second, minute, and hour
|
||||
int r = led_brightness_at(i, sec_pos);
|
||||
int g = led_brightness_at(i, min_pos);
|
||||
int b = led_brightness_at(i, hour_pos);
|
||||
wheel.set_rgb(i, r, g, b);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_colour_picker)
|
||||
add_executable(${OUTPUT_NAME} colour_picker.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,167 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Create a colour wheel on the Encoder Wheel's LED ring, and use all functions of the wheel to interact with it.
|
||||
|
||||
Rotate the wheel to select a Hue
|
||||
Press the up direction to increase Brightness
|
||||
Press the down direction to decrease Brightness
|
||||
Press the left direction to decrease Saturation
|
||||
Press the right direction to increase Saturation
|
||||
Press the centre to hide the selection marker
|
||||
*/
|
||||
|
||||
// Constants
|
||||
constexpr float BRIGHTNESS_STEP = 0.02f; // How much to increase or decrease the brightness each update
|
||||
constexpr float SATURATION_STEP = 0.02f; // How much to increase or decrease the saturation each update
|
||||
const uint UPDATES = 50; // How many times to update the LEDs per second
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
float brightness = 1.0f;
|
||||
float saturation = 1.0f;
|
||||
int position = 0;
|
||||
bool changed = true;
|
||||
bool last_centre_pressed = false;
|
||||
|
||||
// Struct for storing RGB values
|
||||
struct Pixel {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
Pixel() : r(0), g(0), b(0) {};
|
||||
Pixel(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {};
|
||||
};
|
||||
|
||||
// Basic function to convert Hue, Saturation and Value to an RGB colour
|
||||
Pixel hsv_to_rgb(float h, float s, float v) {
|
||||
if(h < 0.0f) {
|
||||
h = 1.0f + fmodf(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: return Pixel(bv, t, p);
|
||||
case 1: return Pixel(q, bv, p);
|
||||
case 2: return Pixel(p, bv, t);
|
||||
case 3: return Pixel(p, q, bv);
|
||||
case 4: return Pixel(t, p, bv);
|
||||
case 5: return Pixel(bv, p, q);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple function to clamp a value between 0.0 and 1.0
|
||||
float clamp01(float value) {
|
||||
return MAX(MIN(value, 1.0f), 0.0f);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
// If up is pressed, increase the brightness
|
||||
if(wheel.pressed(UP)) {
|
||||
brightness += BRIGHTNESS_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If down is pressed, decrease the brightness
|
||||
if(wheel.pressed(DOWN)) {
|
||||
brightness -= BRIGHTNESS_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If right is pressed, increase the saturation
|
||||
if(wheel.pressed(RIGHT)) {
|
||||
saturation += SATURATION_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If left is pressed, decrease the saturation
|
||||
if(wheel.pressed(LEFT)) {
|
||||
saturation -= SATURATION_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// Limit the brightness and saturation between 0.0 and 1.0
|
||||
brightness = clamp01(brightness);
|
||||
saturation = clamp01(saturation);
|
||||
|
||||
// Check if the encoder has been turned
|
||||
if(wheel.delta() != 0) {
|
||||
// Update the position based on the count change
|
||||
position = wheel.step();
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If centre is pressed, trigger a change
|
||||
bool centre_pressed = wheel.pressed(CENTRE);
|
||||
if(centre_pressed != last_centre_pressed) {
|
||||
changed = true;
|
||||
}
|
||||
last_centre_pressed = centre_pressed;
|
||||
|
||||
// Was a change triggered?
|
||||
if(changed) {
|
||||
// Print the colour at the current hue, saturation, and brightness
|
||||
Pixel pixel = hsv_to_rgb((float)position / NUM_LEDS, saturation, brightness);
|
||||
printf("Colour Code = #%02x%02x%02x\n", pixel.r, pixel.g, pixel.b);
|
||||
|
||||
// Set the LED at the current position to either the actual colour,
|
||||
// or an inverted version to show a "selection marker"
|
||||
if(centre_pressed)
|
||||
wheel.set_rgb(position, pixel.r, pixel.g, pixel.b);
|
||||
else
|
||||
wheel.set_rgb(position, 255 - pixel.r, 255 - pixel.g, 255 - pixel.b);
|
||||
|
||||
// Set the LEDs below the current position
|
||||
for(int i = 0; i < position; i++) {
|
||||
wheel.set_hsv(i, (float)i / NUM_LEDS, saturation, brightness);
|
||||
}
|
||||
|
||||
// Set the LEDs after the current position
|
||||
for(int i = position + 1; i < NUM_LEDS; i++) {
|
||||
wheel.set_hsv(i, (float)i / NUM_LEDS, saturation, brightness);
|
||||
}
|
||||
wheel.show();
|
||||
changed = false;
|
||||
}
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_encoder)
|
||||
add_executable(${OUTPUT_NAME} encoder.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,59 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
A demonstration of reading the rotary dial of the Encoder Wheel breakout.
|
||||
*/
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
int position = 0;
|
||||
float hue = 0.0f;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
|
||||
// Set the first LED
|
||||
wheel.clear();
|
||||
wheel.set_hsv(position, hue, 1.0f, 1.0f);
|
||||
wheel.show();
|
||||
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Has the dial been turned since the last time we checked?
|
||||
int16_t change = wheel.delta();
|
||||
if(change != 0) {
|
||||
// Print out the direction the dial was turned, and the count
|
||||
if(change > 0)
|
||||
printf("Clockwise, Count = %d\n", wheel.count());
|
||||
else
|
||||
printf("Counter Clockwise, Count = %d\n", wheel.count());
|
||||
|
||||
// Record the new position (from 0 to 23)
|
||||
position = wheel.step();
|
||||
|
||||
// Record a colour hue from 0.0 to 1.0
|
||||
hue = fmodf(wheel.revolutions(), 1.0f);
|
||||
|
||||
// Set the LED at the new position to the new hue
|
||||
wheel.clear();
|
||||
wheel.set_hsv(position, hue, 1.0f, 1.0f);
|
||||
wheel.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_led_rainbow)
|
||||
add_executable(${OUTPUT_NAME} led_rainbow.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,53 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Displays a rotating rainbow pattern on Encoder Wheel's LED ring.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
constexpr float SPEED = 5.0f; // The speed that the LEDs will cycle at
|
||||
constexpr float BRIGHTNESS = 1.0f; // The brightness of the LEDs
|
||||
const uint UPDATES = 50; // How many times the LEDs will be updated per second
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
float offset = 0.0;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
offset += SPEED / 1000.0f;
|
||||
|
||||
// Update all the LEDs
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
float hue = (float)i / NUM_LEDS;
|
||||
wheel.set_hsv(i, hue + offset, 1.0, BRIGHTNESS);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_stop_watch)
|
||||
add_executable(${OUTPUT_NAME} stop_watch.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,150 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Display a circular stop-watch on the Encoder Wheel's LED ring.
|
||||
|
||||
Press the centre button to start the stopwatch, then again to pause and resume.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
constexpr float BRIGHTNESS = 1.0f; // The brightness of the LEDs
|
||||
const uint UPDATES = 50; // How many times the LEDs will be updated per second
|
||||
const uint MINUTE_UPDATES = UPDATES * 60; // How many times the LEDs will be updated per minute
|
||||
const uint HOUR_UPDATES = MINUTE_UPDATES * 60; // How many times the LEDs will be updated per hour
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
constexpr float IDLE_PULSE_MIN = 0.2f; // The brightness (between 0.0 and 1.0) that the idle pulse will go down to
|
||||
constexpr float IDLE_PULSE_MAX = 0.5f; // The brightness (between 0.0 and 1.0) that the idle pulse will go up to
|
||||
constexpr float IDLE_PULSE_TIME = 2.0f; // The time (in seconds) to perform a complete idle pulse
|
||||
constexpr uint UPDATES_PER_PULSE = IDLE_PULSE_TIME * UPDATES;
|
||||
|
||||
// The state constants used for program flow
|
||||
enum State {
|
||||
IDLE = 0,
|
||||
COUNTING,
|
||||
PAUSED
|
||||
};
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
State state = IDLE;
|
||||
uint idle_update = 0;
|
||||
uint second_update = 0;
|
||||
uint minute_update = 0;
|
||||
uint hour_update = 0;
|
||||
bool last_centre_pressed = false;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Record the current time
|
||||
absolute_time_t current_time = get_absolute_time();
|
||||
|
||||
// Run the update loop forever
|
||||
while(true) {
|
||||
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
// Read whether or not the wheen centre has been pressed
|
||||
bool centre_pressed = wheel.pressed(CENTRE);
|
||||
if(centre_pressed && centre_pressed != last_centre_pressed) {
|
||||
switch(state) {
|
||||
case IDLE: // If we're currently idle, switch to counting
|
||||
second_update = 0;
|
||||
minute_update = 0;
|
||||
hour_update = 0;
|
||||
state = COUNTING;
|
||||
break;
|
||||
case COUNTING: // If we're counting, switch to paused
|
||||
state = PAUSED;
|
||||
break;
|
||||
case PAUSED: // If we're paused, switch back to counting
|
||||
state = COUNTING;
|
||||
}
|
||||
}
|
||||
last_centre_pressed = centre_pressed;
|
||||
|
||||
switch(state) {
|
||||
// If we're idle, perform a pulsing animation to show the stopwatch is ready to go
|
||||
case IDLE:
|
||||
{
|
||||
float percent_along = MIN((float)idle_update / (float)UPDATES_PER_PULSE, 1.0f);
|
||||
float brightness = ((cosf(percent_along * M_PI * 2.0f) + 1.0f) / 2.0f) * ((IDLE_PULSE_MAX - IDLE_PULSE_MIN)) + IDLE_PULSE_MIN;
|
||||
// Update all the LEDs
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
wheel.set_hsv(i, 0.0, 0.0, brightness);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Advance to the next update, wrapping around to zero if at the end
|
||||
idle_update += 1;
|
||||
if(idle_update >= UPDATES_PER_PULSE) {
|
||||
idle_update = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// If we're counting, perform the stopwatch animation
|
||||
case COUNTING:
|
||||
{
|
||||
// Calculate how many LED channels should light, as a proportion of a second, minute, and hour
|
||||
float r_to_light = MIN((float)second_update / UPDATES, 1.0f) * 24.0f;
|
||||
float g_to_light = MIN((float)minute_update / MINUTE_UPDATES, 1.0f) * 24.0f;
|
||||
float b_to_light = MIN((float)hour_update / HOUR_UPDATES, 1.0f) * 24.0f;
|
||||
|
||||
// Set each LED, such that ones below the current time are fully lit, ones after
|
||||
// are off, and the one at the transition is at a percentage of the brightness
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
int r = (int)(CLAMP(r_to_light - i, 0.0f, 1.0f) * BRIGHTNESS * 255.0f);
|
||||
int g = (int)(CLAMP(g_to_light - i, 0.0f, 1.0f) * BRIGHTNESS * 255.0f);
|
||||
int b = (int)(CLAMP(b_to_light - i, 0.0f, 1.0f) * BRIGHTNESS * 255.0f);
|
||||
wheel.set_rgb(i, r, g, b);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Advance the second updates count, wrapping around to zero if at the end
|
||||
second_update += 1;
|
||||
if(second_update >= UPDATES) {
|
||||
second_update = 0;
|
||||
}
|
||||
|
||||
// Advance the minute updates count, wrapping around to zero if at the end
|
||||
minute_update += 1;
|
||||
if(minute_update >= MINUTE_UPDATES) {
|
||||
minute_update = 0;
|
||||
}
|
||||
|
||||
// Advance the hour updates count, wrapping around to zero if at the end
|
||||
hour_update += 1;
|
||||
if(hour_update >= HOUR_UPDATES) {
|
||||
hour_update = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PAUSED:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
current_time = delayed_by_us(start_time, UPDATE_RATE_US);
|
||||
sleep_until(current_time);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include <cmath>
|
||||
|
||||
namespace pimoroni {
|
||||
namespace encoderwheel {
|
||||
|
||||
bool BreakoutEncoderWheel::init(bool skip_chip_id_check) {
|
||||
bool success = false;
|
||||
|
@ -151,7 +152,7 @@ namespace pimoroni {
|
|||
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);
|
||||
h = 1.0f + fmodf(h, 1.0f);
|
||||
}
|
||||
|
||||
int i = int(h * 6);
|
||||
|
@ -244,4 +245,5 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,21 @@
|
|||
#include "common/pimoroni_common.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
namespace encoderwheel {
|
||||
static const uint8_t NUM_LEDS = 24;
|
||||
static const uint8_t NUM_BUTTONS = 5;
|
||||
static const uint8_t NUM_GPIOS = 3;
|
||||
|
||||
static const uint8_t UP = 0;
|
||||
static const uint8_t DOWN = 1;
|
||||
static const uint8_t LEFT = 2;
|
||||
static const uint8_t RIGHT = 3;
|
||||
static const uint8_t CENTRE = 4;
|
||||
|
||||
static const uint8_t GP7 = 7;
|
||||
static const uint8_t GP8 = 8;
|
||||
static const uint8_t GP9 = 9;
|
||||
static const uint8_t GPIOS[] = {GP7, GP8, GP9};
|
||||
|
||||
class BreakoutEncoderWheel {
|
||||
struct RGBLookup {
|
||||
|
@ -142,5 +157,5 @@ namespace pimoroni {
|
|||
private:
|
||||
void take_encoder_reading();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -12,8 +12,6 @@ PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
|
|||
|
||||
# Constants
|
||||
BUTTON_NAMES = ["Up", "Down", "Left", "Right", "Centre"]
|
||||
UPDATES = 50 # How many times the buttons will be checked and LEDs updated, per second
|
||||
UPDATE_RATE = 1 / UPDATES
|
||||
|
||||
# Create a new BreakoutEncoderWheel
|
||||
i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)
|
||||
|
|
Loading…
Reference in New Issue