Code for 'Smart Regulator' featured in 'Model Engineer', November 2020 on. Contains all work to August 2020 including all code described. Top level algorithm development is quite spares, leaving some work for you! Any questions - jon@jons-workshop.com
Dependencies: mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM
Diff: field.cpp
- Revision:
- 3:43cb067ecd00
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/field.cpp Mon Jul 27 08:44:59 2020 +0000 @@ -0,0 +1,105 @@ +#include "mbed.h" +#include "rpm.h" +#include "field.h" +#include "Alternator.h" +#include "BufferedSerial.h" +extern BufferedSerial pc; + +extern ee_settings_2020 user_settings; +extern Timer microsecs; // 64 bit counter, rolls over in half million years + +FieldControl::FieldControl (PinName pwmoscin, PinName vext) : pwm_osc_in (pwmoscin), V_ext (vext) { + pwm_osc_in.period_us (PWM_PERIOD_US); // about 313Hz * 2 + pwm_osc_in.pulsewidth_us (PWM_PERIOD_US - 2); + V_ext.rise (callback(this, &FieldControl::VextRise)); // Attach handler to the rising interruptIn edge + V_ext.fall (callback(this, &FieldControl::VextFall)); // Attach handler to the falling interruptIn edge + t_on = t_off = measured_pw_us = measured_period = rise_count = fall_count = 0L; +// maketable () ; + set_for_speed (0); + old_percent = 1000; // i.e. out of percentage range to force exec on first pass +} + +void FieldControl::VextRise () // InterruptIn interrupt service +{ // Here is possible to read back how regulator has controlled pwm - may or may not be useful + uint64_t tmp = microsecs.read_high_resolution_us(); + measured_period = tmp - t_on; + t_on = tmp; + rise_count++; +} + +void FieldControl::VextFall () // InterruptIn interrupt service +{ + fall_count++; + t_off = microsecs.read_high_resolution_us(); + measured_pw_us = t_off - t_on; +} + +double FieldControl::get_duty_ratio () { + if (measured_period == 0) { + if (V_ext == 1) + return 2.0; // Impossible value indicates error + return -1.0; // Impossible value indicates error + } + return (double) measured_pw_us / (double) measured_period; +} ; + + +void FieldControl::maketable () { // Uses first 17 nums of user_settings relating to lim to be applied at 0, 500, 1000 --- 8000 RPM +// Makes table of 400 entries to 8000 RPM regardless of engine type data. 20 RPM per fine step +// 21 User input table entries 200 RPM apart for MAX_RPM_LIMIT up to 4000, 400 RPM for up to 8000 + double tabvals[28]; + double diff, val = 0.0; + uint32_t tabptr = 0, user_entry_rpm_step, divor; + user_entry_rpm_step = MAX_RPM_LIMIT > 4000 ? 400 : 200; + divor = MAX_RPM_LIMIT > 4000 ? 20 : 20; + for (int i = 0; i < 21; i++) { + tabvals[i] = (double)user_settings.rd (i); + pc.printf ("%d\t%.0f\r\n", i * user_entry_rpm_step, tabvals[i]); + } + for (int i = 1; i < 21; i++) { + diff = tabvals[i] - tabvals[i - 1]; // Either 200 or 400 RPM apart, either 10 or 20 small steps to fill + diff /= divor; // 50 entries 20RPM apart per kRPM + for (int j = 0; j < divor; j++) { + privatemadetab[tabptr++] = (uint8_t) val; + val += diff; + } + } + pc.printf ("Final tab entry posn %d, calculated = %d percent, divor = %d\r\n", tabptr, (uint8_t) val, divor); + while (tabptr < sizeof(privatemadetab)) + privatemadetab[tabptr++] = (uint8_t) val; +} + +uint32_t FieldControl::set_for_speed (uint32_t rpm) { // May 2020 + uint32_t index, pcent; + double pwm = 0.0; + if (rpm > MAX_RPM_LIMIT) + rpm = MAX_RPM_LIMIT; +// index = rpm / 25; // to fit lut spacing of 25rpm intervals, turns rpm into index + index = rpm / 10; // to fit lut spacing of 10rpm intervals, turns rpm into index + pcent = privatemadetab[index]; + if (pcent != old_percent) { + old_percent = pcent; + pwm = (double)pcent; + pwm /= 100.0; + set_pwm (pwm); + } + return old_percent; +} + +extern double Read_Field_Volts () ; + +void FieldControl::set_pwm (double d) { + double t = Read_Field_Volts () ; + if (t > ALTERNATOR_DESIGN_VOLTAGE) + t = ALTERNATOR_DESIGN_VOLTAGE / t; + else + t = 1.0; + uint32_t i; + if (d < 0.0) + d = 0.0; + if (d > 1.0) + d = 1.0; + i = (uint32_t)(d * t * (double)PWM_PERIOD_US); // pwm_factor 0.5 when using 12v alternator in 24v system + pwm_osc_in.pulsewidth_us (PWM_PERIOD_US - i); // Note PWM is inverted as MCP1630 uses inverted OSC_IN signal +} +