Arduino som övervakar båtmotorn

Planering och tankar kring eventuella framtida projekt.
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Arduino som övervakar båtmotorn

Inlägg av BjörnO »

När jag förra året funderade på att förse min gamla båtmotor med en varvräknare fick jag ett förslag att lösa det med en Arduino. Då löste jag det i stället med en billig cykeldator.

Men - tanken slog rot och jag har just köpt en Arduino. Nu gäller det att plocka fram 40 år gamla programmeringskunskaper.

En enkel varvräknare får det bli till att börja med. Bara en rad lysdioder som visar några valda varvtal (marschvarv, maxvarv och några nivåer till).

Här är förslag på kod. Kommentarer mottages tacksamt:

Kod: Markera allt

/*
    UNO board.
    Takes rpm samples via ADC pin, and shows the value on LEDs.
*/

// revmeter, pulse input on pin 2 ----------------------------------------------

int ledR1 = 3; //the number of the pin red LED
int ledR2 = 4; //yellow
int ledR3 = 5; //green
int ledR4 = 6; //green
int ledR5 = 7; //green

unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
unsigned long result = 0;

int pin13 = 13;

void setup()
{
// revmeter setup --------------------------------------------------------------------
    pinMode(ledR1, OUTPUT);   //LED array
    pinMode(ledR2, OUTPUT);
    pinMode(ledR3, OUTPUT);
    pinMode(ledR4, OUTPUT);
    pinMode(ledR5, OUTPUT);

    attachInterrupt (0, inputPulse, RISING);  //pulse imput from rev sensor
}

void loop()
{
    // revmeter loop ------------------------------------------------------------
   	 if (result > (60000 / 2500))       	//2500 rpm (max rpm)
   		 digitalWrite(ledR1, HIGH);
   	 else
   		 digitalWrite(ledR1, LOW);

   	 if (result > (60000 / 2000))        	//2000 rpm (cruising speed)
   		 digitalWrite(ledR2, HIGH);
   	 else
   		 digitalWrite(ledR2, LOW);

   	 if (result > (60000 / 1500))        	//1500 rpm
   		 digitalWrite(ledR3, HIGH);
   	 else
   		 digitalWrite(ledR3, LOW);

   	 if (result > (60000 / 1000))        	//1000 rpm
   		 digitalWrite(ledR4, HIGH);
   	 else
   		 digitalWrite(ledR4, LOW);

   	 if (result > (60000 / 700))         	//700 rpm (idle)
   		 digitalWrite(ledR5, HIGH);
   	 else
   		 digitalWrite(ledR5, LOW);
}

// revmeter interrupt ----------------------------------------------------------
void inputPulse()
{
    currentMillis = millis();             	  //read millis
    result = currentMillis - previousMillis;  //calculate time 
    previousMillis = currentMillis;       	  //save last pulse and prepare for next pulse
}
Senast redigerad av BjörnO 26 december 2013, 17:30:01, redigerad totalt 1 gång.
JanErik
Inlägg: 3118
Blev medlem: 11 februari 2008, 17:15:58
Ort: Vasa, Finland

Re: Arduino som övervakar båtmotorn

Inlägg av JanErik »

Jag skulle nog sätta ett kort flytande medelvärde, dvs en cirkulär buffer på kanske fem "result" för att få stabilare mätvärde.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Arduino som övervakar båtmotorn

Inlägg av blueint »

Fanns väl inte mycket till C programmering 1973 ? ;)
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Nej, C fanns inte då. Jag programmerade i Fortran-4 och maskinspråk för 3-bitars datorer uppbyggda av transistorer. När de första mikrodatorkretsarna kom byggde jag mig en egen dator, långt innan någon kunde stava till PC. Förutom ett eller annat DOS-kommando och någon redigering av PostScript har jag inte programmerat sedan dess.
Det blir att bläddra bland kommandon i manualen och försöka välja något lämpligt.
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Eftersom mitt första önskemål var en analog varvräknare kopplar jag ett instrument till en pwm-utgång med följande kod:

