Verbruiksmeter Injectie motor

Als U een gezamenlijk project wil starten of aan projecten van anderen mee wilt werken.
Berichten: 88
Geregistreerd: 16 Jul 2015, 21:02

Verbruiksmeter Injectie motor

Berichtdoor wim2584 » 26 Nov 2017, 19:13

Hallo,

ik ben een tijd geleden gestart met idee een verbruiksmeter te maken, ik kwam toen al snel uit bij het arduino MPGUINO project, op zich prima, maar voor aan/ inbouw op een motor niet zo handig om dat het LCD screen daar niet zo voor leent.

Heb toen het volgende gevonden (met LCD screen nokia) (zie onderaan)

al veel beter, maar afleesbaarheid is niet echt ok, toen het Idee gekregen om een Oled schermpje te gebruiken, prima, maar had devolgende problemen:
1- de verouderde .ino laat zich alleen met IDE 1.06 uploden
2- de library van het Oled is erg complex en gebruikt samen met de lange ino teveel geheugen
3- de MPGUINO.ino is voor mij veel te ingewikkeld, en dus leiden aanpassingen steeds tot teleurstelling

ben toen begonnen om alles veel eenvoudiger op te zetten:

volgens mij kan ik als ik:
- duty cycle en frequentie van de injector weet de hoeveelheid ingespoten benzine berekenen
- via snelheidmeter pulsen , de snelheid berekenen

hieruit dat L/100km en gem. L/100km berekenen en dan op een Oled zetten.

dus eigenlijk een "uitgeklede"MPguino , het gaat mij alleen om verbruik

Vraag: wie kan en wil daarbij helpen, ik ken (helaas) te slecht C+
cpp code
/*mpguino, open source fuel consumption system
GPL Software, mass production use rights reserved by opengauge.org, personal use is perfectly fine , no warranties expressed or implied

Special thanks to the good folks at ecomodder.com, ardunio.cc, avrfreaks.net, cadsoft.de, atmel.com,
and all the folks who donate their time and resources and share their experiences freely
changes made to work with a Nokia LC 5110, display of range, 3 types of history, automatic storage of values when you stop driving
changed approach for metric/imperial as nobody wants to switch once setup.(can use same routines for MPG and KM/L and speed only need routine for L/100 KM
just fill out different pulse values for Liter compared to Gallon and Km vs Miles, no conversion needed...

YOU SHOULD NOT USE MILLS(), MICROS() OR DELAY() FUNCTIONS DUE TO ENHANCED INTERUPT MANAGEMENT. USE MILLIS2 ,MICROSECONDS AND DELAY2 INSTEAD!

External connections:

PWM: 3, 5, 6, 9, 10, and 11. Provide 8-bit PWM output with the analogWrite() function

Vehicle interface pins
injector open D2 (int0)
injector closed D3 (int1)
speed C0 (pcint8) pin0


Buttons
left C3 (pcint11) pin3
middle C4 (pcint12) pin4
right C5 (pcint13) pin5

*/

/* Program overview (easier said than done)
set up digital pins to drive the lcd
set up pwm pins for lcd brightness and contrast
set up interrupts for the buttons, the speed signal, and the injector high/low signals.
set up tx pin for transmitting values over uart

create accumulators for speed/injector data

mainloop{
incorporate the accumulators into longer storage trips, reset accumulators
display computations, transmit accumulators
scan for key presses and perform their function (change screen,reset a trip,goto setup)
pause for remainder of 1/2 second

Nokia font size that can be selected (height, width)
setNormalFont()= normal,normal
setBigFont()= double,double
setTallFont() =double,normal
setWideFont() = normal,double

*/
#include <PCD8544.h>

// LCD Pins for LCD 5110
// pin 12 - Serial clock out (SCLK) =
// pin 11 - Serial data out (DIN)
// pin 10 - Data/Command select (D/C)
// pin 9 - LCD chip select (CS)
// pin 8 - LCD reset (RST)

PCD8544 nokia = PCD8544(12, 11, 10, 9, 8);

#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <string.h>
typedef uint8_t boolean;
typedef uint8_t byte;
#define RISING 3
#define FALLING 2


#define outhi(port,pin) PORT##port |= ( 1 << P##port##pin )
#define outlo(port,pin) PORT##port &= ~( 1 << P##port##pin )
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

//use with 16mhz, not tested
#define loopsPerSecond 1 // how many times will we try and loop in a second
#define cyclesperhour 3600
#define dispadj 1000
#define looptime 1000000ul/loopsPerSecond //1 per second
# define tempOffset 68 //for temperature measurement
String ThisVersion = "GL1800V22";
long contrast;
int t0;
int t1;
int brightness_loops;
#define usedefaults falsetrue // read stored value
void enableLButton();
void enableMButton();
void enableRButton();
void addEvent(byte eventID, unsigned int ms);
unsigned long microSeconds(void);
unsigned long elapsedMicroseconds(unsigned long startMicroSeconds, unsigned long currentMicroseconds);
unsigned long elapsedMicroseconds(unsigned long startMicroSeconds);
void processInjOpen(void);
void processInjClosed(void);
void enableVSS();
void setup(void);
void mainloop(void);
char* format(unsigned long num);
char * getStr(prog_char * str);
void doDisplayBig();
void doDisplayDetail();
void doDisplayHist1();
void doDisplayHist2();
void doDisplaySystemInfo(void);
void UpdateContrast(void);

// display 6 lines of info on LCD 5110
void displayTripCombo(char *lu1, char * lm1, unsigned long v1, char * lu2, char * lm2, unsigned long v2,
char * lu3, char * lm3, unsigned long v3, char * lu4, char * lm4, unsigned long v4, char * lu5, char * lm5, unsigned long v5, char * lu6, char * lm6, unsigned long v6);
void tDisplay(void * r);
unsigned long instantmph();
unsigned long instantmpg();
unsigned long instantgph();
void bigNum(unsigned long t, char * txt1, const char * txt2);
void init64(unsigned long an[], unsigned long bigPart,
unsigned long littlePart);
void shl64(unsigned long an[]);
void shr64(unsigned long an[]);
void add64(unsigned long an[], unsigned long ann[]);
void sub64(unsigned long an[], unsigned long ann[]);
boolean eq64(unsigned long an[], unsigned long ann[]);
boolean lt64(unsigned long an[], unsigned long ann[]);
void div64(unsigned long num[], unsigned long den[]);
void mul64(unsigned long an[], unsigned long ann[]);

void save();
byte load();
void eeprom_ul_read();
void eeprom_ul_write();
unsigned long store_value;

char * uformat(unsigned long val);
unsigned long rformat(char * val);
void editParm(byte parmIdx);
void initGuino();
unsigned long millis2();
void delay2(unsigned long ms);

int Storage_byte; // define where to start with storage, used in savetrip and loadtrip
int Temp;
//default "factory"values for GL1800
unsigned long distancefactor = 77309;
unsigned long injPulsesPer2Revolutions = 1;
unsigned long injectorSettleTime = 100;
unsigned long vsspause = 0; // 3 is default but for GL1800 0!
unsigned long injEdgeIdx = 0;
unsigned long parms[] = {
44003381ul, 25000ul, 1ul };//default "factory"values for GL1800 A3 Metric
char * parmLabels[] = {
"MicroSec/Liter", "Tank * 1000", "Km/L=1,L/100km=0 " };

