3 #include "nuts_bolts.h"
5 #define PID_PWM_MAX 256
11 _max
= PID_PWM_MAX
- 1;
17 void Pwm::pwm(int new_pwm
)
19 _pwm
= confine(new_pwm
, 0, _max
);
22 Pwm
* Pwm::max_pwm(int new_max
)
24 _max
= confine(new_max
, 0, PID_PWM_MAX
- 1);
25 _pwm
= confine( _pwm
, 0, _max
);
34 void Pwm::set(bool value
)
40 uint32_t Pwm::on_tick(uint32_t dummy
)
42 if ((_pwm
< 0) || _pwm
>= PID_PWM_MAX
) {
49 else if (_pwm
== PID_PWM_MAX
- 1) {
55 * Sigma-Delta PWM algorithm
57 * This Sigma-Delta implementation works by increasing _sd_accumulator by _pwm until we reach _half_ of max,
58 * then decreasing by (max - target_pwm) until we hit zero
60 * While we're increasing, the output is 0 and while we're decreasing the output is 1
62 * For example, with pwm=128 and a max of 256, we'll see the following pattern:
64 * 0 128 1 // after the add, we hit 256/2 = 128 so we change direction
65 * 128 -128 0 // after the add, we hit 0 so we change direction again
70 * with a pwm value of 192 (75%) we'll see this:
72 * 0 192 0 // after the add, we are beyond max/2 so we change direction
73 * 192 -64 1 // haven't reached 0 yet
74 * 128 -64 1 // haven't reached 0 yet
75 * 64 -64 1 // after this add we reach 0, and change direction
83 * with a pwm value of 75 (about 29%) we'll see this pattern:
106 * etcetera. This pattern has 6 '1's over a total of 21 lines which is on 28.57% of the time. If we let it run longer, it would get closer to the target as time went on
109 // this line should never actually do anything, it's just a sanity check in case our accumulator gets corrupted somehow.
110 // If we didn't check and the accumulator is corrupted, we could leave a heater on for quite a long time
111 // the accumulator is kept within these limits by the normal operation of the Sigma-Delta algorithm
112 _sd_accumulator
= confine(_sd_accumulator
, -PID_PWM_MAX
, PID_PWM_MAX
<< 1);
114 // when _sd_direction == false, our output is 0 and our accumulator is increasing by _pwm
115 if (_sd_direction
== false)
117 // increment accumulator
118 _sd_accumulator
+= _pwm
;
119 // if we've reached half of max, flip our direction
120 if (_sd_accumulator
>= (PID_PWM_MAX
>> 1))
121 _sd_direction
= true;
123 // when _sd_direction == true, our output is 1 and our accumulator is decreasing by (MAX - _pwm)
126 // decrement accumulator
127 _sd_accumulator
-= (PID_PWM_MAX
- _pwm
);
128 // if we've reached 0, flip our direction
129 if (_sd_accumulator
<= 0)
130 _sd_direction
= false;
132 Pin::set(_sd_direction
);