kopia lustrzana https://github.com/pimoroni/pimoroni-pico
114 wiersze
3.7 KiB
C++
114 wiersze
3.7 KiB
C++
#include <math.h>
|
|
#include <string>
|
|
#include "pimoroni_i2c.hpp"
|
|
#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;
|
|
} |