byte brightness[] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22}; //middle button cycles through these settings. This is in fact the contrast setting for LCD 5110
#define brightnessLength (sizeof(brightness)/sizeof(byte)) //array size
byte OffsetIdx;

#define microSecondsPerGallonIdx 0
volatile unsigned long fuelfactor;
#define tankSizeIdx 1
#define metricIdx 2
#define parmsLength (sizeof(parms)/sizeof(unsigned long)) /* //array size */

#define nil 3999999999ul

#define guinosigold 0b10100101
#define guinosig 0b11100111

#define vssBit ( 1 << 0 )
#define rbuttonBit ( 1 << 3 ) //changed the buttons due to soldering layout
#define mbuttonBit ( 1 << 4 )
#define lbuttonBit ( 1 << 5 )
boolean brightness_pushed = false;

typedef void (* pFunc)(void);//type for display function pointers

volatile unsigned long timer2_overflow_count;

/*** Set up the Events ***
* We have our own ISR for timer2 which gets called about once a millisecond.
* So we define certain event functions that we can schedule by calling addEvent
* with the event ID and the number of milliseconds to wait before calling the event.
* The milliseconds is approximate.
*
* Keep the event functions SMALL!!! This is an interrupt!
*
*/
//event functions

void enableLButton() {
PCMSK1 |= (1 << PCINT13);//changed the buttons due to soldering layout
}
void enableMButton() {
PCMSK1 |= (1 << PCINT12);
}
void enableRButton() {
PCMSK1 |= (1 << PCINT11);
}
//array of the event functions
pFunc eventFuncs[] = {
enableVSS, enableLButton, enableMButton, enableRButton };
#define eventFuncSize (sizeof(eventFuncs)/sizeof(pFunc))
//define the event IDs
#define enableVSSID 0
#define enableLButtonID 3 //changed the buttons due to soldering layout
#define enableMButtonID 2
#define enableRButtonID 1
//ms counters
unsigned int eventFuncCounts[eventFuncSize];

//schedule an event to occur ms milliseconds from now
void addEvent(byte eventID, unsigned int ms) {
if (ms == 0)
eventFuncs[eventID]();
else
eventFuncCounts[eventID] = ms;
}

/* this ISR gets called every 1.024 milliseconds, we will call that a millisecond for our purposes
go through all the event counts,
if any are non zero subtract 1 and call the associated function if it just turned zero. */
ISR(TIMER2_OVF_vect)
{
timer2_overflow_count++;
for (byte eventID = 0; eventID < eventFuncSize; eventID++) {
if (eventFuncCounts[eventID] != 0) {
eventFuncCounts[eventID]--;
if (eventFuncCounts[eventID] == 0)
eventFuncs[eventID]();
}
}
}

unsigned long maxLoopLength = 0; //see if we are overutilizing the CPU

#define buttonsUp lbuttonBit + mbuttonBit + rbuttonBit // start with the buttons in the right state
byte buttonState = buttonsUp;

//overflow counter used by millis2()
unsigned long lastMicroSeconds = millis2() * 1000;
unsigned long microSeconds(void) {
unsigned long tmp_timer2_overflow_count;
unsigned long tmp;
byte tmp_tcnt2;
cli();
//disable interrupts
tmp_timer2_overflow_count = timer2_overflow_count;
tmp_tcnt2 = TCNT2;
sei();
// enable interrupts
tmp = ((tmp_timer2_overflow_count << 8) + tmp_tcnt2) * 4;
if ((tmp <= lastMicroSeconds) && (lastMicroSeconds < 4290560000ul))
return microSeconds();
lastMicroSeconds = tmp;
return tmp;
}

unsigned long elapsedMicroseconds(unsigned long startMicroSeconds,
unsigned long currentMicroseconds) {
if (currentMicroseconds >= startMicroSeconds)
return currentMicroseconds - startMicroSeconds;
return 4294967295 - (startMicroSeconds - currentMicroseconds);
}

unsigned long elapsedMicroseconds(unsigned long startMicroSeconds) {
return elapsedMicroseconds(startMicroSeconds, microSeconds());
}

//Trip prototype
class Trip {
public:
unsigned long loopCount; //how long has this trip been running
unsigned long injPulses; //can be used for GL1500 or any with fuel outlet measurement device giving pulses
unsigned long injHiSec;// seconds the injector has been open
unsigned long injHius;// microseconds, fractional part of the injectors open
unsigned long injIdleHiSec;// seconds the injector has been open
unsigned long injIdleHius;// microseconds, fractional part of the injectors open
unsigned long vssPulses;//from the speedo
unsigned long vssPulseLength; // only used by instant
//these functions actually return in thousandths,
unsigned long miles();
unsigned long gallons();
unsigned long lkm();
unsigned long mpg();
unsigned long mph();
unsigned long time(); //mmm.ss
unsigned long idleGallons(); //how much volume spent at 0 mph?
void update(Trip t);
void reset();
void SaveTrip(int Storage_byte);
void LoadTrip(int Storage_byte);
Trip();
};

//main objects we will be working with:
unsigned long injHiStart; //for timing injector pulses
Trip tmpTrip;
Trip instant; // actual information
Trip current; // short trip, within 1 tank
Trip tank; // current trip info per full tank
Trip tank1; // previous trip info after tank reset


unsigned volatile long instInjStart = nil;
unsigned volatile long tmpInstInjStart = nil;
unsigned volatile long instInjEnd;
unsigned volatile long tmpInstInjEnd;
unsigned volatile long instInjTot;
unsigned volatile long tmpInstInjTot;
unsigned volatile long instInjCount;
unsigned volatile long tmpInstInjCount;

volatile static pFunc int0Func;
ISR(INT0_vect)
{ //processInjOpen by default
int0Func();
}

volatile static pFunc int1Func;
ISR(INT1_vect)
{//processInjClosed
int1Func();
}

void processInjOpen(void) {
injHiStart = microSeconds();
}

void processInjClosed(void) {
long t = microSeconds();
long x = elapsedMicroseconds(injHiStart, t) - injectorSettleTime;
if (x > 0)
tmpTrip.injHius += x;
tmpTrip.injPulses++;

if (tmpInstInjStart != nil) {
if (x > 0)
tmpInstInjTot += x;
tmpInstInjCount++;
}
else {
tmpInstInjStart = t;
}

tmpInstInjEnd = t;
}

volatile boolean vssFlop = 0;

void enableVSS() {
// tmpTrip.vssPulses++;
vssFlop = !vssFlop;
}

unsigned volatile long lastVSS1;
unsigned volatile long lastVSSTime;
unsigned volatile long lastVSS2;

volatile boolean lastVssFlop = vssFlop;

//attach the vss/buttons interrupt
ISR( PCINT1_vect )
{
static byte vsspinstate = 0;
byte p = PINC;//bypassing digitalRead for interrupt performance
if ((p & vssBit) != (vsspinstate & vssBit)) {
addEvent(enableVSSID, vsspause); //check back in a couple milli
}
if (lastVssFlop != vssFlop) {
lastVSS1 = lastVSS2;
unsigned long t = microSeconds();
lastVSS2 = elapsedMicroseconds(lastVSSTime, t);
lastVSSTime = t;
tmpTrip.vssPulses++;
tmpTrip.vssPulseLength += lastVSS2;
lastVssFlop = vssFlop;
}
vsspinstate = p;
buttonState &= p;
}

