View Single Post
Old 08-20-2018, 12:21 PM   #149 (permalink)
Ecky
Master EcoModder
 
Ecky's Avatar
 
Join Date: Dec 2011
Location: New Zealand
Posts: 5,092

ND Miata - '15 Mazda MX-5 Special Package
90 day: 39.72 mpg (US)

Oxygen Blue - '00 Honda Insight
90 day: 58.53 mpg (US)
Thanks: 2,905
Thanked 2,568 Times in 1,592 Posts
Adapted from code John Sullivan wrote:

Quote:
/*Version a20180807
Alpha code
ic.net: mudder
a.k.a John Sullivan

note1: you MUST move QBATT (PNK) to arduino pin 6 (previously pin 10), due to a hardware conflict with counter1.
note2a: you must connect VSS (BLU/WHT*) to arduino pin5.
note2b: *there are multiple BLU/WHT leads... VSS is the one on the gray seat connector (pin8).
*/

//things you may want to change:
static char IMAbatteryEMPTY=30; //set QBATT to 12% duty
static char IMAbatteryHALF=128; //set QBATT to 50% duty
//This is an 8 bit counter (values 0 through 255), so you have to remap percentage (0:100%) to pwm(0:255).
//To do this, multiply the desired percentage by 2.56, but only enter the resulting integer (no decimals).

static char leanBurnMinActivationSpeed = 35; //~mph
/*Lean burn is only activated when speed limit exceeds this value.
If this speed is too low, then the engine may auto stop when coasting to a stop.
Note: integer roundoff will cause the actual crossover point to occur at a lower mph;
probably 5 mph less than whatever you type here (e.g. '35' will probably actually equate to 30 mph).
I may rewrite the conversion if and when someone shows that this alpha code works.
*/

static char hysteresisMPH=1; //prevent rapid QBATT SoC changing when near leanBurnMinActivationSpeed














/*You probably shouldn't change anything below this line (unless you know what's up)

...

If you continue, know that this code was initially written for simplicity for new users,
but now it has some more advanced concepts, such as direct counter register writes.
I've thrown caution to the wind by not using functions, so be careful if you change things.

*/

static char QBATTpin=6; //NOTE pin change (was pin 10)
static char ACTTRQpin=11;
static char MOTFSApin=12;
static char MOTFSBpin=13;
static char VSSpin=5; //T1 for timer 1

static char bitBangDelay_ms = 20;

static float convertVSStoMPH = 1.1125;
//VSS outputs 4000 pulses per mile. Adding time to the equation, that's 1.1125 pulses per mph.

int VSScount=0; //Number of pulses received from VSS since last checked.
char leanBurnMinPulses = 0; //minimum pulses which will activate lean burn.

char frameorder[]={"ba"}; //the simplest "IMA ok" pulse train I could find

int numBitBangs = 0; //since there's no hardware clock, need to know loop execution rate
int loopExecutionTime_ms = 0;

bool firstRun=true;
bool leanBurnEnabled=false;

void setup() {
pinMode(MOTFSApin,OUTPUT); //clock
pinMode(MOTFSBpin,OUTPUT); //data
pinMode(QBATTpin,OUTPUT); //2kHz PWM, 10%=empty, 90%=full
pinMode(ACTTRQpin,OUTPUT); //2kHz PWM, assist>50%, regen<50%

analogWrite(ACTTRQpin,127); //50% duty tells ECU "IMA not delivering torque"
analogWrite(QBATTpin,IMAbatteryEMPTY); //tell ECU battery is nearly empty.

leanBurnMinPulses = char(leanBurnMinActivationSpeed * convertVSStoMPH);
//Floating point math is annoying & slow

//configure counter1
TCCR1A = 0;
TCCR1B = 0b00000111; //set clock to T1 rising edge (VSSpin)
TCCR1C = 0;
TCNT1H = 0; //16 bit counter's upper byte (unused)
TCNT1L = 0;
TIMSK1 = 0; //disable counter interrupts
}

void loop()
{
//send "IMA OK" signal
for(int ii=0;ii<sizeof(frameorder);ii++){bitbang_MOTFSB_fr ame(frameorder[ii]);}

if(firstRun){loopExecutionTime_ms = 2 * bitBangDelay_ms * numBitBangs;}
//value never changes, but don't know numBitBangs until runtime

VSScount = TCNT1L; //read counter1, (number of pulses on VSS)
TCNT1L = 0; //reset counter1 to zero

if(leanBurnEnabled) //(you're going above mph setpoint)
{
if(long(leanBurnMinActivationSpeed) * long(loopExecutionTime_ms) >= long(VSScount) * 1000)
{
analogWrite(QBATTpin,IMAbatteryEMPTY);
leanBurnEnabled=false;
}
}
else //lean burn is presently disabled (because you're going under the mph setpoint)
{
if(long(leanBurnMinActivationSpeed) * long(loopExecutionTime_ms) + hysteresisMPH <= long(VSScount) * 1000)
{
analogWrite(QBATTpin,IMAbatteryHALF);
leanBurnEnabled=true;
}
}

if(firstRun){firstRun=false;} //keep looped math to a minimum. Gotta save those joules!
}

void bitbang_MOTFSB_frame(char nn)
{
if(nn=='a')
{
bangbit(1);
bangbit(1);
bangbit(1);
bangbit(1);
bangbit(1);
bangbit(1);
bangbit(1);
bangbit(1);
bangbit(1);
bangbit(0);
}
else if (nn=='b')
{
bangbit(0);
bangbit(0);
bangbit(0);
bangbit(0);
bangbit(0);
bangbit(0);
bangbit(0);
bangbit(0);
bangbit(0);
bangbit(0);
}
}

void bangbit(bool jj)
{
digitalWrite(MOTFSApin,LOW); //clock low
digitalWrite(MOTFSBpin,jj); //set data
delay(bitBangDelay_ms);
digitalWrite(MOTFSApin,HIGH); //clock high
delay(bitBangDelay_ms);
if(firstRun){numBitBangs++;}
}
leanBurnMinActivationSpeed values of 28 cause auto-stop, even after I tweaked some things. 30 very rarely causes it, if stopping quickly. Still hunting for that golden value between 30 and 35, I'd like to keep it as low as possible.
  Reply With Quote
The Following User Says Thank You to Ecky For This Useful Post:
Daox (08-21-2018)