Kod: Markera allt

int meterOut = 9; //analog out
	analogWrite(meterOut, 3825 / result)	//analog out to meter (0-4000 rpm = 0-5V)
Senast redigerad av BjörnO 29 december 2013, 19:50:18, redigerad totalt 1 gång.
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Kompletterade med medelvärde. Så här ser det ut nu:

Kod: Markera allt

/*
    UNO board.
    Takes rpm samples via ADC pin, and shows the value on five LEDs.
    also outputs an pwm signal to analog meter
*/

// revmeter, pulse input on pin 2 ----------------------------------------------

int ledR1 = 3; //the pin number of the red LED
int ledR2 = 4; //yellow
int ledR3 = 5; //green
int ledR4 = 6; //green
int ledR5 = 7; //green

int meterOut = 9; //analog out

int a = 0;

unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
unsigned long partresult[6] = {0, 0, 0, 0, 0};
unsigned long result = 0;

int pin13 = 13;

void setup()
{
// revmeter setup --------------------------------------------------------------
	pinMode(ledR1, OUTPUT);   //LED array
	pinMode(ledR2, OUTPUT);
	pinMode(ledR3, OUTPUT);
	pinMode(ledR4, OUTPUT);
	pinMode(ledR5, OUTPUT);

	attachInterrupt (0, inputPulse, RISING);  //pulse imput from rev sensor
}

void loop()
{
	// revmeter loop -----------------------------------------------------------
	if (result > (60000 / 2500))           //2500 rpm (max rpm)
		digitalWrite(ledR1, HIGH);
	else
		digitalWrite(ledR1, LOW);

	if (result > (60000 / 2000))            //2000 rpm (cruising speed)
		digitalWrite(ledR2, HIGH);
	else
		digitalWrite(ledR2, LOW);

	if (result > (60000 / 1500))            //1500 rpm
		digitalWrite(ledR3, HIGH);
	else
		digitalWrite(ledR3, LOW);

	if (result > (60000 / 1000))            //1000 rpm
		digitalWrite(ledR4, HIGH);
	else
		digitalWrite(ledR4, LOW);

	if (result > (60000 / 700))             //700 rpm (idle)
		digitalWrite(ledR5, HIGH);
	else
		digitalWrite(ledR5, LOW);

	analogWrite(meterOut, 3825 / result);    //analog out to meter (0-4000 rpm = 0-5V)
}

// revmeter interrupt ----------------------------------------------------------
void inputPulse()
{
	currentMillis = millis();                        //read millis
	partresult[a] = currentMillis - previousMillis;  //calculate time
	previousMillis = currentMillis;                  //save last pulse and prepare for next pulse
	result = (partresult[0] + partresult[1] + partresult[2] + partresult[3] + partresult[4]) / 5; //mean value of 5 results
	a += 1;        //next step
	if (a = 5)     //reset if end
	{
		a = 0;
	}
}

Edit: Rättade koden.
Senast redigerad av BjörnO 29 december 2013, 19:48:28, redigerad totalt 1 gång.
PopUnoNkoK
Inlägg: 789
Blev medlem: 10 december 2007, 12:40:08
Ort: Piteå

Re: Arduino som övervakar båtmotorn

Inlägg av PopUnoNkoK »

Jag blir nyfiken på hur hårdvaran ser ut. Alltså själva varvräknar delen, input.
Blir säkert snyggt med analog visare, på rätt båt förstås. =)

mvh Peter
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Hårdvaran för varvräknaren blir i första hand den som jag redan monterat, dvs en magnet på svänghjulet och cykeldatorns sensor, se http://elektronikforumet.com/forum/view ... 37#p962837. Jag vet att jag har en hallelementsensor liggande någonstans. Kanske jag hittar den innan det är dags.