pFunc displayFuncs[] = {
doDisplayBig, doDisplayDetail, doDisplayHist1, doDisplayHist2, doDisplaySystemInfo, };

#define displayFuncSize (sizeof(displayFuncs)/sizeof(pFunc)) //array size
prog_char * displayFuncNames[displayFuncSize];
byte newRun = 0;
void setup(void) {
//Serial.begin(9600); // setup serial for debug only
newRun = load();//load the default parameters
byte x = 0;
nokia.setNormalFont();
displayFuncNames[x++] = PSTR("INSTANT BIG");// 1
displayFuncNames[x++] = PSTR("INSTANT DETAIL");// 2
displayFuncNames[x++] = PSTR("HIST1 ");//3
displayFuncNames[x++] = PSTR("HIST2 ");//4
displayFuncNames[x++] = PSTR("CHECK");//5

DDRB = (1 << DDB5) | (1 << DDB4) | (1 << DDB1) | (1 << DDB0);
DDRD = (1 << DDD7) | (1 << DDD6) | (1 << DDD5) | (1 << DDD4);

delay2(500);
contrast = (GetTemp() * -.12 + 50);
nokia.init();
UpdateContrast();
nokia.clear();

int0Func = processInjOpen;
int1Func = processInjClosed;

//set up the external interrupts
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01)))
| ((parms[injEdgeIdx] == 1 ? RISING : FALLING) << ISC00);
EIMSK |= (1 << INT0);
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11)))
| ((parms[injEdgeIdx] == 1 ? FALLING : RISING) << ISC10);
EIMSK |= (1 << INT1);

PORTC |= (1 << 5) | (1 << 4) | (1 << 3); //button pullup resistors

fuelfactor = parms[microSecondsPerGallonIdx];
OffsetIdx = eeprom_read_byte((unsigned char *) 2); // brightnessIdx

//low level interrupt enable stuff
PCMSK1 |= (1 << PCINT8);
enableLButton();
enableMButton();
enableRButton();
PCICR |= (1 << PCIE1);
delay2(1500);
}

byte screen = 0;
byte holdDisplay = 0;
// ************************************************** here the fun begins ***************************************************************************************
void mainloop(void) {
if (newRun != 1)
initGuino();//go through the initialization screen
// unsigned long lastActivity = microSeconds();
// unsigned long tankHold; //state at point of last activity
boolean stored = false;
boolean hasrun = false; // check for first started engine after power has been applied
current.LoadTrip(1); // keep current as history data until reset
tank.LoadTrip(2); // start with loading saved data from tankinfo
tank1.LoadTrip(3); // overall history
while (true) {
unsigned long loopStart = microSeconds();
instant.reset(); //clear instant
cli();
instant.update(tmpTrip); //"copy" of tmpTrip in instant now
tmpTrip.reset(); //reset tmpTrip first so we don't lose too many interrupts
instInjStart = tmpInstInjStart;
instInjEnd = tmpInstInjEnd;
instInjTot = tmpInstInjTot;
instInjCount = tmpInstInjCount;

tmpInstInjStart = nil;
tmpInstInjEnd = nil;
tmpInstInjTot = 0;
tmpInstInjCount = 0;

sei();
UpdateContrast();
// Serial.print("LoopCount: ");
// Serial.println(current.loopCount); // debug value
// Serial.print("Temp: ");
// Serial.println(GetTemp());
// Serial.print("Contrast ");
// Serial.println(contrast+brightness[OffsetIdx]);
// Serial.print("ArrayLength ");
// Serial.println(brightnessLength);
// Serial.print("T0: ");
// Serial.println(t0);
// Serial.print("T1: ");
// Serial.println(t1);
// Serial.println(screen);


current.update(instant); //use instant to update current
tank.update(instant); //use instant to update tank history
tank1.update(instant); // use instant to update tank1 (long term history)

if (brightness_pushed && (current.loopCount - brightness_loops > 10)) // more than x loops (seconds) the brightness button not pressed will store the default for future use.
{
brightness_pushed = false;
eeprom_write_byte((unsigned char *) 2 ,OffsetIdx);
}

if (instant.injPulses != 0 && instant.vssPulses >= 10)// check if motor is running and we move
{
hasrun = true;
stored = false;
}
if (instant.vssPulses < 10 && holdDisplay == 0) // save when you are nearly stopping or stopped by kill switch)
{
if (stored == false && hasrun == true)// only save when at least moved once and engine was running
{
current.SaveTrip(1);
tank.SaveTrip(2);
tank1.SaveTrip(3);
stored = true;
hasrun = false; // reset so we can test again if we moved
}

}

//keep track of how long the loops take before we go int waiting.
unsigned long loopX = elapsedMicroseconds(loopStart);
if (loopX > maxLoopLength)
maxLoopLength = loopX;

while (elapsedMicroseconds(loopStart) < (looptime))
checkbuttons()
;//wait for the end of a second to arrive
}

}

void checkbuttons(void) {
if (holdDisplay == 0) {
displayFuncs[screen](); //call the appropriate display routine
nokia.setCursor(0, 0);

//see if any buttons were pressed, display a brief message if so
if (!(buttonState & lbuttonBit) && !(buttonState & rbuttonBit)) {// left and right = initialize
nokia.print(getStr(PSTR("Setup ")));
initGuino();
}
else if (!(buttonState & lbuttonBit) && !(buttonState
&mbuttonBit)) {// left and middle = tank reset
selectReset();
}
else if (!(buttonState & mbuttonBit) && !(buttonState
&rbuttonBit)) {// right and middle = current reset
selectReset();
}
else if (!(buttonState & lbuttonBit)) { //left is rotate through screeens to the left
if (screen != 0)
screen = (screen - 1);
else
screen = displayFuncSize - 1;
nokia.clear();
nokia.print(getStr(displayFuncNames[screen]));
}
else if (!(buttonState & mbuttonBit)) { //middle is cycle through brightness settings
OffsetIdx ++;
brightness_pushed = true;
brightness_loops = current.loopCount;
if(OffsetIdx > brightnessLength) {
OffsetIdx = 0;
}
UpdateContrast();
nokia.print("Contrast ");
nokia.print (contrast+brightness[OffsetIdx]);
nokia.display();
}
else if (!(buttonState & rbuttonBit)) {//right is rotate through screeens to the right
screen = (screen + 1) % displayFuncSize;
nokia.clear();
nokia.print(getStr(displayFuncNames[screen]));
}
if (buttonState != buttonsUp)
holdDisplay = 1;
}
else {
holdDisplay = 0;
}
buttonState = buttonsUp;//reset the buttons
nokia.display();
}


char fBuff[7];//used by format
// normal font for 6 lines display
void dispv(char * usl, char * ml, unsigned long num) {
nokia.print(parms[metricIdx]==1?ml:usl);
nokia.print(format(num));
}
// Big font for 3 line display
void displ(char * usl, char * ml, unsigned long num) {
nokia.setBigFont();
nokia.print(format(num));
nokia.setNormalFont();
nokia.print(parms[metricIdx]==1?ml:usl);
}

