Completed LedPin() and ServoPin()

Both classes check that total number of combined instantiations does not exceed 16.  ServoPin() has additional limit of only 8 instantiations.

DEPRECATED: PwmPin().  Keep for backwards compatibility only.
TO DO:  Update Tutorial Examples to replace PwmPin with LedPin, and update Extras.h documentations with LedPin and ServoPin.
This commit is contained in:
Gregg 2021-03-20 23:21:09 -05:00
parent a8dff0a7de
commit d49bca9bbe
3 changed files with 211 additions and 179 deletions

View File

@ -1,97 +1,10 @@
#include "PwmPin.h"
PwmPin::PwmPin(uint8_t channel, uint8_t pin){
this->channel=channel & 0x0F;
this->pin=pin;
ledc_timer_config_t ledTimer;
ledTimer.timer_num=LEDC_TIMER_0;
ledTimer.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE;
ledTimer.duty_resolution=LEDC_TIMER_10_BIT;
ledTimer.freq_hz=5000;
ledc_timer_config(&ledTimer);
ledChannel.gpio_num=pin;
ledChannel.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE;
ledChannel.channel=(ledc_channel_t)(this->channel&0x07);
ledChannel.intr_type=LEDC_INTR_DISABLE;
ledChannel.timer_sel=LEDC_TIMER_0;
ledChannel.duty=0;
ledChannel.hpoint=0;
ledc_channel_config(&ledChannel);
}
void PwmPin::set(uint8_t level){
ledChannel.duty=level*1023;
ledChannel.duty/=100;
ledChannel.duty&=0x03FF;
ledc_channel_config(&ledChannel);
}
///////////////////
void PwmPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){
// The algorithm below was provided on the web at https://www.cs.rit.edu/~ncs/color/t_convert.html
// h = [0,360]
// s = [0,1]
// v = [0,1]
int i;
float f, p, q, t;
if( s == 0 ){
*r = *g = *b = v;
return;
}
h /= 60;
i = floor( h ) ;
f = h - i;
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i % 6 ) {
case 0:
*r = v;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = v;
*b = p;
break;
case 2:
*r = p;
*g = v;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = v;
break;
case 4:
*r = t;
*g = p;
*b = v;
break;
case 5:
*r = v;
*g = p;
*b = q;
break;
}
}
///////////////////
LedPin::LedPin(uint8_t pin, uint8_t level){
if(numChannels>15){
if(numChannels+ServoPin::numChannels>15){
Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels ***\n\n",pin);
return;
}
@ -127,6 +40,7 @@ LedPin::LedPin(uint8_t pin, uint8_t level){
ledChannel.hpoint=0;
ledc_channel_config(&ledChannel);
set(level);
//Serial.printf("Configured LED on Pin %d using Channel %d in Speed Mode %d\n",ledChannel.gpio_num,ledChannel.channel,ledChannel.speed_mode);
}
///////////////////
@ -201,9 +115,14 @@ void LedPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){
////////////////////////////
ServoPin::ServoPin(uint8_t channel, uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees){
this->channel=channel & 0x07;
this->pin=pin;
ServoPin::ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees){
if(numChannels>7 || numChannels>(15-LedPin::numChannels)){
Serial.printf("\n*** ERROR: Can't create ServoPin(%d) - no open PWM channels ***\n\n",pin);
return;
}
enabled=true;
this->minMicros=minMicros;
this->maxMicros=maxMicros;
this->minDegrees=minDegrees;
@ -216,27 +135,129 @@ ServoPin::ServoPin(uint8_t channel, uint8_t pin, double initDegrees, uint16_t mi
ledTimer.freq_hz=50;
ledc_timer_config(&ledTimer);
ledChannel.gpio_num=pin;
ledChannel.speed_mode=LEDC_HIGH_SPEED_MODE;
ledChannel.channel=(ledc_channel_t)(this->channel);
ledChannel.intr_type=LEDC_INTR_DISABLE;
ledChannel.timer_sel=LEDC_TIMER_1;
ledChannel.hpoint=0;
ledChannel.duty*=micros2duty;
servoChannel.gpio_num=pin;
servoChannel.speed_mode=LEDC_HIGH_SPEED_MODE;
servoChannel.channel=(ledc_channel_t)numChannels++;
servoChannel.intr_type=LEDC_INTR_DISABLE;
servoChannel.timer_sel=LEDC_TIMER_1;
servoChannel.hpoint=0;
servoChannel.duty*=micros2duty;
set(initDegrees);
//Serial.printf("Configured Servo on Pin %d using Channel %d in Speed Mode %d\n",servoChannel.gpio_num,servoChannel.channel,servoChannel.speed_mode);
}
///////////////////
void ServoPin::set(double degrees){
ledChannel.duty=(degrees-minDegrees)*microsPerDegree+minMicros;
if(!enabled)
return;
if(ledChannel.duty<minMicros)
ledChannel.duty=minMicros;
else if(ledChannel.duty>maxMicros)
ledChannel.duty=maxMicros;
servoChannel.duty=(degrees-minDegrees)*microsPerDegree+minMicros;
ledChannel.duty*=micros2duty;
ledc_channel_config(&ledChannel);
if(servoChannel.duty<minMicros)
servoChannel.duty=minMicros;
else if(servoChannel.duty>maxMicros)
servoChannel.duty=maxMicros;
servoChannel.duty*=micros2duty;
ledc_channel_config(&servoChannel);
}
////////////////////////////
const double ServoPin::micros2duty=65535.0/20000.0;
uint8_t LedPin::numChannels=0;
uint8_t ServoPin::numChannels=0;
//*******************************************************
// DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY ONLY
//*******************************************************
PwmPin::PwmPin(uint8_t channel, uint8_t pin){
this->channel=channel & 0x0F;
this->pin=pin;
ledc_timer_config_t ledTimer;
ledTimer.timer_num=LEDC_TIMER_0;
ledTimer.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE;
ledTimer.duty_resolution=LEDC_TIMER_10_BIT;
ledTimer.freq_hz=5000;
ledc_timer_config(&ledTimer);
ledChannel.gpio_num=pin;
ledChannel.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE;
ledChannel.channel=(ledc_channel_t)(this->channel&0x07);
ledChannel.intr_type=LEDC_INTR_DISABLE;
ledChannel.timer_sel=LEDC_TIMER_0;
ledChannel.duty=0;
ledChannel.hpoint=0;
ledc_channel_config(&ledChannel);
}
///////////////////
void PwmPin::set(uint8_t channel, uint8_t level){
ledChannel.duty=level*1023;
ledChannel.duty/=100;
ledChannel.duty&=0x03FF;
ledc_channel_config(&ledChannel);
}
///////////////////
void PwmPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){
// The algorithm below was provided on the web at https://www.cs.rit.edu/~ncs/color/t_convert.html
// h = [0,360]
// s = [0,1]
// v = [0,1]
int i;
float f, p, q, t;
if( s == 0 ){
*r = *g = *b = v;
return;
}
h /= 60;
i = floor( h ) ;
f = h - i;
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i % 6 ) {
case 0:
*r = v;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = v;
*b = p;
break;
case 2:
*r = p;
*g = v;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = v;
break;
case 4:
*r = t;
*g = p;
*b = v;
break;
case 5:
*r = v;
*g = p;
*b = q;
break;
}
}

View File

@ -1,16 +1,69 @@
/////////////////////////////////////
// PWM Pin Control //
/////////////////////////////////////
// A wrapper around the ESP-IDF ledc library to easily set the brightness of an LED from 0-100%.
// Can be used for any device requiring a PWM output (not just an LED). Frequency of PWM
// is hardcoded to 5000 Hz and either High-Speed Timer-0 (for channels 0-7) or Low-Speed Timer-0
// for channels (8-15) is configured and selected automatically.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ----- PWM Pin Control -----
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Wrappers around the ESP-IDF ledc library to control PWM-based devices:
//
// LedPin(pin) - controls a Dimmable LED on specified pin with frequency=5000 Hz
// - use set(level) to set brightness from 0-100%
//
// ServoPin(pin) - controls a Servo Motor on specified pin with frequency=50 Hz
// - use set(degrees) to set position to degrees
//
// Max number of LedPin instantiations: 16
// Max number of ServoPin instantiatons: 8
// Max combined limit (LedPins+ServoPins): 16
//
// Instantiation of an LedPin or ServoPin that causes any of the maximums above to be exceeded throws
// an error message. The object will still be created, but calls to set(level) or set(degrees) are ignored.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <Arduino.h>
#include <driver/ledc.h>
/////////////////////////////////////
class LedPin {
boolean enabled=false;
ledc_channel_config_t ledChannel;
public:
LedPin(uint8_t pin, uint8_t level=0); // assigns pin to be output of one of 16 PWM channels within initial level
void set(uint8_t level); // sets the PWM duty to level (0-100)
int getPin(){return ledChannel.gpio_num;} // returns the pin number
static uint8_t numChannels;
static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B
};
/////////////////////////////////////
class ServoPin {
boolean enabled=false;
uint16_t minMicros;
uint16_t maxMicros;
double minDegrees;
double microsPerDegree;
ledc_channel_config_t servoChannel;
static const double micros2duty;
public:
ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees);
ServoPin(uint8_t pin, double initDegrees=0) : ServoPin(pin,initDegrees,1000,2000,-90,90) {};
void set(double degrees); // sets the Servo to degrees, where degrees is bounded by [minDegrees,maxDegrees]
int getPin(){return servoChannel.gpio_num;} // returns the pin number
static uint8_t numChannels;
};
//*******************************************************
// DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY ONLY
//*******************************************************
class PwmPin {
uint8_t channel;
uint8_t pin;
@ -18,48 +71,8 @@ class PwmPin {
public:
PwmPin(uint8_t channel, uint8_t pin); // assigns pin to be output of one of 16 PWM channels (0-15)
void set(uint8_t level); // sets the PWM duty to level (0-100)
void set(uint8_t channel, uint8_t level){set(level);} // sets the PWM duty to level (0-100) - deprecated, but defined for backwards compatibility
void set(uint8_t channel, uint8_t level); // sets the PWM duty to level (0-100)
int getPin(){return pin;} // returns the pin number
static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B
};
/////////////////////////////////////
class LedPin {
boolean enabled=false;
ledc_channel_config_t ledChannel;
static uint8_t numChannels;
public:
LedPin(uint8_t pin, uint8_t level=0); // assigns pin to be output of one of 16 PWM channels within initial level
void set(uint8_t level); // sets the PWM duty to level (0-100)
int getPin(){return ledChannel.gpio_num;} // returns the pin number
static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B
};
/////////////////////////////////////
class ServoPin {
uint8_t channel; // channel must be in range [0,7] (only HighSpeed Channels will be used)
uint8_t pin;
uint16_t minMicros;
uint16_t maxMicros;
double minDegrees;
double microsPerDegree;
ledc_channel_config_t ledChannel;
static const double micros2duty;
public:
ServoPin(uint8_t channel, uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees);
ServoPin(uint8_t channel, uint8_t pin, double initDegrees=0) : ServoPin(channel,pin,initDegrees,1000,2000,-90,90) {};
void set(double degrees); // sets the Servo to degrees, where degrees is bounded by [minDegrees,maxDegrees]
int getPin(){return pin;} // returns the pin number
};

View File

@ -5,7 +5,7 @@
#include "PwmPin.h"
//ServoPin servo(3,18,-90);
ServoPin servo(3,18,0,500,2200,-90,90);
//ServoPin servo(18,0,500,2200,-90,90);
void setup(){
@ -17,7 +17,7 @@ void setup(){
Serial.println("Starting...");
LedPin yellow(16);
LedPin yellow(16,10);
LedPin d1(19);
LedPin d2(19);
LedPin d3(19);
@ -30,13 +30,14 @@ void setup(){
LedPin d10(19);
LedPin d11(19);
LedPin d12(19);
LedPin d13(19);
LedPin d14(19);
LedPin d15(19);
LedPin d16(19);
LedPin red(17);
LedPin red(17,100);
while(1){
// ServoPin servo(18,0,500,2200,-90,90);
ServoPin s0(19);
ServoPin servo(18,45);
ServoPin s1(19);
while(0){
for(int i=0;i<100;i++){
yellow.set(i);
delay(10);
@ -48,24 +49,21 @@ void setup(){
}
}
while(1){
double STEP=1;
for(int i=-100*STEP;i<=100*STEP;i++){
servo.set((double)i/STEP);
delay(10);
}
for(int i=100*STEP;i>=-100*STEP;i--){
servo.set((double)i/STEP);
delay(10);
}
}
}
void loop(){
// double STEP=1;
//
// for(int i=-100*STEP;i<=100*STEP;i++){
// servo.set((double)i/STEP);
// delay(10);
// }
//
// for(int i=100*STEP;i>=-100*STEP;i--){
// servo.set((double)i/STEP);
// delay(10);
// }
// return;
}