Mitt problem är att jag inte kan testa förrän efter sjösättningen i vår, så det får bli "torrsim" i stället. Kanske jag kan göra en mockup med en boorrmaskin som svänghjul.
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Kom på att jag kunde använda en andra Arduino som kan mata ut pulser och fungera som motor. Här är lite kod för den:

Kod: Markera allt

/*
   /*
   UNO board.
   Emits pulses for testing of the RPM meter.
   20 ms between pulses (at 3000 rpm) to 90 ms between pulses (at 666 rpm)
   One 0.1 ms pulse each pulse time during 10 s.
   Then next pulse time in sequence until 90 ms.
*/

unsigned long pM = 0;   	 //pulse time
unsigned long sM = 0;   	 //sequence time
unsigned long M = 0;   	 //time
int pT = 10;
int count = 0;
int out = 13;   			 //pulse output pin

void setup()
{
    pinMode(out, OUTPUT);
    Serial.begin(9600);
    delay(10000);   		 //delay 1 s to allow time to start serial monitor
}

void loop()
{
    M = millis();   		 //read millis and save

    if (M < pM + pT)   	 //when time for a pulse - emit pulse
   	 return;
    digitalWrite(out, HIGH);
    delayMicroseconds(100);
    digitalWrite(out, LOW);
    pM = M;   				 //start over

    if(M < sM + 10000)   	 //after 10 s - next pulse time
   	 return;
    pT = pT + 10;
    sM = M;   				 //start over
    Serial.println(pT);   	 //print speed

    if(pT < 90)   			 //when all speeds are done - start from the beginning
   	 return;
    pT = 10;
}
och så här ser varvräknarkoden ut nu:

Kod: Markera allt

/*
	UNO board.
	Takes rpm samples via ADC pin, and shows the value on five LEDs.
	also outputs a pwm signal to analog meter
*/

// revmeter setup, pulse input on pin 2 ----------------------------------------

int ledR1 = 3; //the pin number of the red LED
int ledR2 = 4; //yellow
int ledR3 = 5; //green
int ledR4 = 6; //green
int ledR5 = 7; //green

int meterOut = 9; //analog out

int a = 0;

unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
unsigned long partresult[6] = {0, 0, 0, 0, 0};
unsigned long result = 0;

int pin13 = 13;

void setup()
{
    pinMode(ledR1, OUTPUT);   //LED array
    pinMode(ledR2, OUTPUT);
    pinMode(ledR3, OUTPUT);
    pinMode(ledR4, OUTPUT);
    pinMode(ledR5, OUTPUT);

    attachInterrupt (0, inputPulse, RISING);  //pulse imput from rev sensor
}

void loop()
{
    // revmeter loop to display values on LEDs ---------------------------------
    analogWrite(meterOut, 3825 / result);	//analog out to meter (0-4000 rpm = 0-5V)

    if ((result < (60000 / 700)) and (result >= (60000 / 1000)))  //700-1000 rpm (idle) 85,7-60
   	 digitalWrite(ledR5, HIGH);
    else
   	 digitalWrite(ledR5, LOW);

    if ((result < (60000 / 1000)) and (result >= (60000 / 1500)))  //1000-1500 rpm 60-40
   	 digitalWrite(ledR4, HIGH);
    else
   	 digitalWrite(ledR4, LOW);

    if ((result < (60000 / 1500)) and (result >= (60000 / 2000)))  //1500-2000 rpm  40-30
   	 digitalWrite(ledR3, HIGH);
    else
   	 digitalWrite(ledR3, LOW);

    if ((result < (60000 / 2000)) and (result >= (60000 / 2500)))  //2000-2500 rpm (cruising speed) 30-24
   	 digitalWrite(ledR2, HIGH);
    else
   	 digitalWrite(ledR2, LOW);

    if (result < (60000 / 2500))        	//2500 rpm (max rpm) 24
   	 digitalWrite(ledR1, HIGH);
    else
   	 digitalWrite(ledR1, LOW);
}

