Electronic Controlled Automatic Choke Control

What would you like to see? Post your suggestions here!

Moderators: JeffC, rdoherty, stieg, brentp

brentp
Site Admin
Posts: 6282
Joined: Wed Jan 24, 2007 6:36 am

Post by brentp »

Aside from a timer, consider these:

- use a modern chip with built in current-limiting and over-heat protection.
- build a discrete H-Bridge using self-protecting MOSFETS. An L297 could provide the logic for driving the Mosfets.
- build a current sense circuit (using a low ohm current sense resistor) to trip an 'over current' condition, that the microcontroller could detect
Brent Picasso
CEO and Founder, Autosport Labs
Facebook | Twitter

Yvan
Posts: 86
Joined: Fri Feb 08, 2008 7:58 pm
Location: Kragujevac, Serbia

Post by Yvan »

I took this (four pin) one apart, and and two pins are power for DC motor, other two are for the switch that can be used to sense when the switch is looses contact with whatever it is with contact with when it retracts (or when it comes back in contact when turning the other way).

Six pin ones seems to have some sort of hall sensor, as can be seen here:

http://www.zen17496.zen.co.uk/downloads/g3adzecu.pdf

on page 3 - part V60

So with six pin ones I could have the position feedback, but I already have build the shield for the stepper motor idle control, and I now just used the half of the L293 for DC motor control (with few modifications to the board).
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ

Yvan
Posts: 86
Joined: Fri Feb 08, 2008 7:58 pm
Location: Kragujevac, Serbia

Post by Yvan »

Hi Brent, you replied to this thread both time while I was writing (and since English is not my native language it takes some time). :-)

I know that I can use some other chip, but than I must design new board. This one is designed for stepper motor, and it worked well on the bench, but big dissapointment when I tried it on the engine - could not move the throttle valve. At least not consistently.

So I am trying to do the best I can with what I have.

I was also thinking of adding a temperature sensor glued to the L293. How fast does the sensor read? Is it worth doing?

Anyway, you got me interested back, so I did some more programing, and decided to use average of four readings of overcurrent condition as a parameter for motor shutdown. It seems that it works OK (at the bench at least). :-)

Here is my circuit design:
Attachments
DRL and idle control circuit
DRL and idle control circuit
ArDRLidle.png (54.22 KiB) Viewed 11515 times
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ

Yvan
Posts: 86
Joined: Fri Feb 08, 2008 7:58 pm
Location: Kragujevac, Serbia

Post by Yvan »

My programing skills are about the same as my electronic design skills: I copied most of it from the circuits I found on the Internet, and adapted it for my needs. Comments are probably misspelled. And It could be done much easier, cleaner, better... But it works for me (again so far only on the bench). :-)

Here is the arduino sketch:

Code: Select all

#define DEBUG

#ifdef DEBUG
#define DEBUG_PRINT(x)         Serial.print (x)
#define DEBUG_PRINTzeroDEC(x)  Serial.print (x, 0) // 0 decimal places
#define DEBUG_PRINTDEC(x)      Serial.print (x, DEC)
#define DEBUG_PRINTLN(x)       Serial.println (x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTzeroDEC(x)
#define DEBUG_PRINTDEC(x)
#define DEBUG_PRINTLN(x)
#endif

// Input pins:
const int temperaturePin = A0;     // temperature sensor input
const int tpsPin = A1;             // TPS input
const int saugPin = A2;            // manual saug control input
const int dangerPin = A3;          // sensing DC motor overcurrent

const int acPin = 2;               // a/c ON sensing input
const int idleSW = 4;              // idle switch input
const int brakeswPin = 6;          // "handbrake on" switch input
const int lightswPin = 7;          // "lights on" switch input

// Output pins:
const int DRLoutPin = 5;           // DRL output
const int enableApin = 10;         // PWM motor
const int stepApin = 11;           // drive DC motor
const int lowTempPin = 12;         // low temp relay
const int hiTempPin = 13;          // hi temp relay

// These constants won't change:
const int lowtTempTreshold = 91;   // threshold level for low temp relay
const int hiTempThreshold = 99;    // threshold level for hi temp relay
const int tempHisteresis = 4;      // histeresis for temp relays [deg Celsius]
const int idleThreshold = 20;                          // 50when to start idle correction
const int idleHiThreshold = 85;    // 85when to start fast idle correction
const int idleIdeal = 850;         // idle rpm for warmed up engine
const int tpsThreshold = 100;      // stop idle adjustment above this threshold