void UpdateContrast(){
//contrast=map(GetTemp(),-30,50,60,30);
contrast = (GetTemp() * -.12 + 50);
// Serial.println(contrast+brightness[OffsetIdx]);
nokia.setContrast(contrast + brightness[OffsetIdx]);
}


char* format(unsigned long num) {
byte dp = 3;

while (num > 999999) {
num /= 10;
dp++;
if (dp == 5)
break; // We'll lose the top numbers like an odometer
}
if (dp == 5)
dp = 99; // We don't need a decimal point here.

// Round off the non-printed value.
if ((num % 10) > 4)
num += 10;
num /= 10;
byte x = 6;
while (x > 0) {
x--;
if (x == dp) { //time to poke in the decimal point?{
fBuff[x] = '.';
}
else {
fBuff[x] = '0' + (num % 10);//poke the ascii character for the digit.
num /= 10;
}
}
fBuff[6] = 0;
return fBuff;
}


//get a string from flash
char mBuff[17];//used by getStr
char * getStr(prog_char * str) {
strcpy_P(mBuff, str);
return mBuff;
}

void doDisplayBig() {

if (instant.vssPulses == 0 && instant.injPulses != 0){// usage per hour
displayBigTripCombo("GH","LH", instantgph(), "AV", "AV", current.mpg(), "RG","RG", DistanceLeft());
}
if (instant.vssPulses != 0 && instant.injPulses != 0){// usage per distance {
if (parms[metricIdx]==1)
displayBigTripCombo("DV","DV", instantmpg(), "AV", "AV", current.mpg(), "RG","RG", DistanceLeft());
else
displayBigTripCombo("VD","VD", instantlkm(), "AV", "AV", current.mpg(), "RG","RG", DistanceLeft());
}
if (instant.vssPulses == 0 && instant.injPulses == 0){// Volume used and distance {
displayBigTripCombo("VU","VU", tank.gallons(), "DI", "DI", tank.miles(), "RG","RG", DistanceLeft());
}
}


void doDisplayDetail() {
if (instant.vssPulses == 0){// Idle consumption
displayTripCombo("IDLE : ","IDLE : ", current.idleGallons(), "DIST: ", "DIST: ", current.miles(), "GpH : ","L/uur: ",
instantgph(), "AVG1 : ","AVG1 : ", current.mpg(),"USED: ","USED: ", current.gallons(),"RANGE :", "RANGE :", DistanceLeft());
}
else {//consumption by distance
displayTripCombo("MPG : ","Km/L : ", instantmpg(), "DIST: ", "DIST: ", current.miles(), "GpH : ","L/uur: ",
instantgph(), "AVG : ","AVG : ", current.mpg(),"USED: ","USED: ", current.gallons(),"RANGE :", "RANGE :", DistanceLeft());
}
}

void doDisplayHist1() {
displayTripCombo("AVG1 : ","AVG1 : ", tank.mpg(), "IDLE1: ","IDLE1: ", tank.idleGallons(),"Km/h1: ","Km/h1: ", tank.mph(), "DIST1: ", "DIST1: ", tank.miles(), "USED1: ","USED1: ", tank.gallons(), "MiLeft:", "KmLeft:", DistanceLeft());
}

void doDisplayHist2() {
displayTripCombo("AVG2 : ","AVG2 : ", tank1.mpg(), "IDLE2: ","IDLE2: ", tank1.idleGallons(),"Km/h2: ","Km/h2: ", tank1.mph(), "DIST2: ", "DIST2: ", tank1.miles(), "USED2: ","USED2: ", tank1.gallons(),"MiLeft:", "KmLeft:", DistanceLeft());
}


void displayTripCombo(char *lu1, char * lm1, unsigned long v1, char * lu2, char * lm2, unsigned long v2,
char * lu3, char * lm3, unsigned long v3, char * lu4, char * lm4, unsigned long v4, char * lu5, char * lm5, unsigned long v5, char * lu6, char * lm6, unsigned long v6) {
nokia.setCursor(0,0);
dispv(lu1, lm1, v1);
nokia.println();
dispv(lu2, lm2, v2);
nokia.println();
dispv(lu3, lm3, v3);
nokia.println();
dispv(lu4, lm4, v4);
nokia.println();
dispv(lu5, lm5, v5);
nokia.println();
dispv(lu6, lm6, v6);
nokia.println();
nokia.display();
}

void displayBigTripCombo(char *lu1, char * lm1, unsigned long v1, char * lu2, char * lm2, unsigned long v2,
char * lu3, char * lm3, unsigned long v3) {
nokia.setCursor(0,0);
displ(lu1, lm1, v1);
nokia.println();
displ(lu2, lm2, v2);
nokia.println();
displ(lu3, lm3, v3);
nokia.println();
nokia.display();
}

void doDisplaySystemInfo(void) {
nokia.setTallFont();
nokia.setCursor(0,0);
nokia.print("Ver: ");
nokia.print(ThisVersion);
nokia.setCursor(0,16);
nokia.print("TEMP: ");
nokia.print(GetTemp());
nokia.setCursor(0,32);
nokia.print("Loops ");
nokia.print(current.loopCount);
nokia.display();
nokia.setNormalFont();

} //display max cpu utilization


Trip::Trip() {
}

//for display computing
unsigned long tmp1[2];
unsigned long tmp2[2];
unsigned long tmp3[2];

unsigned long instantmph() {
unsigned long vssPulseTimeuS = instant.vssPulseLength / instant.vssPulses;
init64(tmp1, 0, 1000000000ul);
init64(tmp2, 0, distancefactor);
div64(tmp1, tmp2);
init64(tmp2, 0, cyclesperhour);
mul64(tmp1, tmp2);
init64(tmp2, 0, vssPulseTimeuS);
div64(tmp1, tmp2);
return tmp1[1];
}

unsigned long instantlkm() {
unsigned long imph = instantmph();
unsigned long igph = instantgph();
if (igph == 0)
return 0;
if (imph == 0)
return 999999000;
init64(tmp1, 0, 100000ul);
init64(tmp2, 0, igph);
mul64(tmp2, tmp1);
init64(tmp1, 0, imph);
div64(tmp2,tmp1);
return tmp2[1];
}

unsigned long instantmpg() {
// if(parms[metricIdx]==1)
// return instantlkm();
unsigned long imph = instantmph();
unsigned long igph = instantgph();
if (imph == 0)
return 0;
if (igph == 0)
return 999999000;
init64(tmp1, 0, 1000ul);
init64(tmp2, 0, imph);
mul64(tmp1, tmp2);
init64(tmp2, 0, igph);
div64(tmp1,tmp2);
return tmp1[1];

}

unsigned long DistanceLeft() {
// unsigned long temp = (parms[tankSizeIdx] - tank.gallons()) * current.mpg(); // don't get too optimistic and use historical usage.
unsigned long temp1 = tank.gallons();
unsigned long temp2 = current.mpg();
// unsigned long temp3 = instant.mpg();
if (temp1 > parms[tankSizeIdx])
return 0;
init64(tmp1, 0, parms[tankSizeIdx]);
init64(tmp2, 0, temp1);
sub64(tmp1, tmp2);
init64(tmp2, 0, temp2);
mul64(tmp1, tmp2);
init64(tmp2, 0, 1000ul);
div64(tmp1, tmp2);
return tmp1[1];
}

