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

Committer:
JonFreeman
Date:
Mon Jul 27 08:44:59 2020 +0000
Revision:
3:43cb067ecd00
End of July after good day out at Ashton Court

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 3:43cb067ecd00 1 #include "mbed.h"
JonFreeman 3:43cb067ecd00 2 #include "rpm.h"
JonFreeman 3:43cb067ecd00 3 #include "field.h"
JonFreeman 3:43cb067ecd00 4 #include "Alternator.h"
JonFreeman 3:43cb067ecd00 5 #include "BufferedSerial.h"
JonFreeman 3:43cb067ecd00 6 extern BufferedSerial pc;
JonFreeman 3:43cb067ecd00 7
JonFreeman 3:43cb067ecd00 8 extern ee_settings_2020 user_settings;
JonFreeman 3:43cb067ecd00 9 extern Timer microsecs; // 64 bit counter, rolls over in half million years
JonFreeman 3:43cb067ecd00 10
JonFreeman 3:43cb067ecd00 11 FieldControl::FieldControl (PinName pwmoscin, PinName vext) : pwm_osc_in (pwmoscin), V_ext (vext) {
JonFreeman 3:43cb067ecd00 12 pwm_osc_in.period_us (PWM_PERIOD_US); // about 313Hz * 2
JonFreeman 3:43cb067ecd00 13 pwm_osc_in.pulsewidth_us (PWM_PERIOD_US - 2);
JonFreeman 3:43cb067ecd00 14 V_ext.rise (callback(this, &FieldControl::VextRise)); // Attach handler to the rising interruptIn edge
JonFreeman 3:43cb067ecd00 15 V_ext.fall (callback(this, &FieldControl::VextFall)); // Attach handler to the falling interruptIn edge
JonFreeman 3:43cb067ecd00 16 t_on = t_off = measured_pw_us = measured_period = rise_count = fall_count = 0L;
JonFreeman 3:43cb067ecd00 17 // maketable () ;
JonFreeman 3:43cb067ecd00 18 set_for_speed (0);
JonFreeman 3:43cb067ecd00 19 old_percent = 1000; // i.e. out of percentage range to force exec on first pass
JonFreeman 3:43cb067ecd00 20 }
JonFreeman 3:43cb067ecd00 21
JonFreeman 3:43cb067ecd00 22 void FieldControl::VextRise () // InterruptIn interrupt service
JonFreeman 3:43cb067ecd00 23 { // Here is possible to read back how regulator has controlled pwm - may or may not be useful
JonFreeman 3:43cb067ecd00 24 uint64_t tmp = microsecs.read_high_resolution_us();
JonFreeman 3:43cb067ecd00 25 measured_period = tmp - t_on;
JonFreeman 3:43cb067ecd00 26 t_on = tmp;
JonFreeman 3:43cb067ecd00 27 rise_count++;
JonFreeman 3:43cb067ecd00 28 }
JonFreeman 3:43cb067ecd00 29
JonFreeman 3:43cb067ecd00 30 void FieldControl::VextFall () // InterruptIn interrupt service
JonFreeman 3:43cb067ecd00 31 {
JonFreeman 3:43cb067ecd00 32 fall_count++;
JonFreeman 3:43cb067ecd00 33 t_off = microsecs.read_high_resolution_us();
JonFreeman 3:43cb067ecd00 34 measured_pw_us = t_off - t_on;
JonFreeman 3:43cb067ecd00 35 }
JonFreeman 3:43cb067ecd00 36
JonFreeman 3:43cb067ecd00 37 double FieldControl::get_duty_ratio () {
JonFreeman 3:43cb067ecd00 38 if (measured_period == 0) {
JonFreeman 3:43cb067ecd00 39 if (V_ext == 1)
JonFreeman 3:43cb067ecd00 40 return 2.0; // Impossible value indicates error
JonFreeman 3:43cb067ecd00 41 return -1.0; // Impossible value indicates error
JonFreeman 3:43cb067ecd00 42 }
JonFreeman 3:43cb067ecd00 43 return (double) measured_pw_us / (double) measured_period;
JonFreeman 3:43cb067ecd00 44 } ;
JonFreeman 3:43cb067ecd00 45
JonFreeman 3:43cb067ecd00 46
JonFreeman 3:43cb067ecd00 47 void FieldControl::maketable () { // Uses first 17 nums of user_settings relating to lim to be applied at 0, 500, 1000 --- 8000 RPM
JonFreeman 3:43cb067ecd00 48 // Makes table of 400 entries to 8000 RPM regardless of engine type data. 20 RPM per fine step
JonFreeman 3:43cb067ecd00 49 // 21 User input table entries 200 RPM apart for MAX_RPM_LIMIT up to 4000, 400 RPM for up to 8000
JonFreeman 3:43cb067ecd00 50 double tabvals[28];
JonFreeman 3:43cb067ecd00 51 double diff, val = 0.0;
JonFreeman 3:43cb067ecd00 52 uint32_t tabptr = 0, user_entry_rpm_step, divor;
JonFreeman 3:43cb067ecd00 53 user_entry_rpm_step = MAX_RPM_LIMIT > 4000 ? 400 : 200;
JonFreeman 3:43cb067ecd00 54 divor = MAX_RPM_LIMIT > 4000 ? 20 : 20;
JonFreeman 3:43cb067ecd00 55 for (int i = 0; i < 21; i++) {
JonFreeman 3:43cb067ecd00 56 tabvals[i] = (double)user_settings.rd (i);
JonFreeman 3:43cb067ecd00 57 pc.printf ("%d\t%.0f\r\n", i * user_entry_rpm_step, tabvals[i]);
JonFreeman 3:43cb067ecd00 58 }
JonFreeman 3:43cb067ecd00 59 for (int i = 1; i < 21; i++) {
JonFreeman 3:43cb067ecd00 60 diff = tabvals[i] - tabvals[i - 1]; // Either 200 or 400 RPM apart, either 10 or 20 small steps to fill
JonFreeman 3:43cb067ecd00 61 diff /= divor; // 50 entries 20RPM apart per kRPM
JonFreeman 3:43cb067ecd00 62 for (int j = 0; j < divor; j++) {
JonFreeman 3:43cb067ecd00 63 privatemadetab[tabptr++] = (uint8_t) val;
JonFreeman 3:43cb067ecd00 64 val += diff;
JonFreeman 3:43cb067ecd00 65 }
JonFreeman 3:43cb067ecd00 66 }
JonFreeman 3:43cb067ecd00 67 pc.printf ("Final tab entry posn %d, calculated = %d percent, divor = %d\r\n", tabptr, (uint8_t) val, divor);
JonFreeman 3:43cb067ecd00 68 while (tabptr < sizeof(privatemadetab))
JonFreeman 3:43cb067ecd00 69 privatemadetab[tabptr++] = (uint8_t) val;
JonFreeman 3:43cb067ecd00 70 }
JonFreeman 3:43cb067ecd00 71
JonFreeman 3:43cb067ecd00 72 uint32_t FieldControl::set_for_speed (uint32_t rpm) { // May 2020
JonFreeman 3:43cb067ecd00 73 uint32_t index, pcent;
JonFreeman 3:43cb067ecd00 74 double pwm = 0.0;
JonFreeman 3:43cb067ecd00 75 if (rpm > MAX_RPM_LIMIT)
JonFreeman 3:43cb067ecd00 76 rpm = MAX_RPM_LIMIT;
JonFreeman 3:43cb067ecd00 77 // index = rpm / 25; // to fit lut spacing of 25rpm intervals, turns rpm into index
JonFreeman 3:43cb067ecd00 78 index = rpm / 10; // to fit lut spacing of 10rpm intervals, turns rpm into index
JonFreeman 3:43cb067ecd00 79 pcent = privatemadetab[index];
JonFreeman 3:43cb067ecd00 80 if (pcent != old_percent) {
JonFreeman 3:43cb067ecd00 81 old_percent = pcent;
JonFreeman 3:43cb067ecd00 82 pwm = (double)pcent;
JonFreeman 3:43cb067ecd00 83 pwm /= 100.0;
JonFreeman 3:43cb067ecd00 84 set_pwm (pwm);
JonFreeman 3:43cb067ecd00 85 }
JonFreeman 3:43cb067ecd00 86 return old_percent;
JonFreeman 3:43cb067ecd00 87 }
JonFreeman 3:43cb067ecd00 88
JonFreeman 3:43cb067ecd00 89 extern double Read_Field_Volts () ;
JonFreeman 3:43cb067ecd00 90
JonFreeman 3:43cb067ecd00 91 void FieldControl::set_pwm (double d) {
JonFreeman 3:43cb067ecd00 92 double t = Read_Field_Volts () ;
JonFreeman 3:43cb067ecd00 93 if (t > ALTERNATOR_DESIGN_VOLTAGE)
JonFreeman 3:43cb067ecd00 94 t = ALTERNATOR_DESIGN_VOLTAGE / t;
JonFreeman 3:43cb067ecd00 95 else
JonFreeman 3:43cb067ecd00 96 t = 1.0;
JonFreeman 3:43cb067ecd00 97 uint32_t i;
JonFreeman 3:43cb067ecd00 98 if (d < 0.0)
JonFreeman 3:43cb067ecd00 99 d = 0.0;
JonFreeman 3:43cb067ecd00 100 if (d > 1.0)
JonFreeman 3:43cb067ecd00 101 d = 1.0;
JonFreeman 3:43cb067ecd00 102 i = (uint32_t)(d * t * (double)PWM_PERIOD_US); // pwm_factor 0.5 when using 12v alternator in 24v system
JonFreeman 3:43cb067ecd00 103 pwm_osc_in.pulsewidth_us (PWM_PERIOD_US - i); // Note PWM is inverted as MCP1630 uses inverted OSC_IN signal
JonFreeman 3:43cb067ecd00 104 }
JonFreeman 3:43cb067ecd00 105