HomeSpan/src/extras/PwmPin.cpp

264 lines
5.9 KiB
C++

#include "PwmPin.h"
///////////////////
LedPin::LedPin(uint8_t pin, uint8_t level){
if(numChannels+ServoPin::numChannels>15){
Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels ***\n\n",pin);
return;
}
enabled=true;
if(numChannels==0){ // first instantiation of an LedPin
ledc_timer_config_t ledTimer;
ledTimer.timer_num=LEDC_TIMER_0;
ledTimer.duty_resolution=LEDC_TIMER_10_BIT;
ledTimer.freq_hz=5000;
ledTimer.speed_mode=LEDC_HIGH_SPEED_MODE; // configure both the HIGH-Speed Timer 0 and Low-Speed Timer 0
ledc_timer_config(&ledTimer);
ledTimer.speed_mode=LEDC_LOW_SPEED_MODE;
ledc_timer_config(&ledTimer);
}
ledChannel.gpio_num=pin;
if(numChannels<8){
ledChannel.speed_mode=LEDC_LOW_SPEED_MODE;
ledChannel.channel=(ledc_channel_t)(7-numChannels);
} else {
ledChannel.speed_mode=LEDC_HIGH_SPEED_MODE;
ledChannel.channel=(ledc_channel_t)(15-numChannels);
}
numChannels++;
ledChannel.intr_type=LEDC_INTR_DISABLE;
ledChannel.timer_sel=LEDC_TIMER_0;
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);
}
///////////////////
void LedPin::set(uint8_t level){
if(!enabled)
return;
ledChannel.duty=level*1023;
ledChannel.duty/=100;
ledChannel.duty&=0x03FF;
ledc_channel_config(&ledChannel);
}
///////////////////
void LedPin::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;
}
}
////////////////////////////
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;
microsPerDegree=(double)(maxMicros-minMicros)/(maxDegrees-minDegrees);
ledc_timer_config_t ledTimer;
ledTimer.timer_num=LEDC_TIMER_1;
ledTimer.speed_mode=LEDC_HIGH_SPEED_MODE;
ledTimer.duty_resolution=LEDC_TIMER_16_BIT;
ledTimer.freq_hz=50;
ledc_timer_config(&ledTimer);
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){
if(!enabled)
return;
servoChannel.duty=(degrees-minDegrees)*microsPerDegree+minMicros;
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;
}
}