unsigned long instantgph() {
init64(tmp1, 0, instInjTot);
init64(tmp2, 0, 3600000000ul);
mul64(tmp1, tmp2);
init64(tmp2, 0, 1000ul);
mul64(tmp1, tmp2);
init64(tmp2, 0, fuelfactor);
div64(tmp1, tmp2);
init64(tmp2, 0, instInjEnd - instInjStart);
div64(tmp1, tmp2);
return tmp1[1];
}

unsigned long instantrpm(){
init64(tmp1,0,instInjCount);
init64(tmp2,0,120000000ul);// 2 revs = 120 seconds
mul64(tmp1,tmp2);
init64(tmp2,0,1000ul);
mul64(tmp1,tmp2);
init64(tmp2,0,injPulsesPer2Revolutions);
div64(tmp1,tmp2);
init64(tmp2,0,instInjEnd-instInjStart);
div64(tmp1,tmp2);
return tmp1[1];
}


unsigned long instInjOpen()//get the average time the injector is opened
{
init64(tmp1,0,instInjEnd-instInjStart);
init64(tmp2,0,1000ul);
mul64(tmp1,tmp2);
init64(tmp2,0,instInjCount);
div64(tmp1,tmp2);
return tmp1[1];
}

unsigned long Trip::miles() {
init64(tmp1, 0, vssPulses);
init64(tmp2, 0, 1000);
mul64(tmp1, tmp2);
init64(tmp2, 0, distancefactor);
div64(tmp1, tmp2);
return tmp1[1];
}

unsigned long Trip::mph() {
if (loopCount == 0)
return 0;
init64(tmp1, 0, loopsPerSecond);
init64(tmp2, 0, vssPulses);
mul64(tmp1, tmp2);
init64(tmp2, 0, 3600000ul);
mul64(tmp1, tmp2);
init64(tmp2, 0, distancefactor);
div64(tmp1, tmp2);
init64(tmp2, 0, loopCount);
div64(tmp1, tmp2);
return tmp1[1];
}

unsigned long Trip::gallons() {
init64(tmp1, 0, injHiSec);
init64(tmp2, 0, 1000000);
mul64(tmp1, tmp2);
init64(tmp2, 0, injHius);
add64(tmp1, tmp2);
init64(tmp2, 0, dispadj);
mul64(tmp1, tmp2);
init64(tmp2, 0, fuelfactor);
div64(tmp1, tmp2);
return tmp1[1];
}

unsigned long Trip::idleGallons() {
init64(tmp1, 0, injIdleHiSec);
init64(tmp2, 0, 1000000);
mul64(tmp1, tmp2);
init64(tmp2, 0, injIdleHius);
add64(tmp1, tmp2);
init64(tmp2, 0, dispadj);
mul64(tmp1, tmp2);
init64(tmp2, 0, fuelfactor);
div64(tmp1, tmp2);
return tmp1[1];
}

unsigned long Trip::lkm() {
if (injPulses == 0)
return 0;
if (vssPulses == 0)
return 999999000; //who doesn't like to see 999999? :)
init64(tmp1, 0, injHiSec);
init64(tmp3, 0, 1000000ul);
mul64(tmp3, tmp1);
init64(tmp1, 0, injHius);
add64(tmp3, tmp1);
init64(tmp1, 0, distancefactor);
mul64(tmp3, tmp1);
init64(tmp1, 0, 80000ul);
mul64(tmp3, tmp1);
init64(tmp1, 0, fuelfactor);
init64(tmp2, 0, vssPulses);
mul64(tmp1, tmp2);
div64(tmp3, tmp1);
return tmp3[1];
}

unsigned long Trip::mpg() {
// if(parms[metricIdx]==1)
// return lkm();
if (vssPulses == 0)
return 0;
// if (injPulses == 0)
// return 999999000; //who doesn't like to see 999999? :)

init64(tmp1, 0, injHiSec);
init64(tmp3, 0, 1000000);
mul64(tmp3, tmp1);
init64(tmp1, 0, injHius);
add64(tmp3, tmp1);
init64(tmp1, 0, distancefactor);
mul64(tmp3, tmp1);

init64(tmp1, 0, fuelfactor);
init64(tmp2, 0, dispadj);
mul64(tmp1, tmp2);
init64(tmp2, 0, vssPulses);
mul64(tmp1, tmp2);

div64(tmp1, tmp3);
return tmp1[1];
}


//return the seconds as a time mmm.ss, eventually hhh:mm too
unsigned long Trip::time() {
// return seconds*1000;
byte d = 60;
unsigned long seconds = loopCount / loopsPerSecond;
// if(seconds/60 > 999) d = 3600; //scale up to hours.minutes if we get past 999 minutes
return ((seconds / d) * 1000) + ((seconds % d) * 10);

}

void Trip::reset() {
loopCount = 0;
injPulses = 0;
injHius = 0;
injHiSec = 0;
vssPulses = 0;
vssPulseLength = 0;
injIdleHiSec = 0;
injIdleHius = 0;
}

void Trip::SaveTrip(int Storage_byte) {
nokia.clear();
nokia.print("saving data");
Temp = (Storage_byte * 16) + 44; // complete storage = 4*4 = 16 bytes, should start at byte 60 for storage_byte = 1
eeprom_ul_write(loopCount, Temp); //total loops
Temp = (Storage_byte * 16) + 48;
eeprom_ul_write(vssPulses, Temp); //distance
Temp = (Storage_byte * 16) + 52;
eeprom_ul_write(injHiSec, Temp); // Total injector open time
Temp = (Storage_byte * 16) + 56;
eeprom_ul_write(injIdleHiSec, Temp); // Idle Speed = 0, engine running
nokia.display();
nokia.clear();
}

void Trip::LoadTrip(int Storage_byte) {
nokia.clear();
nokia.print("loading data");
Temp = (Storage_byte * 16) + 44; // complete storage = 24 bytes, should start at byte 60 for storage_byte = 1, 2 should start at 88.
loopCount = (eeprom_ul_read(Temp)); //total loops
Temp = (Storage_byte * 16) + 48;
vssPulses = (eeprom_ul_read(Temp)); //distance
Temp = (Storage_byte * 16) + 52;
injHiSec = (eeprom_ul_read(Temp)); // Total injector open time
Temp = (Storage_byte * 16) + 56;
injIdleHiSec = (eeprom_ul_read(Temp)); // Speed = 0, engine running
nokia.display();
nokia.clear();
}

void Trip::update(Trip t) {
loopCount++; //we call update once per loop
vssPulses += t.vssPulses;
vssPulseLength += t.vssPulseLength;

if (t.injPulses > 2 && t.injHius < 500000) {//chasing ghosts
injPulses += t.injPulses;
injHius += t.injHius;
if (injHius >= 1000000) { //rollover into the injHiSec counter
injHiSec++;
injHius -= 1000000;
}
if (t.vssPulses == 0) { //track volume spent standing still

injIdleHius += t.injHius;
if (injIdleHius >= 1000000) { //r
injIdleHiSec++;
injIdleHius -= 1000000;
}
}
}
}

