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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers field.cpp Source File

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