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
Electronic Controlled Automatic Choke Control
Moderators: JeffC, rdoherty, stieg, brentp
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).
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
1600cc M10B16
petrol + LPG, MJLJ
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:
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
- ArDRLidle.png (54.22 KiB) Viewed 11512 times
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ
1600cc M10B16
petrol + LPG, MJLJ
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:
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 (temp < 67) {
idleWarmup = -6 * temp + 400;
idle = idleIdeal + idleWarmup + idleAC; // calculate idle speed
}
if (analogRead(tpsPin) < tpsThreshold) {
int hiCurrent = analogRead(dangerPin);
hiCurrent = map(hiCurrent, 400, 655, 0, 1023);
avgHiCurrent = (avgHiCurrent*3+hiCurrent)/4;
if (avgHiCurrent > 555) {
digitalWrite(enableApin, LOW); // switch off the motor
numberOfDangerSitu++;
DEBUG_PRINTLN ("");
DEBUG_PRINTLN ("");
DEBUG_PRINTLN (" DANGER ");
DEBUG_PRINTLN ("");
DEBUG_PRINTLN ("");
delay(1555);
}
if (numberOfDangerSitu > 2) {
digitalWrite(enableApin, LOW); // switch off the motor
DEBUG_PRINTLN ("");
DEBUG_PRINTLN ("");
DEBUG_PRINTLN (" Cool down a bit!!!");
DEBUG_PRINTLN ("");
numberOfDangerSitu=0;
delay(5555);
}
// get and map the value for the maual idle adjustment
int saug = (map(analogRead(2), 0, 1023, 0, 50));
// and if there is NO signal for maual idle adjustment
if (saug < 1) {
// proceed with automatic idle control:
// if rpm is lower than desired idle rpm:
if (rpm < idle - idleThreshold) {
// if it is more than idleHiThreshold lower
if (rpm < idle - idleHiThreshold) stepUpHi=1;
else stepUp=1; // or if it is more than idleThreshold lower
}
// and when idle is corrected
else if (rpm >= idle) {
digitalWrite(enableApin, LOW); // stop the motor
stepUp=0;
stepUpHi=0;
}
// if rpm is idleThreshold [rpm] higher than desired idle rpm
if (rpm > idle + idleThreshold) {
// if it is more than idleHiThreshold higher
if (rpm > idle + idleHiThreshold) stepDownHi=1 ;
else stepDown=1 ; // or if it is more than idleThreshold higher
}
// and when idle is corrected
else if (rpm <= idle) {
digitalWrite(enableApin, LOW); // stop the motor
stepDown=0;
stepDownHi=0;
}
// idle coorection UP
if ((stepUpHi != 0) {
pwmHI=pwmHI+15; // up and down are not build equal
analogWrite(enableApin, pwmHI); // fast speed
digitalWrite(stepApin, HIGH); // turn the motor CW
}
else if ((stepUp != 0) {
#ifdef DEBUG
stepCount++;
#endif
pwmLO=pwmLO+15; // up and down are not build equal
analogWrite(enableApin, pwmLO); // slow speed
digitalWrite(stepApin, HIGH); // turn the motor CW
}
// idle coorection DOWN
if ((stepDownHi != 0) && (digitalRead(idleSW) == LOW)) {
analogWrite(enableApin, pwmHI); // fast speed
digitalWrite(stepApin, LOW); // turn the motor CCW
}
else if ((stepDown != 0) && (digitalRead(idleSW) == LOW)) {
#ifdef DEBUG
stepCount--;
#endif
analogWrite(enableApin, pwmLO); // slow speed
digitalWrite(stepApin, LOW); // turn the motor CCW
}
}
else {
// 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(enableApin, LOW); // power off the motor
if((saug - previousSaug) > 0) {
analogWrite(enableApin, (pwmMD+15)); // set motor speed
digitalWrite(stepApin, HIGH); // turn the motor CW
}
else if((saug - previousSaug) < 0){
analogWrite(enableApin, pwmMD); // set motor speed
digitalWrite(stepApin, LOW); // turn the motor CCW
}
DEBUG_PRINT(" SaugUpDown: ");
DEBUG_PRINT(saug - previousSaug);
// remember the previous value of the Saug
previousSaug = saug;
DEBUG_PRINT(" Saug: ");
DEBUG_PRINT(saug);
}
// DEBUG_PRINT(", Time: ");
// DEBUG_PRINTzeroDEC((micros() - timeold)/eventcount);
// DEBUG_PRINT("us, Freq: ");
// DEBUG_PRINT(rpm/30);
DEBUG_PRINT(" current: ");
DEBUG_PRINT(hiCurrent);
DEBUG_PRINT(" avg current: ");
DEBUG_PRINT(avgHiCurrent);
DEBUG_PRINT(" rpm: ");
DEBUG_PRINTzeroDEC(rpm);
DEBUG_PRINT(", StepUp: ");
DEBUG_PRINT(stepUp);
DEBUG_PRINT(", StepUpHi: ");
DEBUG_PRINT(stepUpHi);
DEBUG_PRINT(", StepDown: ");
DEBUG_PRINT(stepDown);
DEBUG_PRINT(", StepDownHi: ");
DEBUG_PRINT(stepDownHi);
DEBUG_PRINT(", StepCount: ");
DEBUG_PRINT(stepCount);
DEBUG_PRINT(", Target idle: ");
DEBUG_PRINT(idle);
}
// if handbrake AND light switchches are HIGH,
// AND rpm> 655, DRL is ON:
if ((digitalRead(brakeswPin) == HIGH) && \
(digitalRead(lightswPin) == HIGH) && \
(rpm > 655)) {
analogWrite(DRLoutPin, 90); // set PWM to ~ 35%
}
// in any other case - DRL is OFF
else {
digitalWrite(DRLoutPin, LOW);
}
// if coolant temp >= 91C, turn on the low temp relay:
if (temp >= lowtTempTreshold) {
digitalWrite(lowTempPin, HIGH);
}
// when coolant temp is low enough switch off the temp low relay:
else if (temp < lowtTempTreshold-tempHisteresis){
digitalWrite(lowTempPin,LOW);
}
// if the coolant temp >= 99C, turn on the hi temp relay:
if (temp >= hiTempThreshold) {
digitalWrite(hiTempPin, HIGH);
}
// when coolant temp is low enaugh switch off the hi temp relay:
else if (temp < hiTempThreshold-tempHisteresis){
digitalWrite(hiTempPin,LOW);
}
// print the temperature:
DEBUG_PRINT(", Celsius: ");
DEBUG_PRINTLN(temp);
}
checklog(); // make sure log is ok before processing
processlog(); // process and dump the log file to the PC ?????
chkstale(); // check to see if tach readings are > 3 seconds old (stopped!)
}
void chkstale()
{
if ((millis()> (lasttachint+3000)) && (rpm>0)){
rpm=0;
}
}
// Make sure log hasn't overflowed
void checklog()
{
if (logoflo==true)
{
noInterrupts();
clearlog();
interrupts();
DEBUG_PRINT("log overflowed at ");
DEBUG_PRINTLN(millis());
}
}
void processlog()
{
int dlog,i; // how many entries to copy and dump
unsigned long dmillis[32];
byte dflag[32]; // space for the log entries
noInterrupts(); // disable interrupts while we copy the log
dlog=ilog; // copy the count
if (dlog!=0) // if there's anything to copy
{
for(int i=0; i<dlog;i++)
{
dmillis[i]=lmillis[i];
dflag[i]=lflag[i];
}
ilog=0; // reset the count
}
interrupts(); // reenable interrupts
if (dlog!=0) // if there's anything to process
{
for (i=0;i<dlog;i++)
{
if (dflag[i]=='T')
{
processtach(dmillis[i]);
}
}
}
}
// RPM Calculation logic
void processtach(unsigned long lmillis) // input is interrupt time in millis
{
unsigned long tachtime; // elapsed time for 10 tach events
if (lasttachint!=0) // skip calculation on first time in
{
tachtime=lmillis-lasttachint; // time for last 10 events
if (tachtime>0) // just avoid divide by 0
{
//rpm based on time in ms for 10 tach pulses
rpm=(30000/(float)tachtime)*10;
}
}
lasttachint=lmillis;
}
// Tach interrupt function
void tachmonitor()
{
static int tachcount;
if (tachcount <9) // bulking up tach interrupts by a factor of 10
{
tachcount++;
}
else // every 10th tach pulse we spawn a log entry
{
if (ilog<=maxlog)
{
lflag[ilog]='T'; // pedal pass flag
lmillis[ilog]=millis();
ilog++;
}
else
{
logoflo=true; // we've overrun the log table
}
tachcount=0;
}
}
void clearlog() // clear the interrupt log
{
for(int i=0; i<=maxlog; i++)
{
lflag[i]=' ';
lmillis[i]=12345678;
}
ilog=0;
logoflo=false;
}
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ
1600cc M10B16
petrol + LPG, MJLJ
-
- Posts: 152
- Joined: Wed Jan 02, 2008 12:52 pm
- Location: Melbourne, Australia
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.
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.
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.
Anyway, I hope that someone will find what I posted usefull.
'87 BMW 316 E30
1600cc M10B16
petrol + LPG, MJLJ
1600cc M10B16
petrol + LPG, MJLJ