int previousSaug = 0;              // for manual idle controll via potentiometer
int stepUp = 0;
int stepUpHi = 0;
int stepDown = 0;
int stepDownHi = 0;
#ifdef DEBUG
int stepCount = 0;
#endif
float pullupR = 2385;              // measured resistance of CLT pullup resistor
long resistance;
float temp;
int avgHiCurrent = 0;              // high current average value
int numberOfDangerSitu=0;          // number of high current danger situations


// RPM Calculation variables
unsigned long lasttachint;        //time in millis of most recent tach interrupt
float rpm=0;                      //tach instantaneous rpm
volatile int ilog=0;
int maxlog=31;
volatile boolean logoflo;   //index to log table, max entry #, log overflow flag
volatile byte lflag[32];
volatile unsigned long lmillis[32]; //log of interrupts

// Init function
void setup()
{
#ifdef DEBUG
  // Initialize serial comms
  Serial.begin(9600);
#endif

  digitalWrite(10, LOW);            // disable first DC motor
  digitalWrite(8, LOW);             // disable second DC motor

  // Clear the interrupt table
  clearlog();

  // declare in/out pins:
  pinMode(acPin, INPUT);
  pinMode(idleSW, INPUT);
  pinMode(brakeswPin, INPUT);
  pinMode(lightswPin, INPUT);
  pinMode(3, INPUT);                        // rpm input pin

  pinMode(DRLoutPin, OUTPUT);
  pinMode(enableApin, OUTPUT);
  pinMode(stepApin, OUTPUT);
  pinMode(lowTempPin, OUTPUT);
  pinMode(hiTempPin, OUTPUT);

  // turn the motor CCW to the start position
  while (digitalRead(idleSW) == LOW) {
    digitalWrite(enableApin, HIGH); // fast motor speed
    digitalWrite(stepApin, LOW);    // turn the motor CCW
  }

  // Attach interrupt from tachometer
  attachInterrupt(1, tachmonitor, RISING);
}