double GetTemp(void)
{
// long int wADC;
double t;

// The internal temperature has to be used
// with the internal reference of 1.1V.
// Channel 8 can not be selected with
// the analogRead function yet.

// Set the internal reference and mux.
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
ADCSRA |= _BV(ADEN); // enable the ADC

delay2(20); // wait for voltages to become stable.

ADCSRA |= _BV(ADSC); // Start the ADC

// Detect end-of-conversion
while (bit_is_set(ADCSRA,ADSC));
t0 = ADCL;
t1 = ADCH; //apparently you need to read ADCH too to get results in t0
// Reading register "ADCW" takes care of how to read ADCL and ADCH.
// The offset of 324.31 could be wrong. It is just an indication.
// t = (ADCW - tempOffset ) / 1.22; this didn't work below zero! Now reading ADCL only
t = (t0 - tempOffset) * 0.82;

// The returned temperature is in degrees Celcius.
return (t);
}

//the standard 64 bit math brings in 5000+ bytes
//these brings in 1214 bytes, and everything is passed by reference
unsigned long zero64[] = {
0, 0 };

void init64(unsigned long an[], unsigned long bigPart, unsigned long littlePart) {
an[0] = bigPart;
an[1] = littlePart;
}

//left shift 64 bit "number"
void shl64(unsigned long an[]) {
an[0] <<= 1;
if (an[1] & 0x80000000)
an[0]++;
an[1] <<= 1;
}

//right shift 64 bit "number"
void shr64(unsigned long an[]) {
an[1] >>= 1;
if (an[0] & 0x1)
an[1] += 0x80000000;
an[0] >>= 1;
}

//add ann to an
void add64(unsigned long an[], unsigned long ann[]) {
an[0] += ann[0];
if (an[1] + ann[1] < ann[1])
an[0]++;
an[1] += ann[1];
}

//subtract ann from an
void sub64(unsigned long an[], unsigned long ann[]) {
an[0] -= ann[0];
if (an[1] < ann[1]) {
an[0]--;
}
an[1] -= ann[1];
}

//true if an == ann
boolean eq64(unsigned long an[], unsigned long ann[]) {
return (an[0] == ann[0]) && (an[1] == ann[1]);
}

//true if an < ann
boolean lt64(unsigned long an[], unsigned long ann[]) {
if (an[0] > ann[0])
return false;
return (an[0] < ann[0]) || (an[1] < ann[1]);
}

//divide num by den
void div64(unsigned long num[], unsigned long den[]) {
unsigned long quot[2];
unsigned long qbit[2];
unsigned long tmp[2];
init64(quot, 0, 0);
init64(qbit, 0, 1);

if (eq64(num, zero64)) { //numerator 0, call it 0
init64(num, 0, 0);
return;
}

if (eq64(den, zero64)) { //numerator not zero, denominator 0, infinity in my book.
init64(num, 0xffffffff, 0xffffffff);
return;
}

init64(tmp, 0x80000000, 0);
while (lt64(den, tmp)) {
shl64(den);
shl64(qbit);
}

while (!eq64(qbit, zero64)) {
if (lt64(den, num) || eq64(den, num)) {
sub64(num, den);
add64(quot, qbit);
}
shr64(den);
shr64(qbit);
}

//remainder now in num, but using it to return quotient for now
init64(num, quot[0], quot[1]);
}

//multiply num by den
void mul64(unsigned long an[], unsigned long ann[]) {
unsigned long p[2] = {
0, 0 };
unsigned long y[2] = {
ann[0], ann[1] };
while (!eq64(y, zero64)) {
if (y[1] & 1)
add64(p, an);
shl64(an);
shr64(y);
}
init64(an, p[0], p[1]);
}

void save() {
eeprom_write_byte((unsigned char *) 0, guinosig);
eeprom_write_byte((unsigned char *) 1, parmsLength);
eeprom_write_byte((unsigned char *) 2 ,OffsetIdx);
byte p = 0;
for (int x = 4; p < parmsLength; x += 4) {
unsigned long v = parms[p];
eeprom_write_byte((unsigned char *) x, (v >> 24) & 255);
eeprom_write_byte((unsigned char *) x + 1, (v >> 16) & 255);
eeprom_write_byte((unsigned char *) x + 2, (v >> 8) & 255);
eeprom_write_byte((unsigned char *) x + 3, (v) & 255);
p++;
}
}

byte load() { //return 1 if loaded ok
#ifdef usedefaults
OffsetIdx = eeprom_read_byte((unsigned char *) 2); // brightnessIdx
//screen = eeprom_read_byte((unsigned char *) 3); // last screen stored
return 1;
#endif
byte b = eeprom_read_byte((unsigned char *) 0);
byte c = eeprom_read_byte((unsigned char *) 1);
OffsetIdx = eeprom_read_byte((unsigned char *) 2); // brightnessIdx
//screen = eeprom_read_byte((unsigned char *) 3); // last screen stored
if (b == guinosigold)
c = 9; //before fancy parameter counter

if (b == guinosig || b == guinosigold) {
byte p = 0;

for (int x = 4; p < c; x += 4) {
unsigned long v = eeprom_read_byte((unsigned char *) x);
v = (v << 8) + eeprom_read_byte((unsigned char *) x + 1);
v = (v << 8) + eeprom_read_byte((unsigned char *) x + 2);
v = (v << 8) + eeprom_read_byte((unsigned char *) x + 3);
parms[p] = v;
p++;
}
return 1;
}
return 0;
}


unsigned long eeprom_ul_write (unsigned long store_value,int start)
{
unsigned long v = store_value;
eeprom_write_byte((unsigned char *) start , (v >> 24) & 255);
eeprom_write_byte((unsigned char *) start + 1, (v >> 16) & 255);
eeprom_write_byte((unsigned char *) start + 2, (v >> 8) & 255);
eeprom_write_byte((unsigned char *) start + 3, (v) & 255);
return 0;
}

unsigned long eeprom_ul_read (int start)
{
unsigned long v = eeprom_read_byte((unsigned char *) start);
v = (v << 8) + eeprom_read_byte((unsigned char *) start + 1);
v = (v << 8) + eeprom_read_byte((unsigned char *) start + 2);
v = (v << 8) + eeprom_read_byte((unsigned char *) start + 3);
store_value = v;
return store_value;
}


unsigned long eeprom_1byte_write (byte store_value,int start) //to be used for initial bytes e.g. brightness setting, screen when stopped etc. use the high part of memory to avoid conflict with other storage.
{
byte v = store_value;
eeprom_write_byte((unsigned char *) start , v );
return 0;
}

unsigned long eeprom_1byte_read (int start)
{
byte v = eeprom_read_byte((unsigned char *) start);
store_value = v;
return store_value;
}



char * uformat(unsigned long val) {
unsigned long d = 1000000000ul;
for (byte p = 0; p < 10; p++) {
mBuff[p] = '0' + (val / d);
val = val - (val / d * d);
d /= 10;
}
mBuff[10] = 0;
return mBuff;
}

unsigned long rformat(char * val) {
unsigned long d = 1000000000ul;
unsigned long v = 0ul;
for (byte p = 0; p < 10; p++) {
v = v + (d * (val[p] - '0'));
d /= 10;
}
return v;
}


