Skip to content

Commit e87ddb4

Browse files
committed
Version 2.2.2
- Added compatibility with the ESP32 Arduino framework - Added full featured AnalogWrite methods for ESP32 to control up to 9 PWM and 2 DAC signals.
1 parent fbef1f1 commit e87ddb4

File tree

6 files changed

+169
-34
lines changed

6 files changed

+169
-34
lines changed

QuickPID.cpp

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
The parameters specified here are those for for which we can't set up
1919
reliable defaults, so we need to have the user set them.
2020
**********************************************************************************/
21-
QuickPID::QuickPID(int16_t* Input, int16_t* Output, int16_t* Setpoint,
21+
QuickPID::QuickPID(int* Input, int* Output, int* Setpoint,
2222
float Kp, float Ki, float Kd, float POn = 1, uint8_t ControllerDirection = 0)
2323
{
2424
myOutput = Output;
@@ -40,7 +40,7 @@ QuickPID::QuickPID(int16_t* Input, int16_t* Output, int16_t* Setpoint,
4040
to use Proportional on Error without explicitly saying so.
4141
**********************************************************************************/
4242

43-
QuickPID::QuickPID(int16_t* Input, int16_t* Output, int16_t* Setpoint,
43+
QuickPID::QuickPID(int* Input, int* Output, int* Setpoint,
4444
float Kp, float Ki, float Kd, uint8_t ControllerDirection)
4545
: QuickPID::QuickPID(Input, Output, Setpoint, Kp, Ki, Kd, pOn = 1, ControllerDirection = 0)
4646
{
@@ -60,8 +60,8 @@ bool QuickPID::Compute()
6060
uint32_t timeChange = (now - lastTime);
6161

6262
if (timeChange >= sampleTimeUs) { // Compute the working error variables
63-
int16_t input = *myInput;
64-
int16_t dInput = input - lastInput;
63+
int input = *myInput;
64+
int dInput = input - lastInput;
6565
error = *mySetpoint - input;
6666

6767
if (kpi < 31 && kpd < 31) outputSum += FX_MUL(FL_FX(kpi) , error) - FX_MUL(FL_FX(kpd), dInput); // fixed-point
@@ -204,7 +204,7 @@ void QuickPID::SetSampleTimeUs(uint32_t NewSampleTimeUs)
204204
The PID controller is designed to vary its output within a given range.
205205
By default this range is 0-255, the Arduino PWM range.
206206
******************************************************************************/
207-
void QuickPID::SetOutputLimits(int16_t Min, int16_t Max)
207+
void QuickPID::SetOutputLimits(int Min, int Max)
208208
{
209209
if (Min >= Max) return;
210210
outMin = Min;
@@ -329,7 +329,7 @@ float QuickPID::analogReadAvg(int ADCpin) {
329329
return (float)sum / 16.0;
330330
}
331331

332-
int16_t QuickPID::Saturate(int16_t Out) {
332+
int QuickPID::Saturate(int Out) {
333333
if (Out > outMax) Out = outMax;
334334
else if (Out < outMin) Out = outMin;
335335
return Out;
@@ -360,3 +360,63 @@ void QuickPID::Stabilize(int inputPin, int outputPin, uint32_t timeout) {
360360
while ((analogReadAvg(inputPin) < atSetpoint) && (millis() <= timeout));
361361
analogWrite(outputPin, atOutput);
362362
}
363+
364+
#if defined(ESP32)
365+
366+
// Adds support for analogWrite() for up to 9 PWM pins plus pins DAC1 and DAC2 which are 8-bit true analog outputs.
367+
// Also adds support for changing the PWM frequency (5000 Hz default) and timer resolution (13-bit default).
368+
369+
analog_write_channel_t _analog_write_channels[9] = { { 2, 5000, 13}, //LED_BUILTIN
370+
{ 4, 5000, 13}, { 13, 5000, 13}, { 14, 5000, 13}, { 16, 5000, 13}, { 17, 5000, 13}, { 27, 5000, 13}, { 32, 5000, 13}, { 33, 5000, 13}
371+
};
372+
373+
void analogWriteFrequency(float frequency) {
374+
for (uint8_t i = 0; i < 9; i++) {
375+
_analog_write_channels[i].frequency = frequency;
376+
if (frequency < 0.0001) {
377+
ledcDetachPin(_analog_write_channels[i].pin);
378+
pinMode(_analog_write_channels[i].pin, INPUT);
379+
}
380+
}
381+
}
382+
383+
void analogWriteFrequency(uint8_t pin, float frequency) {
384+
for (uint8_t i = 0; i < 9; i++) {
385+
if (_analog_write_channels[i].pin == pin) {
386+
_analog_write_channels[i].frequency = frequency;
387+
if (frequency < 0.0001) {
388+
ledcDetachPin(_analog_write_channels[i].pin);
389+
pinMode(_analog_write_channels[i].pin, INPUT);
390+
}
391+
}
392+
}
393+
}
394+
395+
void analogWriteResolution(uint8_t resolution) {
396+
for (uint8_t i = 0; i < 9; i++) {
397+
_analog_write_channels[i].resolution = resolution;
398+
}
399+
}
400+
401+
void analogWriteResolution(uint8_t pin, uint8_t resolution) {
402+
for (uint8_t i = 0; i < 9; i++) {
403+
if (_analog_write_channels[i].pin == pin) {
404+
_analog_write_channels[i].resolution = resolution;
405+
ledcSetup(i, _analog_write_channels[i].frequency, resolution);
406+
ledcAttachPin(_analog_write_channels[i].pin, i);
407+
}
408+
}
409+
}
410+
411+
void analogWrite(uint8_t pin, uint32_t value) {
412+
for (uint8_t i = 0; i < 9; i++) {
413+
if (_analog_write_channels[i].pin == pin) {
414+
uint8_t resolution = _analog_write_channels[i].resolution;
415+
uint32_t valueMax = (pow(2, resolution)) - 1;
416+
if (value > valueMax) value = valueMax;
417+
ledcWrite(i, value);
418+
}
419+
if (pin == DAC1 || pin == DAC2) dacWrite(pin, value & 255);
420+
}
421+
}
422+
#endif

QuickPID.h

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ class QuickPID
1818
// commonly used functions ************************************************************************************
1919

2020
// Constructor. Links the PID to Input, Output, Setpoint and initial Tuning Parameters.
21-
QuickPID(int16_t*, int16_t*, int16_t*, float, float, float, float, uint8_t);
21+
QuickPID(int*, int*, int*, float, float, float, float, uint8_t);
2222

2323
// Overload constructor with proportional mode. Links the PID to Input, Output, Setpoint and Tuning Parameters.
24-
QuickPID(int16_t*, int16_t*, int16_t*, float, float, float, uint8_t);
24+
QuickPID(int*, int*, int*, float, float, float, uint8_t);
2525

2626
// Sets PID to either Manual (0) or Auto (non-0).
2727
void SetMode(uint8_t Mode);
@@ -34,7 +34,7 @@ class QuickPID
3434
void AutoTune(int, int, int, int, uint32_t);
3535

3636
// Sets and clamps the output to a specific range (0-255 by default).
37-
void SetOutputLimits(int16_t, int16_t);
37+
void SetOutputLimits(int, int);
3838

3939
// available but not commonly used functions ******************************************************************
4040

@@ -68,35 +68,35 @@ class QuickPID
6868

6969
private:
7070
void Initialize();
71-
int16_t Saturate(int16_t);
71+
int Saturate(int);
7272
void CheckPeak(int);
7373
void StepUp(int, int, uint32_t);
7474
void StepDown(int, int, uint32_t);
7575
void Stabilize(int, int, uint32_t);
7676

77-
float dispKp; // We'll hold on to the tuning parameters for display purposes.
77+
float dispKp; // We'll hold on to the tuning parameters for display purposes.
7878
float dispKi;
7979
float dispKd;
8080
float dispKu;
8181
float dispTu;
8282
float dispTd;
8383

84-
float pOn; // proportional mode (0-1) default = 1, 100% Proportional on Error
85-
float kp; // (P)roportional Tuning Parameter
86-
float ki; // (I)ntegral Tuning Parameter
87-
float kd; // (D)erivative Tuning Parameter
88-
float kpi; // proportional on error amount
89-
float kpd; // proportional on measurement amount
84+
float pOn; // proportional mode (0-1) default = 1, 100% Proportional on Error
85+
float kp; // (P)roportional Tuning Parameter
86+
float ki; // (I)ntegral Tuning Parameter
87+
float kd; // (D)erivative Tuning Parameter
88+
float kpi; // proportional on error amount
89+
float kpd; // proportional on measurement amount
9090

9191
uint8_t controllerDirection;
9292

93-
int16_t *myInput; // Pointers to the Input, Output, and Setpoint variables. This creates a
94-
int16_t *myOutput; // hard link between the variables and the PID, freeing the user from having
95-
int16_t *mySetpoint; // to constantly tell us what these values are. With pointers we'll just know.
93+
int *myInput; // Pointers to the Input, Output, and Setpoint variables. This creates a
94+
int *myOutput; // hard link between the variables and the PID, freeing the user from having
95+
int *mySetpoint; // to constantly tell us what these values are. With pointers we'll just know.
9696

9797
uint32_t sampleTimeUs, lastTime;
98-
int16_t outMin, outMax, error;
99-
int16_t lastInput, outputSum;
98+
int outMin, outMax, error;
99+
int lastInput, outputSum;
100100
bool inAuto;
101101

102102
// AutoTune
@@ -109,4 +109,21 @@ class QuickPID
109109

110110
};
111111

112+
#if defined(ESP32)
113+
// Adds support for analogWrite() for up to 16 PWM pins plus pins DAC1 and DAC2 which are 8-bit true analog outputs.
114+
// Also adds support for changing the PWM frequency (5000 Hz default) and timer resolution (13-bit default).
115+
116+
typedef struct analog_write_channel {
117+
int8_t pin;
118+
double frequency;
119+
uint8_t resolution;
120+
} analog_write_channel_t;
121+
122+
void analogWriteFrequency(float frequency = 5000);
123+
void analogWriteFrequency(uint8_t pin, float frequency = 5000);
124+
void analogWriteResolution(uint8_t resolution = 13);
125+
void analogWriteResolution(uint8_t pin, uint8_t resolution = 13);
126+
void analogWrite(uint8_t pin, uint32_t value = 0);
127+
#endif
128+
112129
#endif

README.md

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Development began with a fork of the Arduino PID Library. Modifications and new
1616
- `POn` parameter controls the setpoint weighting and mix of Proportional on Error to Proportional on Measurement
1717
- Reorganized and more efficient PID algorithm, faster analog read function, micros() timing resolution
1818
- Runs a complete PID cycle (*read-compute-write*) faster than just an `analogRead()` command in Arduino
19+
- Includes a complete`analogWrite()`function for ESP32 boards. This controls up to 9 independent PWM pins and 2 DAC pins.
1920

2021
### Performance
2122

@@ -51,8 +52,8 @@ The new `kpi` and `kpd` parameters are calculated in the `SetTunings()` function
5152
#### QuickPID_Constructor
5253

5354
```c++
54-
QuickPID::QuickPID(int16_t* Input, int16_t* Output, int16_t* Setpoint,
55-
float Kp, float Ki, float Kd, float POn, bool ControllerDirection)
55+
QuickPID::QuickPID(int* Input, int* Output, int* Setpoint,
56+
float Kp, float Ki, float Kd, float POn, uint8_t ControllerDirection)
5657
```
5758
5859
- `Input`, `Output`, and `Setpoint` are pointers to the variables holding these values.
@@ -64,8 +65,8 @@ QuickPID::QuickPID(int16_t* Input, int16_t* Output, int16_t* Setpoint,
6465
- `ControllerDirection` Either DIRECT or REVERSE determines which direction the output will move for a given error. DIRECT is most common.
6566
6667
```c++
67-
QuickPID::QuickPID(int16_t* Input, int16_t* Output, int16_t* Setpoint,
68-
float Kp, float Ki, float Kd, bool ControllerDirection)
68+
QuickPID::QuickPID(int* Input, int* Output, int* Setpoint,
69+
float Kp, float Ki, float Kd, uint8_t ControllerDirection)
6970
```
7071

7172
This allows you to use Proportional on Error without explicitly saying so.
@@ -119,15 +120,15 @@ Sets the period, in microseconds, at which the calculation is performed. The def
119120
#### SetOutputLimits
120121

121122
```c++
122-
void QuickPID::SetOutputLimits(int16_t Min, int16_t Max)
123+
void QuickPID::SetOutputLimits(int Min, int Max)
123124
```
124125
125126
The PID controller is designed to vary its output within a given range. By default this range is 0-255, the Arduino PWM range.
126127
127128
#### SetMode
128129
129130
```c++
130-
void QuickPID::SetMode(bool Mode)
131+
void QuickPID::SetMode(uint8_t Mode)
131132
```
132133

133134
Allows the controller Mode to be set to `MANUAL` (0) or `AUTOMATIC` (non-zero). when the transition from manual to automatic occurs, the controller is automatically initialized.
@@ -143,7 +144,7 @@ Does all the things that need to happen to ensure a bump-less transfer from manu
143144
#### SetControllerDirection
144145

145146
```c++
146-
void QuickPID::SetControllerDirection(bool Direction)
147+
void QuickPID::SetControllerDirection(uint8_t Direction)
147148
```
148149
149150
The PID will either be connected to a DIRECT acting process (+Output leads to +Input) or a REVERSE acting process (+Output leads to -Input.) We need to know which one, because otherwise we may increase the output when we should be decreasing. This is called from the constructor.
@@ -157,8 +158,8 @@ float QuickPID::GetKd()
157158
float QuickPID::GetKu()
158159
float QuickPID::GetTu()
159160
float QuickPID::GetTd()
160-
bool QuickPID::GetMode()
161-
bool QuickPID::GetDirection()
161+
uint8_t QuickPID::GetMode()
162+
uint8_t QuickPID::GetDirection()
162163
```
163164

164165
These functions query the internal state of the PID. They're here for display purposes.
@@ -171,10 +172,63 @@ int QuickPID::analogReadFast(int ADCpin)
171172
172173
A faster configuration of `analogRead()`where a preset of 32 is used. If the architecture definition isn't found, normal `analogRead()`is used to return a value.
173174
175+
#### AnalogWrite (PWM and DAC) for ESP32
176+
177+
```c++
178+
void analogWrite(uint8_t pin, uint32_t value)
179+
```
180+
181+
Call this function just like in the standard Arduino framework. It controls up to 9 independent PWM outputs and 2 DAC outputs. The controllable GPIO pins are 2, 4, 13, 14, 16, 17, 27, 32 and 33 for PWM and DAC0 (GPIO25) and DAC1 (GPIO26) for true analog outputs. The default PWM frequency is 5000 Hz and the default resolution is 13-bit (0-8191).
182+
183+
#### AnalogWrite Configuration Functions for ESP32
184+
185+
```c++
186+
void analogWriteFrequency(float frequency = 5000);
187+
void analogWriteFrequency(uint8_t pin, float frequency = 5000);
188+
void analogWriteResolution(uint8_t resolution = 13);
189+
void analogWriteResolution(uint8_t pin, uint8_t resolution = 13);
190+
```
191+
192+
Calling `analogWriteFrequency(frequency)`will set the PWM frequency for all 8 assigned pins. Using `analogWriteFrequency(0)`will detach the 9 assigned pins and set them as input.
193+
194+
To independently assign a unique frequency to each PWM pin, use the `analogWriteFrequency(pin, frequency)` function. If the frequency is set to 0, this function will detach the referenced pin and configure it as an input.
195+
196+
Calling `analogWriteResolution(resolution)` will set the resolution for all 9 assigned pins. Read more about the [Supported Range of Frequency and Duty Resolution](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html#ledc-api-supported-range-frequency-duty-resolution) here.
197+
198+
To independently assign a unique frequency to each PWM pin, use the `analogWriteResolution(pin, resolution)` function. Note that it is required to call this function once prior to using AnalogWrite as this will automatically setup and attach (initialize) the pin.
199+
200+
#### Fade Example for ESP32
201+
202+
```c++
203+
#include "QuickPID.h"
204+
205+
#define LED_BUILTIN 2
206+
int brightness = 0;
207+
int step = 1;
208+
209+
void setup() {
210+
analogWriteResolution(LED_BUILTIN, 10);
211+
}
212+
213+
void loop() {
214+
analogWrite(LED_BUILTIN, brightness);
215+
216+
brightness += step;
217+
if ( brightness >= 1023) step = -1;
218+
if ( brightness <= 0) step = 1;
219+
delay(1);
220+
}
221+
```
222+
174223
### Change Log
175224

176225
#### [![arduino-library-badge](https://www.ardu-badge.com/badge/QuickPID.svg?)](https://www.ardu-badge.com/QuickPID)
177226

227+
- Added compatibility with the ESP32 Arduino framework
228+
- Added full featured AnalogWrite methods for ESP32 to control up to 9 PWM and 2 DAC signals
229+
230+
#### Version 2.2.1
231+
178232
- Even faster AutoTune function
179233
- AutoTune now determines the controllability of the process
180234
- Added AMIGO_PID tuning rule

keywords.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
##########################################
88

99
QuickPID KEYWORD1
10+
analog_write_channel_t KEYWORD1
1011

1112
##########################################
1213
# Methods and Functions (KEYWORD2)
@@ -29,6 +30,9 @@ GetMode KEYWORD2
2930
GetDirection KEYWORD2
3031
analogReadFast KEYWORD2
3132
analogReadAvg KEYWORD2
33+
analogWrite KEYWORD2
34+
analogWriteFrequency KEYWORD2
35+
analogWriteResolution KEYWORD2
3236

3337
##########################################
3438
# Constants (LITERAL1)

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "QuickPID",
33
"keywords": "PID, controller, signal",
4-
"description": "A fast fixed/floating point PID controller with AutoTune and 9 tuning rules to choose from. This controller can automatically determine and set tuning parameters. An added feature is contolling the mix of Proportional on Error to Proportional on Measurement.",
4+
"description": "A fast fixed/floating point PID controller with AutoTune and 9 tuning rules to choose from. This controller can automatically determine and set tuning parameters. Compatible with most Arduino and ESP32 boards.",
55
"url": "https://github.com/Dlloydev/QuickPID",
66
"include": "QuickPID",
77
"authors":

library.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
name=QuickPID
2-
version=2.2.1
2+
version=2.2.2
33
author=David Lloyd
44
maintainer=David Lloyd <[email protected]>
55
sentence=A fast fixed/floating point PID controller with AutoTune and 9 tuning rules to choose from.
6-
paragraph=This controller can automatically determine and set tuning parameters. An added feature is contolling the mix of Proportional on Error to Proportional on Measurement.
6+
paragraph=This controller can automatically determine and set tuning parameters. Compatible with most Arduino and ESP32 boards.
77
category=Signal Input/Output
88
url=https://github.com/Dlloydev/QuickPID
99
architectures=*

0 commit comments

Comments
 (0)