11/*
2- ESP32 PWM, SERVO and TONE Library, Version 5.0.1
2+ ESP32 PWM, SERVO and TONE Library, Version 5.0.2
33 by dlloydev https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite
44 License: MIT
55*/
@@ -45,90 +45,20 @@ float Pwm::write(int pin, uint32_t duty, uint32_t frequency, uint8_t resolution,
4545 return mem[ch].frequency ;
4646}
4747
48- float Pwm::writeServo (int pin, float value, double speed, double ke) {
49- uint8_t ch = attached (pin);
50- wr_servo (pin, value, speed, ke);
51- return mem[ch].ye ; // normalized easing position (0.0 - 1.0)
52- }
53-
54- float Pwm::writeServo (int pin, float value) {
48+ uint8_t Pwm::attach (int pin) {
5549 uint8_t ch = attached (pin);
5650 if (ch == 253 ) { // free channels exist
5751 for (uint8_t c = 0 ; c < chMax; c++) {
5852 if (mem[c].pin == 255 && ch == 253 ) { // first free ch
5953 mem[c].pin = pin;
6054 ch = c;
61- if (mem[ch].frequency < 40 || mem[ch].frequency > 900 ) mem[ch].frequency = 50 ;
62- if (mem[ch].resolution > widthMax) mem[ch].resolution = widthMax;
63- else if (mem[ch].resolution < 14 && widthMax == 20 ) mem[ch].resolution = 16 ;
64- else if (mem[ch].resolution < 14 ) mem[ch].resolution = 14 ;
6555 ledcSetup (ch, mem[ch].frequency , mem[ch].resolution );
6656 if (sync) pause (ch);
6757 ledcAttachPin (pin, ch);
58+ return ch;
6859 }
6960 }
7061 }
71- wr_servo (pin, value, mem[ch].speed , mem[ch].ke );
72- return mem[ch].ye ; // normalized easing position (0.0 - 1.0)
73- }
74-
75- void Pwm::tone (int pin, uint32_t frequency, uint16_t duration, uint16_t interval) {
76- uint8_t ch = attach (pin);
77- if (ch < chMax) {
78- uint32_t ms = millis ();
79- static bool durDone = false ;
80- #if defined(CONFIG_IDF_TARGET_ESP32C3)
81- if (frequency < 153 ) frequency = 153 ;
82- #else
83- if (frequency < 4 ) frequency = 4 ;
84- #endif
85- if (!durDone) {
86- if (frequency != mem[ch].frequency && (ms - mem[ch].startMs > interval)) {
87- mem[ch].startMs = ms;
88- mem[ch].frequency = frequency;
89- ledcChangeFrequency (ch, frequency, mem[ch].resolution );
90- write (pin, 127 , frequency, 8 );
91- resume (ch);
92- }
93- if ((duration && ((ms - mem[ch].startMs ) > duration)) || (duration == 0 )) {
94- mem[ch].startMs = ms;
95- durDone = true ;
96- if (duration < 0xffff ) pause (ch);
97- }
98- } else if (ms - mem[ch].startMs > interval) durDone = false ;
99- }
100- }
101-
102- void Pwm::note (int pin, note_t note, uint8_t octave, uint16_t duration, uint16_t interval) {
103- const uint16_t noteFrequencyBase[12 ] = {
104- // C C# D Eb E F F# G G# A Bb B
105- 4186 , 4435 , 4699 , 4978 , 5274 , 5588 , 5920 , 6272 , 6645 , 7040 , 7459 , 7902
106- };
107- uint32_t noteFreq = (uint32_t )noteFrequencyBase[note] / (uint32_t )(1 << (8 - octave));
108- if (octave <= 8 || note <= NOTE_MAX) tone (pin, noteFreq, duration, interval);
109- }
110-
111- float Pwm::read (int pin) {
112- uint8_t ch = attached (pin);
113- if (ch < chMax) {
114- float deg = (readMicroseconds (pin) - mem[ch].servoMinUs ) / (mem[ch].servoMaxUs - mem[ch].servoMinUs ) * 180.0 ;
115- return deg < 0 ? 0 : deg;
116- }
117- else return 0 ;
118- }
119-
120- float Pwm::readMicroseconds (int pin) {
121- uint8_t ch = attached (pin);
122- if (ch < chMax) return mem[ch].duty * ((1000000.0 / mem[ch].frequency ) / ((1 << mem[ch].resolution ) - 1.0 )); // μs
123- else return 0 ;
124- }
125-
126- uint8_t Pwm::attach (int pin) {
127- uint8_t ch = firstFreeCh ();
128- if (ch < chMax) mem[ch].pin = pin;
129- ledcSetup (ch, mem[ch].frequency , mem[ch].resolution );
130- if (sync) pause (ch);
131- ledcAttachPin (pin, ch);
13262 return ch;
13363}
13464
@@ -180,8 +110,7 @@ uint8_t Pwm::attachServo(int pin, int ch) {
180110
181111uint8_t Pwm::attachServo (int pin, int ch, bool invert) {
182112 if (ch < chMax) config_servo (ch, mem[ch].servoMinUs , mem[ch].servoMaxUs );
183- uint8_t chan = (invert) ? attachInvert (pin, ch) : attach (pin, ch);
184- return chan;
113+ return (invert) ? attachInvert (pin, ch) : attach (pin, ch);
185114}
186115
187116uint8_t Pwm::attachServo (int pin, int minUs, int maxUs) {
@@ -197,8 +126,7 @@ uint8_t Pwm::attachServo(int pin, int ch, int minUs, int maxUs) {
197126
198127uint8_t Pwm::attachServo (int pin, int ch, int minUs, int maxUs, bool invert) {
199128 config_servo (ch, minUs, maxUs);
200- uint8_t chan = (invert) ? attachInvert (pin, ch) : attach (pin, ch);
201- return chan;
129+ return (invert) ? attachInvert (pin, ch) : attach (pin, ch);
202130}
203131
204132uint8_t Pwm::attachServo (int pin, int minUs, int maxUs, double speed, double ke) {
@@ -214,8 +142,85 @@ uint8_t Pwm::attachServo(int pin, int ch, int minUs, int maxUs, double speed, do
214142
215143uint8_t Pwm::attachServo (int pin, int ch, int minUs, int maxUs, double speed, double ke, bool invert) {
216144 config_servo (ch, minUs, maxUs, speed, ke);
217- uint8_t chan = (invert) ? attachInvert (pin, ch) : attach (pin, ch);
218- return chan;
145+ return (invert) ? attachInvert (pin, ch) : attach (pin, ch);
146+ }
147+
148+ float Pwm::read (int pin) {
149+ uint8_t ch = attached (pin);
150+ if (ch < chMax) {
151+ float deg = (readMicroseconds (pin) - mem[ch].servoMinUs ) / (mem[ch].servoMaxUs - mem[ch].servoMinUs ) * 180.0 ;
152+ return deg < 0 ? 0 : deg;
153+ }
154+ else return 0 ;
155+ }
156+
157+ float Pwm::readMicroseconds (int pin) {
158+ uint8_t ch = attached (pin);
159+ if (ch < chMax) return mem[ch].duty * ((1000000.0 / mem[ch].frequency ) / ((1 << mem[ch].resolution ) - 1.0 )); // μs
160+ else return 0 ;
161+ }
162+
163+ float Pwm::writeServo (int pin, float value, double speed, double ke) {
164+ uint8_t ch = attached (pin);
165+ wr_servo (pin, value, speed, ke);
166+ return mem[ch].ye ; // normalized easing position (0.0 - 1.0)
167+ }
168+
169+ float Pwm::writeServo (int pin, float value) {
170+ uint8_t ch = attached (pin);
171+ if (ch == 253 ) { // free channels exist
172+ for (uint8_t c = 0 ; c < chMax; c++) {
173+ if (mem[c].pin == 255 && ch == 253 ) { // first free ch
174+ mem[c].pin = pin;
175+ ch = c;
176+ if (mem[ch].frequency < 40 || mem[ch].frequency > 900 ) mem[ch].frequency = 50 ;
177+ if (mem[ch].resolution > widthMax) mem[ch].resolution = widthMax;
178+ else if (mem[ch].resolution < 14 && widthMax == 20 ) mem[ch].resolution = 16 ;
179+ else if (mem[ch].resolution < 14 ) mem[ch].resolution = 14 ;
180+ ledcSetup (ch, mem[ch].frequency , mem[ch].resolution );
181+ if (sync) pause (ch);
182+ ledcAttachPin (pin, ch);
183+ }
184+ }
185+ }
186+ wr_servo (pin, value, mem[ch].speed , mem[ch].ke );
187+ return mem[ch].ye ; // normalized easing position (0.0 - 1.0)
188+ }
189+
190+ void Pwm::tone (int pin, uint32_t frequency, uint16_t duration, uint16_t interval) {
191+ uint8_t ch = attach (pin);
192+ if (ch < chMax) {
193+ uint32_t ms = millis ();
194+ static bool durDone = false ;
195+ #if defined(CONFIG_IDF_TARGET_ESP32C3)
196+ if (frequency < 153 ) frequency = 153 ;
197+ #else
198+ if (frequency < 4 ) frequency = 4 ;
199+ #endif
200+ if (!durDone) {
201+ if (frequency != mem[ch].frequency && (ms - mem[ch].startMs > interval)) {
202+ mem[ch].startMs = ms;
203+ mem[ch].frequency = frequency;
204+ ledcChangeFrequency (ch, frequency, mem[ch].resolution );
205+ write (pin, 127 , frequency, 8 );
206+ resume (ch);
207+ }
208+ if ((duration && ((ms - mem[ch].startMs ) > duration)) || (duration == 0 )) {
209+ mem[ch].startMs = ms;
210+ durDone = true ;
211+ if (duration < 0xffff ) pause (ch);
212+ }
213+ } else if (ms - mem[ch].startMs > interval) durDone = false ;
214+ }
215+ }
216+
217+ void Pwm::note (int pin, note_t note, uint8_t octave, uint16_t duration, uint16_t interval) {
218+ const uint16_t noteFrequencyBase[12 ] = {
219+ // C C# D Eb E F F# G G# A Bb B
220+ 4186 , 4435 , 4699 , 4978 , 5274 , 5588 , 5920 , 6272 , 6645 , 7040 , 7459 , 7902
221+ };
222+ uint32_t noteFreq = (uint32_t )noteFrequencyBase[note] / (uint32_t )(1 << (8 - octave));
223+ if (octave <= 8 || note <= NOTE_MAX) tone (pin, noteFreq, duration, interval);
219224}
220225
221226uint8_t Pwm::attached (int pin) {
@@ -243,9 +248,9 @@ void Pwm::detach(int pin) {
243248 uint8_t ch = attached (pin);
244249 if (ch < chMax) {
245250 reset_fields (ch);
246- if (digitalRead (pin) == HIGH) delay ( 3 ); // wait until low
247- ledcWrite (ch, 4 ); // minimal duty for jitterless detach
248- ledcDetachPin (mem[ch].pin );
251+ if (digitalRead (pin) == HIGH) delayMicroseconds (mem[ch]. servoMaxUs ); // wait until LOW
252+ ledcWrite (ch, 4 ); // set minimal duty
253+ ledcDetachPin (mem[ch].pin ); // jitterless
249254 REG_SET_FIELD (GPIO_PIN_MUX_REG[pin], MCU_SEL, GPIO_MODE_DEF_DISABLE);
250255 }
251256}
0 commit comments