void selectReset(){ // when left and middle button are pressed in the screen you are looking at, a reset of this will be done
switch (screen){
nokia.setCursor(0, 0);
nokia.setNormalFont();
case 0:
current.reset();
tank.reset();
current.SaveTrip(1);
nokia.print("Reset tank ");
break;
case 1:
current.reset();
current.SaveTrip(1);
tank.reset();
nokia.print("Reset tank ");
break;
case 2:
tank.reset();
tank.SaveTrip(2);
nokia.print("Reset Hist1 ");
break;
case 3:
tank1.reset();
tank1.SaveTrip(3);
nokia.print("Reset Hist2 ");
break;
nokia.display();
delay2(1000);
}
}


void editParm(byte parmIdx) {
unsigned long v = parms[parmIdx];
byte p = 9; //right end of 10 digit number 0..9
nokia.clear(); //clear the screen
nokia.setCursor(0, 0);
nokia.print(parmLabels[parmIdx]);
nokia.setCursor(0, 8);// second line of screen
char * fmtv = uformat(v);
nokia.print(fmtv);
nokia.print(" OK");
nokia.display();

for (int x = 9; x >= 0; x--) { //do a nice thing and put the cursor at the first non zero number
if (fmtv[x] != '0')
p = x;
}
nokia.setCursor(0,16);
nokia.print(" ");
nokia.setCursor(p*6,16);
nokia.print("^"); //indicator where we are
nokia.setCursor(p*6,8);
nokia.display();

byte keyLock = 1;
while (true) {

if (p < 10)
nokia.setCursor(p*6, 8);
if (p == 10)
nokia.setCursor(12*6, 8);

if (keyLock == 0) {
if (!(buttonState & lbuttonBit) && !(buttonState & rbuttonBit)) {// left & right
return;
}
else if (!(buttonState & lbuttonBit)) {// left
p = p - 1;
if (p == 255)
p = 10;

nokia.setCursor(0,16);
nokia.print(" ");
nokia.setCursor(p*6,16);
if (p == 10) // OK
nokia.setCursor((12*6)-3, 16);
nokia.print("^"); //indicator where we are
nokia.setCursor(p*6,8);
nokia.display();
}
else if (!(buttonState & rbuttonBit)) {// right

p = p + 1;
if (p == 11)
p = 0;
nokia.setCursor(0,16);
nokia.print(" ");
nokia.setCursor(p*6,16);
if (p == 10) // OK
nokia.setCursor((12*6)-3, 16);
nokia.print("^"); //indicator where we are
nokia.setCursor(p*6,8);
nokia.display();

}
else if (!(buttonState & mbuttonBit)) {// middle
if (p == 11) { //cancel selected
return;
}
if (p == 10) { //ok selected
parms[parmIdx] = rformat(fmtv);
return;
}

byte n = fmtv[p] - '0';

n++;
if (n > 9)
n = 0;
if (p == 0 && n > 3)
n = 0;
fmtv[p] = '0' + n;
nokia.setCursor(0, 8);
nokia.print(fmtv);
nokia.display();

}

if (buttonState != buttonsUp)
keyLock = 1;
}
else {
keyLock = 0;
}
buttonState = buttonsUp;
delay2(125);
}
nokia.clear();
}

void initGuino() { //edit all the parameters
for (int x = 0; x < parmsLength; x++)
editParm(x);
save();

int0Func = processInjOpen;
int1Func = processInjClosed;
EIMSK &= ~(1 << INT0);
EIMSK &= ~(1 << INT1);

EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01)))
| ((parms[injEdgeIdx] == 1 ? RISING : FALLING) << ISC00);
EIMSK |= (1 << INT0);
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11)))
| ((parms[injEdgeIdx] == 1 ? FALLING : RISING) << ISC10);
EIMSK |= (1 << INT1);

fuelfactor = parms[microSecondsPerGallonIdx];
// if (parms[metricIdx] == 1){ // not needed as we are going to define the pulses per distance/volume direct in the parameters. Metric will only show Km or Liter instead of Miles and gallons.
// distancefactor /= 1.609;
// fuelfactor /= 3.785;
// }

holdDisplay = 1;
}

unsigned long millis2() {
return timer2_overflow_count * 64UL * 2 / (16000000UL / 128000UL);
}

void delay2(unsigned long ms) {
unsigned long start = millis2();
while (millis2() - start < ms)
;
}

int main(void) {
sei();
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
sbi(TIMSK0, TOIE0);

// set timer 1 prescale factor to 64
sbi(TCCR1B, CS11);
sbi(TCCR1B, CS10);
// put timer 1 in 8-bit phase correct pwm mode
sbi(TCCR1A, WGM10);
// set timer 2 prescale factor to 64
sbi(TCCR2B, CS22);
// configure timer 2 for phase correct pwm (8-bit)
sbi(TCCR2A, WGM20);

// set a2d prescale factor to 128
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);

// enable a2d conversions
sbi(ADCSRA, ADEN);

UCSR0B = 0;

sei();

timer2_overflow_count = 0;

TCCR2A = 1 << WGM20 | 1 << WGM21;
// set timer 2 prescale factor to 64
TCCR2B = 1 << CS22;
TIMSK2 |= 1 << TOIE2;
TIMSK0 &= !(1 << TOIE0);

setup();
mainloop();

return 0;
}

Advertisement

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Verbruiksmeter Injectie motor

Berichtdoor Koepel » 26 Nov 2017, 19:39

Dit is geen Arduino board en de code loopt jaren achter.

De code bestaat voor een groot deel uit code om met 64-bit integer te rekenen. Ik vraag me af of dat wel nodig is.
Ik zag verder geen fouten die opvielen, dus dat valt mee.

Het is lastig om je iets te adviseren.
Ik weet niet eens welke microcontroller je hebt, wat het schema is van de MPGUINO, welke PCD8544 library je gebruikt, welke OLED library je wilt gebruiken, enzovoorts.

Dit project is zeer specifiek voor een bepaald doel, en gaat met de interrupts en eigen millis() en delay() functies buiten de normale Arduino code om. Wanneer je zelf te weinig kennis hebt, dan wordt het lastig. Misschien heeft iemand anders het al voor een OLED gemaakt.

Berichten: 88
Geregistreerd: 16 Jul 2015, 21:02

Re: Verbruiksmeter Injectie motor

Berichtdoor wim2584 » 26 Nov 2017, 20:26

Bedankt voor reactie,

eea draait op een arduino,



http://ecomodder.com/wiki/index.php/MPGuino

echter is mij de code Veel te moeilijk.

ik dat aan zo.n 0,96 Oled schermpje die veel op aliexpers staan

https://www.aliexpress.com/item/WAVGAT-Blue-color-128X64-OLED-LCD-LED-Display-Module-For-Arduino-0-96-I2C-IIC-SPI/32830611513.html?spm=2114.search0104.3.9.lzpoSD&ws_ab_test=searchweb0_0,searchweb201602_1_10152_10065_10151_10344_10068_10345_10342_10343_10340_10341_10541_10562_10084_10083_10304_10307_10301_10177_10539_10312_10059_10313_10314_10534_10533_100031_10604_10603_10103_10594_10557_10596_10595_10142_10107,searchweb201603_14,ppcSwitch_5&btsid=0a82708f-7cf9-4c40-8eb3-28202b0f876f&algo_expid=65f0d42f-db81-4dc5-9d33-410cfebf4078-1&algo_pvid=65f0d42f-db81-4dc5-9d33-410cfebf4078&rmStoreLevelAB=4




