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
field.cpp
00001 #include "mbed.h" 00002 #include "rpm.h" 00003 #include "field.h" 00004 #include "Alternator.h" 00005 #include "BufferedSerial.h" 00006 extern BufferedSerial pc; 00007 00008 extern ee_settings_2020 user_settings; 00009 extern Timer microsecs; // 64 bit counter, rolls over in half million years 00010 00011 FieldControl::FieldControl (PinName pwmoscin, PinName vext) : pwm_osc_in (pwmoscin), V_ext (vext) { 00012 pwm_osc_in.period_us (PWM_PERIOD_US); // about 313Hz * 2 00013 pwm_osc_in.pulsewidth_us (PWM_PERIOD_US - 2); 00014 V_ext.rise (callback(this, &FieldControl::VextRise)); // Attach handler to the rising interruptIn edge 00015 V_ext.fall (callback(this, &FieldControl::VextFall)); // Attach handler to the falling interruptIn edge 00016 t_on = t_off = measured_pw_us = measured_period = rise_count = fall_count = 0L; 00017 // maketable () ; 00018 set_for_speed (0); 00019 old_percent = 1000; // i.e. out of percentage range to force exec on first pass 00020 } 00021 00022 void FieldControl::VextRise () // InterruptIn interrupt service 00023 { // Here is possible to read back how regulator has controlled pwm - may or may not be useful 00024 uint64_t tmp = microsecs.read_high_resolution_us(); 00025 measured_period = tmp - t_on; 00026 t_on = tmp; 00027 rise_count++; 00028 } 00029 00030 void FieldControl::VextFall () // InterruptIn interrupt service 00031 { 00032 fall_count++; 00033 t_off = microsecs.read_high_resolution_us(); 00034 measured_pw_us = t_off - t_on; 00035 } 00036 00037 double FieldControl::get_duty_ratio () { 00038 if (measured_period == 0) { 00039 if (V_ext == 1) 00040 return 2.0; // Impossible value indicates error 00041 return -1.0; // Impossible value indicates error 00042 } 00043 return (double) measured_pw_us / (double) measured_period; 00044 } ; 00045 00046 00047 void FieldControl::maketable () { // Uses first 17 nums of user_settings relating to lim to be applied at 0, 500, 1000 --- 8000 RPM 00048 // Makes table of 400 entries to 8000 RPM regardless of engine type data. 20 RPM per fine step 00049 // 21 User input table entries 200 RPM apart for MAX_RPM_LIMIT up to 4000, 400 RPM for up to 8000 00050 double tabvals[28]; 00051 double diff, val = 0.0; 00052 uint32_t tabptr = 0, user_entry_rpm_step, divor; 00053 user_entry_rpm_step = MAX_RPM_LIMIT > 4000 ? 400 : 200; 00054 divor = MAX_RPM_LIMIT > 4000 ? 20 : 20; 00055 for (int i = 0; i < 21; i++) { 00056 tabvals[i] = (double)user_settings.rd (i); 00057 pc.printf ("%d\t%.0f\r\n", i * user_entry_rpm_step, tabvals[i]); 00058 } 00059 for (int i = 1; i < 21; i++) { 00060 diff = tabvals[i] - tabvals[i - 1]; // Either 200 or 400 RPM apart, either 10 or 20 small steps to fill 00061 diff /= divor; // 50 entries 20RPM apart per kRPM 00062 for (int j = 0; j < divor; j++) { 00063 privatemadetab[tabptr++] = (uint8_t) val; 00064 val += diff; 00065 } 00066 } 00067 pc.printf ("Final tab entry posn %d, calculated = %d percent, divor = %d\r\n", tabptr, (uint8_t) val, divor); 00068 while (tabptr < sizeof(privatemadetab)) 00069 privatemadetab[tabptr++] = (uint8_t) val; 00070 } 00071 00072 uint32_t FieldControl::set_for_speed (uint32_t rpm) { // May 2020 00073 uint32_t index, pcent; 00074 double pwm = 0.0; 00075 if (rpm > MAX_RPM_LIMIT) 00076 rpm = MAX_RPM_LIMIT; 00077 // index = rpm / 25; // to fit lut spacing of 25rpm intervals, turns rpm into index 00078 index = rpm / 10; // to fit lut spacing of 10rpm intervals, turns rpm into index 00079 pcent = privatemadetab[index]; 00080 if (pcent != old_percent) { 00081 old_percent = pcent; 00082 pwm = (double)pcent; 00083 pwm /= 100.0; 00084 set_pwm (pwm); 00085 } 00086 return old_percent; 00087 } 00088 00089 extern double Read_Field_Volts () ; 00090 00091 void FieldControl::set_pwm (double d) { 00092 double t = Read_Field_Volts () ; 00093 if (t > ALTERNATOR_DESIGN_VOLTAGE) 00094 t = ALTERNATOR_DESIGN_VOLTAGE / t; 00095 else 00096 t = 1.0; 00097 uint32_t i; 00098 if (d < 0.0) 00099 d = 0.0; 00100 if (d > 1.0) 00101 d = 1.0; 00102 i = (uint32_t)(d * t * (double)PWM_PERIOD_US); // pwm_factor 0.5 when using 12v alternator in 24v system 00103 pwm_osc_in.pulsewidth_us (PWM_PERIOD_US - i); // Note PWM is inverted as MCP1630 uses inverted OSC_IN signal 00104 } 00105
Generated on Fri Jul 22 2022 15:22:19 by
1.7.2