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

Committer:
JonFreeman
Date:
2020-12-05
Revision:
5:6ca3e7ffc553
Parent:
3:43cb067ecd00

File content as of revision 5:6ca3e7ffc553:

#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
}