Vandaar als ik via het injectorsignaal de duty cycle en frequentie kan meten, komt hier een aantal ml uit, als ik dan verder via de snelheids sensor
(x pulsen/km) , de snelheid bereken komt hier een verbruik uit, het hele MPguino verhaal gaat ver boven mijn pet, wil ik ook niet mee verder gaan, het is alleen om het idee.

scope beeld injector zie bijlage

Berichten: 88
Geregistreerd: 16 Jul 2015, 21:02

Re: Verbruiksmeter Injectie motor

Berichtdoor wim2584 » 26 Nov 2017, 20:38

bijlage was te groot...:(

opnieuw
Bijlagen
injector 2.jpg
injector 2.jpg (33.6 KiB) 11331 keer bekeken

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Verbruiksmeter Injectie motor

Berichtdoor Koepel » 27 Nov 2017, 03:12

Sorry, maar ik zie het niet zitten om die OLED daarmee te laten werken.
Er is een grote kans dat het teveel geheugen gebruikt, en misschien is de library niet compatible met de specifieke code van de MPGuino.

Gebruikers-avatar
Berichten: 270
Geregistreerd: 30 Dec 2012, 11:42

Re: Verbruiksmeter Injectie motor

Berichtdoor Rudi » 27 Nov 2017, 12:58

Zo'n Nokia scherm zou ik niet aanraden, oude technologie en niet echt kontrastrijk.
Ik heb een OLED display gebruikt in mijn Arduinows!OBD2 (wagen) project. Een OLED heeft een scherpe en kontrastrijke uitlezing overdag en is niet verblindend in het donker.
Ik had ook met een LCD display getest maar dat is lastiger kijken bij zonnig daglicht.
Mijn project houdt in dat via de OBD2 bus een aantal wagengegevens kunnen worden opgevraagd en getoond.
Zulke gegevens kunnen via een zogenaamde PID worden opgevraagd. Ik denk echter dat OBD2 niet of weinig bij motoren wordt gebruikt.

Voor de geïnteresseerden, links naar mijn Arduinows!OBD2 blogpagina's:
Introduktie, BT communicatie, Hardware en software keuze, Sketch, Opbouw
Softwarematig kan e.e.a. waarschijnlijk veel beter maar het geheel werkt nu al meer dan een jaar vlotjes en betrouwbaar in mijn wagen.
Ik maakte gebruik van de U8G library die zoals je zelf hebt ondervonden veel geheugen in beslag neemt.
Ondertussen is er een nieuwere library (U8G2) en een U8x8 text only versie die, vermoed ik, veel minder geheugen in beslag neemt.

Probeer eerst eens wat uit met de U8x8 library en een OLED scherm. Als je dat onder de knie hebt dan zal het makkelijker worden om de mpguino sketch aan te passen voor OLED uitlezing.
Arduinows!
Why do computer programmers confuse Halloween with Christmas? Because Oct 31 = Dec 25
I got 01100011 problems but a bit ain't 00000001

Berichten: 88
Geregistreerd: 16 Jul 2015, 21:02

Re: Verbruiksmeter Injectie motor

Berichtdoor wim2584 » 27 Nov 2017, 17:48

helaas zit er geen OBD op deze motor Yamaha , (BMW heeft trouwens wel zoiets), maar hier zit een RC/TX K-Line? interface op waarvan ik geen gegeven heb, en ook niet weet wat voor data beschikbaar.

Die eenvoudigere library wist ik nog niet, zal eens kijken hoe dat werkt.

Vindt trouwens jou project ook heel leuk, (buiten elektronica doe ik ook veel aan auto motor reparatie, en ben dus bekend met OBDII), maar buiten de standaard PID is het vaak nuttig andere (merk specifieke PID) te kunnen bekijken, in mijn geval zou ik graag PID weten van mijn roetfilter (temp en verschildruk), maar kan die nu alleen uitlezen met Forscan (Ford), maar zou ook mogelijk zijn met jouw schakeling, alleen hoe kom je aan de PID waarden?

Bovenstaande heeft natuurlijk niet zoveel te doen met het Topic....

als ikzelf een "nieuwe" erg simpele verbruiksmeters zou willen maken, zal ik eerst:

-de frequentie en de duty cycle van het injector signaal moeten meten met een arduino, hoe pak ik dat het makkelijkste aan?
-de snelheid van de motor meten met wielsensor (xpuls/km) , hoe doe ik dat op een simpele manier?

Berichten: 1
Geregistreerd: 10 Jan 2018, 00:11

Re: Verbruiksmeter Injectie motor

Berichtdoor electronicasmurf » 10 Jan 2018, 00:31

Ik heb me zojuist hier geregistreerd om een antwoord te kunnen geven, geen idee of het topic al te oud is om nog te reageren maar dan hoor ik dat vanzelf.(ook als ik andere zaken fout doe)

Ik ben een tijd geleden met exact hetzelfde bezig geweest, alleen niet tot een resultaat gekomen.
Hiervoor de pulseIn functie gebruikt, triggerend op LOW. Deze functie geeft als resultaat de tijd (duration) dat de puls actief is geweest. Vermenigvuldigen met de flowrate van de injector en dan komt daar de afgegeven hoeveelheid brandstof uit. Al de aantallen bij elkaar optellen en het totaal verbuik volgt. Vervolgens aan de toongenerator en de injector laten sweepen, brandstof opvangen en de totale afgegeven hoeveelheid aflezen in een maatbeker. Vervolgens kan deze waarde worden vergeleken met wat er op de arduino is uitgerekend. Eventueel is er een correctiefactor te berekenen. Want de injector is niet dicht als de spanning weer aanwezig is(ook niet direct open wanneer de injector wordt aangestuurd).
Zover ben ik echter nog niet gekomen, aan de toongenerator kreeg ik onjuiste momentane verbruikcijfers.

Andere mogelijkheid is een interrupt op change en dan kijken of de poort hoog of laag is geworden. Naar hoog tijd - naar laag tijd is de openingstijd.
Ben benieuwd of er aan uw kant al iets werkend is.

Berichten: 1
Geregistreerd: 05 Jan 2019, 02:43

Re: Verbruiksmeter Injectie motor

Berichtdoor TripComputer945 » 05 Jan 2019, 02:49

Ook net aangemeld om hier iets te kunnen schrijven. Ik zou graag een boordcomputertje willen samenstellen voor m'n auto (zonder OBD2).

MPGuino heb ik ook al bekeken. Me dunkt dat dat met een Arduino Nano en een 128x32 I2C Oled beter c.q. mooier kan. Nano en schermpje heb ik al, "Hello World!" en een temperatuurprogrammaatje (van iemand anders) heb ik al met succes uitgeprobeerd. Nu de rest nog. :-D

O ja, ik heb wel eens wat geprogrammeerd, maar nog geen/amper C.

Terug naar Gezamenlijke projecten

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 3 gasten