// revmeter interrupt ----------------------------------------------------------
void inputPulse()
{
    currentMillis = millis();                    	//read millis
    partresult[a] = currentMillis - previousMillis;  //time between pulses
    previousMillis = currentMillis;              	//prepare for next pulse
    result = (partresult[0] + partresult[1] + partresult[2] + partresult[3] + partresult[4]) / 5; //mean value of 5 results
    a = a + 1;										 //next step
    if (a == 5)
    {
   	 a = 0;   	//start over if end
    }
}
Nu ser det ut att fungera:


Om någon ser att jag gjort något konstigt så säg till.

/Björn
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Nu har jag dammat av projektet igen.

Ett första steg kommer att övervaka tre temperaturer i motorrummet och motorns varvtal. Med tre i2c- temeratursensorer och en i2c- display blir ledningsdragningen minimal för temperaturövervakningen. Hallelementsensorn koplar jag som tidigare till en inerruptingång.

Läsa av temperaturerna och visa resultatet på displayen verkar ganska enkelt. Men hur går det när interrupten bryter in, upp till 3000 gånger per minut?
Användarvisningsbild
PaNiC
Inlägg: 2565
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

Re: Arduino som övervakar båtmotorn

Inlägg av PaNiC »

Interrupten avbryter ju allt annat du håller på med, så man gör klokt i att hålla interruptrutinerna så korta som möjligt. Nu vet jag inte hur det funkar med Arduino, men hade du använt AVRen "ren" så hade du kunnat koppla pulsgivaren direkt till timer/countern genom hårdvara, så hade du sluppit interruptrutinen där, men kanske fått ha en timer-interrupt istället för att läsa av räknaren. Men den hade du ju då kunnat hålla till displayens uppdateringsintervall istället, säg 1-2 ggr/sek.
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Dilemmat är att om jag inte använder interrupt kanske jag missar pulser och om jag använder interrupt stör jag displayhanteringen. Kanske jag skulle dela ner pulsfrekvensen. Jag har en 4017 liggande så jag kan lätt dela med 10 och få intervallet 50-300 pulser per minut. Jag behöver inte läsa av temperaturerna oftare än med minutintervall och kanske behöver uppdatera displayen med några sekunders intervall.
Användarvisningsbild
PaNiC
Inlägg: 2565
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

Re: Arduino som övervakar båtmotorn

Inlägg av PaNiC »

Jo jag förstår det, men om man använder hårdvarucountern på sättet som jag beskrev så slipper man de problemen.
BjörnO
Inlägg: 242
Blev medlem: 3 juni 2013, 19:52:42

Re: Arduino som övervakar båtmotorn

Inlägg av BjörnO »

Att använda hårdvarucountern blir nog att ta sig vatten över huvudet för mig, får försöka på enklare sätt. Jag har några ideer:
1) att göra "allt" i interruptrutinen och på så sätt hindra interrupten att bryta in. Men det går nog inte utan neddelning av pulsfrekvensen eftersom jag i värsta fall bara har 20 ms på mig (med neddelning 200 ms).
2) att bara läsa av tiden i interruptrutinen och göra allt annat utanför. Hur går det då när interrupten kommer mitt i kommunikationen över i2c-bussen?
3) att stänga av interrupten när jag vill kommunicera med i2c. Då får jag ett ogiltigt värde när jag slår på interrupten igen, men det får jag i så fall filtrera bort.
Användarvisningsbild
PaNiC
Inlägg: 2565
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

Re: Arduino som övervakar båtmotorn

Inlägg av PaNiC »

Att göra allt i interruptrutinen är inte att rekommendera. Lustiga fenomen uppstår om interruptet triggar igen om den inte är färdig.
Det enda du bör göra i interruptrutinen är att öka en räknare, som du sedan använder för att räkna ut varvtalet.
I2C är ett synkront protokoll, så ingenting konstigt bör hända om du håller avbrottet inom rimlighetens gränser.
Skriv svar