// Main loop
void loop()
{
  if (rpm > 455) {                            // is the engine runnung?
    int pwmLO = 75;                                  // set low PWM 50% - low motor speed
    int pwmMD = 65;                                  // set high PWM 25% - midle motor speed
    int pwmHI = 127;                                 // set high PWM 100% - hi motor speed
    float RawADC = analogRead(temperaturePin);
    resistance = ((pullupR * RawADC) / (1024 - RawADC));
    temp = log(resistance);
    // use the Steinhart-Hart Thermistor Equation:
    // Temperature in Kelvin = 1 / {A + B[ln(R)] + C[ln(R)]^3}
    temp = 1 / (0.001761660642 + (0.0002364853666 * temp) + \
               (0.0000002766518199 * temp * temp * temp ));
    temp = temp - 273.15;                     // Convert Kelvin to Celsius

    int idle = idleIdeal;                     // set the initial idle speed
    int idleAC = 0;
    int idleWarmup = 0;
    if (digitalRead(acPin) == LOW) {
      idleAC = 250;                           // raise rpm if a/c is on
      idle = idleIdeal + idleWarmup + idleAC; // calculate idle speed
    }

    // calculate warmup idle (below 67 Celsius)
    if &#40;temp < 67&#41; &#123;
      idleWarmup = -6 * temp + 400;
      idle = idleIdeal + idleWarmup + idleAC; // calculate idle speed
    &#125;

    if &#40;analogRead&#40;tpsPin&#41; < tpsThreshold&#41; &#123;
      int hiCurrent = analogRead&#40;dangerPin&#41;;
      hiCurrent = map&#40;hiCurrent, 400, 655, 0, 1023&#41;;
      avgHiCurrent = &#40;avgHiCurrent*3+hiCurrent&#41;/4;
      if &#40;avgHiCurrent > 555&#41; &#123;
        digitalWrite&#40;enableApin, LOW&#41;;        // switch off the motor
        numberOfDangerSitu++;
        DEBUG_PRINTLN &#40;""&#41;;
        DEBUG_PRINTLN &#40;""&#41;;
        DEBUG_PRINTLN &#40;"  DANGER  "&#41;;
        DEBUG_PRINTLN &#40;""&#41;;
        DEBUG_PRINTLN &#40;""&#41;;
        delay&#40;1555&#41;;
      &#125;
      if &#40;numberOfDangerSitu > 2&#41; &#123;
        digitalWrite&#40;enableApin, LOW&#41;;        // switch off the motor
        DEBUG_PRINTLN &#40;""&#41;;
        DEBUG_PRINTLN &#40;""&#41;;
        DEBUG_PRINTLN &#40;"         Cool down a bit!!!"&#41;;
        DEBUG_PRINTLN &#40;""&#41;;
        numberOfDangerSitu=0;
        delay&#40;5555&#41;;
      &#125;

      // get and map the value for the maual idle adjustment
      int saug = &#40;map&#40;analogRead&#40;2&#41;, 0, 1023, 0, 50&#41;&#41;;
      // and if there is NO signal for maual idle adjustment
      if &#40;saug < 1&#41; &#123;
        // proceed with automatic idle control&#58;

        // if rpm is lower than desired idle rpm&#58;
        if &#40;rpm < idle - idleThreshold&#41; &#123;
          // if it is more than idleHiThreshold lower
          if &#40;rpm < idle - idleHiThreshold&#41; stepUpHi=1;
          else stepUp=1;  // or if it is more than idleThreshold lower
        &#125;

        // and when idle is corrected
        else if &#40;rpm >= idle&#41; &#123;
          digitalWrite&#40;enableApin, LOW&#41;;  // stop the motor
          stepUp=0;
          stepUpHi=0;
        &#125;

        // if rpm is idleThreshold &#91;rpm&#93; higher than desired idle rpm
        if &#40;rpm > idle + idleThreshold&#41; &#123;
          // if it is more than idleHiThreshold higher
          if &#40;rpm > idle + idleHiThreshold&#41; stepDownHi=1 ;
          else stepDown=1 ;  // or if it is more than idleThreshold higher
        &#125;
        // and when idle is corrected
        else if &#40;rpm <= idle&#41; &#123;
          digitalWrite&#40;enableApin, LOW&#41;;  // stop the motor
          stepDown=0;
          stepDownHi=0;
        &#125;

        // idle coorection UP
        if &#40;&#40;stepUpHi != 0&#41; &#123;
          pwmHI=pwmHI+15;                 // up and down are not build equal
          analogWrite&#40;enableApin, pwmHI&#41;; // fast speed
          digitalWrite&#40;stepApin, HIGH&#41;;   // turn the motor CW
        &#125;
        else if &#40;&#40;stepUp != 0&#41; &#123;
#ifdef DEBUG
          stepCount++;
#endif
          pwmLO=pwmLO+15;                  // up and down are not build equal
          analogWrite&#40;enableApin, pwmLO&#41;;  // slow speed
          digitalWrite&#40;stepApin, HIGH&#41;;    // turn the motor CW
        &#125;

        // idle coorection DOWN
        if &#40;&#40;stepDownHi != 0&#41; && &#40;digitalRead&#40;idleSW&#41; == LOW&#41;&#41; &#123;
          analogWrite&#40;enableApin, pwmHI&#41;; // fast speed
          digitalWrite&#40;stepApin, LOW&#41;;    // turn the motor CCW
        &#125;
        else if &#40;&#40;stepDown != 0&#41; && &#40;digitalRead&#40;idleSW&#41; == LOW&#41;&#41; &#123;
#ifdef DEBUG
          stepCount--;
#endif
          analogWrite&#40;enableApin, pwmLO&#41;; // slow speed
          digitalWrite&#40;stepApin, LOW&#41;;    // turn the motor CCW
        &#125;
      &#125;

      else &#123;
        // if the signal for maual idle adjustment exists
        // turn the motor CW or CCW in respest to the change
        // in the reading for maual idle adjustment
        digitalWrite&#40;enableApin, LOW&#41;;    // power off the motor
        if&#40;&#40;saug - previousSaug&#41; > 0&#41; &#123;
          analogWrite&#40;enableApin, &#40;pwmMD+15&#41;&#41;; // set motor speed
          digitalWrite&#40;stepApin, HIGH&#41;;   // turn the motor CW
        &#125;
        else if&#40;&#40;saug - previousSaug&#41; < 0&#41;&#123;
          analogWrite&#40;enableApin, pwmMD&#41;; // set motor speed
          digitalWrite&#40;stepApin, LOW&#41;;    // turn the motor CCW
        &#125;
        DEBUG_PRINT&#40;"  SaugUpDown&#58; "&#41;;
        DEBUG_PRINT&#40;saug - previousSaug&#41;;
        // remember the previous value of the Saug
        previousSaug = saug;
        DEBUG_PRINT&#40;"  Saug&#58; "&#41;;
        DEBUG_PRINT&#40;saug&#41;;
      &#125;

      // DEBUG_PRINT&#40;",  Time&#58; "&#41;;
      // DEBUG_PRINTzeroDEC&#40;&#40;micros&#40;&#41; - timeold&#41;/eventcount&#41;;
      // DEBUG_PRINT&#40;"us,  Freq&#58; "&#41;;
      // DEBUG_PRINT&#40;rpm/30&#41;;
      DEBUG_PRINT&#40;"  current&#58; "&#41;;
      DEBUG_PRINT&#40;hiCurrent&#41;;
      DEBUG_PRINT&#40;"  avg current&#58; "&#41;;
      DEBUG_PRINT&#40;avgHiCurrent&#41;;
      DEBUG_PRINT&#40;"  rpm&#58; "&#41;;
      DEBUG_PRINTzeroDEC&#40;rpm&#41;;
      DEBUG_PRINT&#40;",  StepUp&#58; "&#41;;
      DEBUG_PRINT&#40;stepUp&#41;;
      DEBUG_PRINT&#40;",  StepUpHi&#58; "&#41;;
      DEBUG_PRINT&#40;stepUpHi&#41;;
      DEBUG_PRINT&#40;",  StepDown&#58; "&#41;;
      DEBUG_PRINT&#40;stepDown&#41;;
      DEBUG_PRINT&#40;",  StepDownHi&#58; "&#41;;
      DEBUG_PRINT&#40;stepDownHi&#41;;
      DEBUG_PRINT&#40;",  StepCount&#58; "&#41;;
      DEBUG_PRINT&#40;stepCount&#41;;
      DEBUG_PRINT&#40;",  Target idle&#58; "&#41;;
      DEBUG_PRINT&#40;idle&#41;;
    &#125;

    // if handbrake AND light switchches are HIGH,
    // AND rpm> 655, DRL is ON&#58;
    if &#40;&#40;digitalRead&#40;brakeswPin&#41; == HIGH&#41; && \ 
    &#40;digitalRead&#40;lightswPin&#41; == HIGH&#41; && \
        &#40;rpm > 655&#41;&#41; &#123;
      analogWrite&#40;DRLoutPin, 90&#41;;          // set PWM to ~ 35%
    &#125; 
    // in any other case - DRL is OFF
    else &#123;
      digitalWrite&#40;DRLoutPin, LOW&#41;;
    &#125;

    // if coolant temp >= 91C, turn on the low temp relay&#58;
    if &#40;temp >= lowtTempTreshold&#41; &#123;
      digitalWrite&#40;lowTempPin, HIGH&#41;;
    &#125; 
    // when coolant temp is low enough switch off the temp low relay&#58;
    else if &#40;temp < lowtTempTreshold-tempHisteresis&#41;&#123;
      digitalWrite&#40;lowTempPin,LOW&#41;; 
    &#125;

    // if the coolant temp >= 99C, turn on the hi temp relay&#58;
    if &#40;temp >= hiTempThreshold&#41; &#123;
      digitalWrite&#40;hiTempPin, HIGH&#41;;
    &#125; 
    // when coolant temp is low enaugh switch off the hi temp relay&#58;
    else if &#40;temp < hiTempThreshold-tempHisteresis&#41;&#123;
      digitalWrite&#40;hiTempPin,LOW&#41;; 
    &#125;

    // print the temperature&#58;
    DEBUG_PRINT&#40;",  Celsius&#58; "&#41;; 
    DEBUG_PRINTLN&#40;temp&#41;;
  &#125;
  checklog&#40;&#41;;    // make sure log is ok before processing
  processlog&#40;&#41;;  // process and dump the log file to the PC ?????
  chkstale&#40;&#41;;    // check to see if tach readings are > 3 seconds old &#40;stopped!&#41;

&#125;
void chkstale&#40;&#41;
&#123;
  if &#40;&#40;millis&#40;&#41;> &#40;lasttachint+3000&#41;&#41; && &#40;rpm>0&#41;&#41;&#123;
    rpm=0; 
  &#125;
&#125;

// Make sure log hasn't overflowed
void checklog&#40;&#41;
&#123;
  if &#40;logoflo==true&#41;
  &#123;
    noInterrupts&#40;&#41;;
    clearlog&#40;&#41;;
    interrupts&#40;&#41;;
    DEBUG_PRINT&#40;"log overflowed at "&#41;;
    DEBUG_PRINTLN&#40;millis&#40;&#41;&#41;;
  &#125;
&#125;

void processlog&#40;&#41;
&#123;
  int dlog,i;                 // how many entries to copy and dump
  unsigned long dmillis&#91;32&#93;;
  byte dflag&#91;32&#93;;             // space for the log entries
  noInterrupts&#40;&#41;;             // disable interrupts while we copy the log
  dlog=ilog;                  // copy the count
  if &#40;dlog!=0&#41;                // if there's anything to copy
  &#123;
    for&#40;int i=0; i<dlog;i++&#41;
    &#123;
      dmillis&#91;i&#93;=lmillis&#91;i&#93;;
      dflag&#91;i&#93;=lflag&#91;i&#93;;
    &#125;
    ilog=0;                   // reset the count
  &#125;
  interrupts&#40;&#41;;               // reenable interrupts
  if &#40;dlog!=0&#41;                // if there's anything to process
  &#123;
    for &#40;i=0;i<dlog;i++&#41;
    &#123;
      if &#40;dflag&#91;i&#93;=='T'&#41;
      &#123;
        processtach&#40;dmillis&#91;i&#93;&#41;;
      &#125;
    &#125;
  &#125;
&#125;

// RPM Calculation logic
void processtach&#40;unsigned long lmillis&#41; // input is interrupt time in millis
&#123;
  unsigned long tachtime;          // elapsed time for 10 tach events
  if &#40;lasttachint!=0&#41;              // skip calculation on first time in
  &#123;
    tachtime=lmillis-lasttachint;  // time for last 10 events
    if &#40;tachtime>0&#41;                // just avoid divide by 0
    &#123;
      //rpm based on time in ms for 10 tach pulses
      rpm=&#40;30000/&#40;float&#41;tachtime&#41;*10;
    &#125;
  &#125;
  lasttachint=lmillis;
&#125;

// Tach interrupt function
void tachmonitor&#40;&#41;
&#123;
  static int tachcount;
  if &#40;tachcount <9&#41;              // bulking up tach interrupts by a factor of 10
  &#123;
    tachcount++;
  &#125;
  else                           // every 10th tach pulse we spawn a log entry
  &#123;
    if &#40;ilog<=maxlog&#41;
    &#123;
      lflag&#91;ilog&#93;='T';           // pedal pass flag
      lmillis&#91;ilog&#93;=millis&#40;&#41;;
      ilog++;
    &#125;
    else
    &#123;
      logoflo=true;              // we've overrun the log table
    &#125;
    tachcount=0;
  &#125;
&#125;

void clearlog&#40;&#41;                  // clear the interrupt log
&#123;
  for&#40;int i=0; i<=maxlog; i++&#41;
  &#123;
    lflag&#91;i&#93;=' ';
    lmillis&#91;i&#93;=12345678;
  &#125;
  ilog=0;
  logoflo=false;
&#125;
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ

Yvan
Posts: 86
Joined: Fri Feb 08, 2008 7:58 pm
Location: Kragujevac, Serbia

Post by Yvan »

Comments and suggestions are appreciated.
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ

Spockie-Tech
Posts: 152
Joined: Wed Jan 02, 2008 12:52 pm
Location: Melbourne, Australia

Post by Spockie-Tech »

Um..

It looks like too much circuitry and code for a general "comments and suggestions ?" request.

Do you have any specific areas you want suggestions on ? Otherwise, any potential readers would need to familairise themself with your whole purpose, design, code, build it themself and see if it works the way they would have done it. Not very likely.

Yvan
Posts: 86
Joined: Fri Feb 08, 2008 7:58 pm
Location: Kragujevac, Serbia

Post by Yvan »

No, nothing specific. I guess that someone with more knowledge than me (I already wrote that I copied most of the circuits and code from the different locations on the Internet) could easily spot a weak point. Perhaps not.

Anyway, I hope that someone will find what I posted usefull.
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ

Post Reply