kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Added audio tone and motor functions to PicoExplorer library and demo
rodzic
96d702ef9a
commit
b659709f5a
|
@ -106,6 +106,7 @@ int main() {
|
||||||
shapes.push_back(shape);
|
shapes.push_back(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pico_explorer.set_audio_pin(pico_explorer.GP0);
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
pico_explorer.set_pen(120, 40, 60);
|
pico_explorer.set_pen(120, 40, 60);
|
||||||
|
@ -123,13 +124,30 @@ int main() {
|
||||||
pico_explorer.circle(shape.x, shape.y, shape.r);
|
pico_explorer.circle(shape.x, shape.y, shape.r);
|
||||||
}
|
}
|
||||||
|
|
||||||
float led_step = fmod(i / 20.0f, M_PI * 2.0f);
|
|
||||||
int r = (sin(led_step) * 25.0f) + 25.0f;
|
|
||||||
pico_explorer.set_led(r, r / 1.2f, r);
|
|
||||||
|
|
||||||
pico_explorer.set_pen(255, 255, 255);
|
pico_explorer.set_pen(255, 255, 255);
|
||||||
pico_explorer.text("This is a test of some text data that should wrap nicely onto multiple lines which is dead useful like.", 10, 10, 180);
|
pico_explorer.text("This is a test of some text data that should wrap nicely onto multiple lines which is dead useful like.", 10, 10, 180);
|
||||||
|
|
||||||
|
float rv = pico_explorer.get_adc(pico_explorer.ADC0);
|
||||||
|
pico_explorer.set_pen(255, 255, 255);
|
||||||
|
pico_explorer.circle(rv * 140 + 50, 110, 20);
|
||||||
|
pico_explorer.set_pen(rv * 255, 0, 0);
|
||||||
|
pico_explorer.circle(rv * 140 + 50, 110, 15);
|
||||||
|
|
||||||
|
float gv = pico_explorer.get_adc(pico_explorer.ADC1);
|
||||||
|
pico_explorer.set_pen(255, 255, 255);
|
||||||
|
pico_explorer.circle(gv * 140 + 50, 160, 20);
|
||||||
|
pico_explorer.set_pen(0, gv * 255, 0);
|
||||||
|
pico_explorer.circle(gv * 140 + 50, 160, 15);
|
||||||
|
|
||||||
|
float bv = pico_explorer.get_adc(pico_explorer.ADC2);
|
||||||
|
pico_explorer.set_pen(255, 255, 255);
|
||||||
|
pico_explorer.circle(bv * 140 + 50, 210, 20);
|
||||||
|
pico_explorer.set_pen(0, 0, bv * 255);
|
||||||
|
pico_explorer.circle(bv * 140 + 50, 210, 15);
|
||||||
|
|
||||||
|
pico_explorer.set_motor(pico_explorer.MOTOR1, pico_explorer.FORWARD, bv);
|
||||||
|
|
||||||
|
pico_explorer.set_tone(100 + (bv * 1000), rv);
|
||||||
/*
|
/*
|
||||||
if(pico_display.is_pressed(pico_display.A)) {
|
if(pico_display.is_pressed(pico_display.A)) {
|
||||||
pico_display.rectangle(0, 0, 18, 18);
|
pico_display.rectangle(0, 0, 18, 18);
|
||||||
|
|
|
@ -1,69 +1,110 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "hardware/pwm.h"
|
#include "hardware/pwm.h"
|
||||||
|
#include "hardware/adc.h"
|
||||||
|
|
||||||
#include "pico_explorer.hpp"
|
#include "pico_explorer.hpp"
|
||||||
|
|
||||||
const uint8_t LED_R = 6;
|
const uint8_t MOTOR1N = 8;
|
||||||
const uint8_t LED_G = 7;
|
const uint8_t MOTOR1P = 9;
|
||||||
const uint8_t LED_B = 8;
|
const uint8_t MOTOR2N = 10;
|
||||||
|
const uint8_t MOTOR2P = 11;
|
||||||
|
|
||||||
namespace pimoroni {
|
namespace pimoroni {
|
||||||
|
|
||||||
PicoExplorer::PicoExplorer()
|
PicoExplorer::PicoExplorer()
|
||||||
: screen(240, 240, __fb), PicoGraphics(240, 240, __fb) {
|
: screen(240, 240, __fb), PicoGraphics(240, 240, __fb) {
|
||||||
|
|
||||||
// setup the rgb led for pwm control
|
|
||||||
pwm_config cfg = pwm_get_default_config();
|
|
||||||
pwm_config_set_output_polarity(&cfg, true, true);
|
|
||||||
|
|
||||||
// red
|
|
||||||
pwm_set_wrap(pwm_gpio_to_slice_num(LED_R), 65535);
|
|
||||||
pwm_init(pwm_gpio_to_slice_num(LED_R), &cfg, true);
|
|
||||||
gpio_set_function(LED_R, GPIO_FUNC_PWM);
|
|
||||||
|
|
||||||
// green
|
|
||||||
pwm_set_wrap(pwm_gpio_to_slice_num(LED_G), 65535);
|
|
||||||
pwm_init(pwm_gpio_to_slice_num(LED_G), &cfg, true);
|
|
||||||
gpio_set_function(LED_G, GPIO_FUNC_PWM);
|
|
||||||
|
|
||||||
// blue
|
|
||||||
pwm_set_wrap(pwm_gpio_to_slice_num(LED_B), 65535);
|
|
||||||
pwm_init(pwm_gpio_to_slice_num(LED_B), &cfg, true);
|
|
||||||
gpio_set_function(LED_B, GPIO_FUNC_PWM);
|
|
||||||
|
|
||||||
// setup button inputs
|
// setup button inputs
|
||||||
gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A);
|
gpio_set_function(A, GPIO_FUNC_SIO); gpio_set_dir(A, GPIO_IN); gpio_pull_up(A);
|
||||||
gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B);
|
gpio_set_function(B, GPIO_FUNC_SIO); gpio_set_dir(B, GPIO_IN); gpio_pull_up(B);
|
||||||
gpio_set_function(X, GPIO_FUNC_SIO); gpio_set_dir(X, GPIO_IN); gpio_pull_up(X);
|
gpio_set_function(X, GPIO_FUNC_SIO); gpio_set_dir(X, GPIO_IN); gpio_pull_up(X);
|
||||||
gpio_set_function(Y, GPIO_FUNC_SIO); gpio_set_dir(Y, GPIO_IN); gpio_pull_up(Y);
|
gpio_set_function(Y, GPIO_FUNC_SIO); gpio_set_dir(Y, GPIO_IN); gpio_pull_up(Y);
|
||||||
|
|
||||||
|
// setup ADC channels
|
||||||
|
adc_init();
|
||||||
|
const uint8_t ADC_BASE_PIN = 26;
|
||||||
|
adc_gpio_init(ADC0 + ADC_BASE_PIN);
|
||||||
|
adc_gpio_init(ADC1 + ADC_BASE_PIN);
|
||||||
|
adc_gpio_init(ADC2 + ADC_BASE_PIN);
|
||||||
|
|
||||||
|
// setup motor pins
|
||||||
|
pwm_config motor_pwm_cfg = pwm_get_default_config();
|
||||||
|
pwm_config_set_wrap(&motor_pwm_cfg, 255);
|
||||||
|
|
||||||
|
pwm_init(pwm_gpio_to_slice_num(MOTOR1N), &motor_pwm_cfg, true);
|
||||||
|
gpio_set_function(MOTOR1N, GPIO_FUNC_PWM);
|
||||||
|
|
||||||
|
pwm_init(pwm_gpio_to_slice_num(MOTOR1P), &motor_pwm_cfg, true);
|
||||||
|
gpio_set_function(MOTOR1P, GPIO_FUNC_PWM);
|
||||||
|
|
||||||
|
pwm_init(pwm_gpio_to_slice_num(MOTOR2N), &motor_pwm_cfg, true);
|
||||||
|
gpio_set_function(MOTOR2N, GPIO_FUNC_PWM);
|
||||||
|
|
||||||
|
pwm_init(pwm_gpio_to_slice_num(MOTOR2P), &motor_pwm_cfg, true);
|
||||||
|
gpio_set_function(MOTOR2P, GPIO_FUNC_PWM);
|
||||||
|
|
||||||
// initialise the screen
|
// initialise the screen
|
||||||
screen.init();
|
screen.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicoExplorer::set_led(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
// gamma correct the provided 0-255 brightness value onto a
|
|
||||||
// 0-65535 range for the pwm counter
|
|
||||||
static const float gamma = 2.8;
|
|
||||||
|
|
||||||
uint16_t value;
|
|
||||||
|
|
||||||
// red
|
|
||||||
value = (uint16_t)(pow((float)(r) / 255.0f, gamma) * 65536.0f + 0.5f);
|
|
||||||
pwm_set_gpio_level(LED_R, value);
|
|
||||||
|
|
||||||
// green
|
|
||||||
value = (uint16_t)(pow((float)(g) / 255.0f, gamma) * 65536.0f + 0.5f);
|
|
||||||
pwm_set_gpio_level(LED_G, value);
|
|
||||||
|
|
||||||
// blue
|
|
||||||
value = (uint16_t)(pow((float)(b) / 255.0f, gamma) * 65536.0f + 0.5f);
|
|
||||||
pwm_set_gpio_level(LED_B, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PicoExplorer::is_pressed(uint8_t button) {
|
bool PicoExplorer::is_pressed(uint8_t button) {
|
||||||
return !gpio_get(button);
|
return !gpio_get(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float PicoExplorer::get_adc(uint8_t channel) {
|
||||||
|
adc_select_input(channel);
|
||||||
|
// scale raw 12-bit adc value to 0 .. 1 float
|
||||||
|
float result = float(adc_read()) / (1 << 12);
|
||||||
|
// clamp result to 0 .. 1
|
||||||
|
result = std::min(1.0f, std::max(0.0f, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PicoExplorer::set_motor(uint8_t channel, uint8_t action, float speed) {
|
||||||
|
uint8_t p = channel == MOTOR1 ? MOTOR1P : MOTOR2P;
|
||||||
|
uint8_t n = channel == MOTOR1 ? MOTOR1N : MOTOR2N;
|
||||||
|
|
||||||
|
switch(action) {
|
||||||
|
case FORWARD: {
|
||||||
|
pwm_set_gpio_level(p, speed * 255);
|
||||||
|
pwm_set_gpio_level(n, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REVERSE: {
|
||||||
|
pwm_set_gpio_level(p, 0);
|
||||||
|
pwm_set_gpio_level(n, speed * 255);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case STOP: {
|
||||||
|
pwm_set_gpio_level(p, 0);
|
||||||
|
pwm_set_gpio_level(n, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PicoExplorer::set_audio_pin(uint8_t pin) {
|
||||||
|
pwm_config tone_pwm_cfg = pwm_get_default_config();
|
||||||
|
|
||||||
|
// calculate the pwm wrap value for this frequency
|
||||||
|
// first we set the clock divider to give us exactly
|
||||||
|
// ten thousand cycles per second
|
||||||
|
pwm_config_set_clkdiv(&tone_pwm_cfg, 255);
|
||||||
|
pwm_init(pwm_gpio_to_slice_num(pin), &tone_pwm_cfg, true);
|
||||||
|
gpio_set_function(pin, GPIO_FUNC_PWM);
|
||||||
|
audio_pin = pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PicoExplorer::set_tone(uint16_t frequency, float duty) {
|
||||||
|
// output a square wave, so 50% duty cycle
|
||||||
|
if(audio_pin != -1) {
|
||||||
|
uint16_t pwm_wrap = 490196 / frequency;
|
||||||
|
pwm_set_wrap(audio_pin, pwm_wrap);
|
||||||
|
pwm_set_gpio_level(audio_pin, pwm_wrap * duty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@ namespace pimoroni {
|
||||||
class PicoExplorer : public PicoGraphics {
|
class PicoExplorer : public PicoGraphics {
|
||||||
uint16_t __fb[240 * 240];
|
uint16_t __fb[240 * 240];
|
||||||
ST7789 screen;
|
ST7789 screen;
|
||||||
|
int8_t audio_pin = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PicoExplorer();
|
PicoExplorer();
|
||||||
|
@ -15,13 +16,40 @@ namespace pimoroni {
|
||||||
void set_backlight(uint8_t brightness) {screen.set_backlight(brightness);}
|
void set_backlight(uint8_t brightness) {screen.set_backlight(brightness);}
|
||||||
void update() {screen.update();}
|
void update() {screen.update();}
|
||||||
|
|
||||||
void set_led(uint8_t r, uint8_t g, uint8_t b);
|
|
||||||
bool is_pressed(uint8_t button);
|
bool is_pressed(uint8_t button);
|
||||||
|
|
||||||
|
float get_adc(uint8_t channel);
|
||||||
|
|
||||||
|
void set_motor(uint8_t channel, uint8_t action, float speed = 0.0f);
|
||||||
|
|
||||||
|
void set_audio_pin(uint8_t pin);
|
||||||
|
void set_tone(uint16_t frequency, float duty = 0.2f);
|
||||||
|
|
||||||
static const uint8_t A = 12;
|
static const uint8_t A = 12;
|
||||||
static const uint8_t B = 13;
|
static const uint8_t B = 13;
|
||||||
static const uint8_t X = 14;
|
static const uint8_t X = 14;
|
||||||
static const uint8_t Y = 15;
|
static const uint8_t Y = 15;
|
||||||
|
|
||||||
|
static const uint8_t ADC0 = 0;
|
||||||
|
static const uint8_t ADC1 = 1;
|
||||||
|
static const uint8_t ADC2 = 2;
|
||||||
|
|
||||||
|
static const uint8_t MOTOR1 = 0;
|
||||||
|
static const uint8_t MOTOR2 = 1;
|
||||||
|
|
||||||
|
static const uint8_t FORWARD = 0;
|
||||||
|
static const uint8_t REVERSE = 1;
|
||||||
|
static const uint8_t STOP = 2;
|
||||||
|
|
||||||
|
static const uint8_t GP0 = 0;
|
||||||
|
static const uint8_t GP1 = 1;
|
||||||
|
static const uint8_t GP2 = 2;
|
||||||
|
static const uint8_t GP3 = 3;
|
||||||
|
static const uint8_t GP4 = 4;
|
||||||
|
static const uint8_t GP5 = 5;
|
||||||
|
static const uint8_t GP6 = 6;
|
||||||
|
static const uint8_t GP7 = 7;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
Ładowanie…
Reference in New Issue