Chwilowe spalanie benzyny + komp pokladowy - Kuter_tm - 15-12-2016
Witam
Od początku
Arduino mam od około 80 godzin
UNO kupiłem głownie po to żeby spróbować zrobić sobie wskaźnik który będzie pokazywał mi AFR w samochodzie. I w sumie to się udało. Mam kontroler sondy szerokopasmowej, który ma wyjscie analogowe 0-5V ale żeby odczytać co pokazuje, potrzebny laptop albo telefon i wpinka do centraliki. Stąd pomysł na arduino
Afr sie udało zrobić, pokazuje fajnie i dokładnie. Więc dołożyłem jeszcze EGT, niestety nie mam podłączonego, ale w teorii powinno działać ok. Na wyświetlaczu jest jeszcze pomiar napięcia aku. Ogolnie wyglada to tak
Ostatnio dołożyłem do całość diodę która miga po przekroczeniu AFR 15.5 ale tu jest problem.
Gdy puszczam gaz i "samochód ciągle silnik" wtryski są zamknięte (nie dają sygnału) i AFR idzę w góre co powoduje mruganie diody. Więc wymyśliłem sobie żeby zrobić warunek IF i to If miało by byc że dioda mruga tylko wtedy gdy afr pójdzie wyżej niz 15 i wtryski będą dawały sygnał
Idąc dalej tropem wtrysków skoro będę miał już ich sygnał i będę wiedział jaki maja wydatek paliwa, pomyślalem żeby zrobić coś wiecej i wpadło mi do głowy chwilowe spalanie. W samochodzie mam tylko średnie i mnie do irytuje.
Czy jest taka opcja możliwa? Domyślam się że, czy tak , czy tak będę musiał sygnał z wtrysku pobrać i zmniejszyć jego wartość do max wielkości 5V, pomyslalem żeby użyć do tego lm317 i zbic napięcie np do 3V.
W dalszych planach mam zamiar dołożyć przycisk który będzie mi zmieniał pewnie dane wyświetlacza, na doładowanie vacum, temp wew, zew dawał alerty w przypadku niskich temp.
Może ktoś pomóc i w tym? Dać jakiś link do czegoś podobnego. Bo nie wiem jak temat ugryźć
RE: Chwilowe spalanie benzyny + komp pokladowy - Smaczek - 15-12-2016
Witam,
A sygnał z wtrysków jest analogowy, tzn. zmienia się na nim napięcie, czy też są to impulsy o określonym napięciu?
Pozdrawiam.
RE: Chwilowe spalanie benzyny + komp pokladowy - Kuter_tm - 15-12-2016
Hej.
Dzieki za odpowiedz.
Wtrysk benzyny odbywa sie w sposób że sterownik podaje minus na wtryskiwacz. Plus jest zawsze na wtrysku podawany jest tylko minus-sterowany jest masą. Czas wtrysku jest w ms
Ps da rade jakos to skrócić?
Kod: lcd.setCursor(0,0);
lcd.print("AFR Warming UP");
lcd.setCursor(0,1);
lcd.print("Czekaj.");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print("."); //8
delay(1000);
lcd.print("."); //9
delay(1000);
lcd.print("!"); //10
delay(1000);
lcd.clear();
lcd.print ("Saab 9-3 :)");
lcd.setCursor(0,1);
lcd.print("SportSedan");
delay(1000);
lcd.clear();
}
RE: Chwilowe spalanie benzyny + komp pokladowy - Smaczek - 16-12-2016
Witam,
Jeśli sterowanie odbywa się poprzez zwieranie do masy to ułatwia to sprawę. Musisz jedynie dokonywać detekcji logicznego 0. Raczej nie podłączaj sterowania wtrysków bezpośrednio do wejścia mikrokontrolera, a zrób to najlepiej przez tranzystor.
Co do programu:
- do dokładnego pomiaru potrzebne jest zastosowanie przerwań,
- za ich pomocą musisz zmierzyć czas iluś (im większej ilości, tym dokładniejszy pomiar) wtryśnięć (przy założeniu, że dawkowanie jest za każdym razem identyczne),
- na podstawie pomiaru obliczasz ilość wtryśnięć w czasie np. 1 s,
- mając daną ilość paliwa wtryskiwaną podczas jednej iniekcji możesz obliczyć zużycie na jednostkę czasu,
- określenie spalania chwilowego w przeliczeniu na drogę wymaga znajomości prędkości auta w chwili pomiaru.
PS.
Skrócić się da, gdy zastosujesz pętlę dla:
lcd.print(".");
delay(1000);
RE: Chwilowe spalanie benzyny + komp pokladowy - piotr2393 - 16-12-2016
(15-12-2016, 17:52)Kuter_tm napisał(a): Hej.
Dzieki za odpowiedz.
Wtrysk benzyny odbywa sie w sposób że sterownik podaje minus na wtryskiwacz. Plus jest zawsze na wtrysku podawany jest tylko minus-sterowany jest masą. Czas wtrysku jest w ms
Ps da rade jakos to skrócić?
Kod: lcd.setCursor(0,0);
lcd.print("AFR Warming UP");
lcd.setCursor(0,1);
lcd.print("Czekaj.");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print(".");
delay(1000);
lcd.print("."); //8
delay(1000);
lcd.print("."); //9
delay(1000);
lcd.print("!"); //10
delay(1000);
lcd.clear();
lcd.print ("Saab 9-3 :)");
lcd.setCursor(0,1);
lcd.print("SportSedan");
delay(1000);
lcd.clear();
}
Pewnie że sie da, jeśli chcesz zachować te czasy to skrócić to możesz zwykłym for'em. Pętla wykona się 10 razy.
Kod: for(int i=0; i<10; i++)
{
lcd.print(".");
delay(1000);
}
RE: Chwilowe spalanie benzyny + komp pokladowy - Kuter_tm - 16-12-2016
Witam
kod skróciłem dzieki
Co do paliwa to mam stałą 261gram/minute
Jak by przyjąc ze 261g jest to 261 ml /60sek to wychodzi ze w ciągu sekundy wtrysk podaje 4,32 ml
przyjmując że najdłuższy czas wtrysku to 25 ms, czyli 1,08ml
hmm wiec skoro w ciagu 60 minut wtryskiwacz poda 15660 ml paliwa czyli 15,6 litra i w ciągu tego czasu przejade 100 km to wyjdzie mi spalanie 15,6/100
-I teraz odnosnie arduino. Ustawić wejście na pinie analogowym rozumiem?
- Jaki tranzystor tam podłączyc? Rozumiem że LM317 i para rezystorów odpada ?
Czyli arduino powinno liczyć ile czasu przykładowo A5(jeżeli tu wepne) jest jako LOW, bo sterowane masa
wiec, napisze z jednostkami w nawiasach [] (A5*4,32[ml w ciagu1sek] *3600[czas na godzine]/1000[ml zeby wyszły litry])/100[km]
Znalazłem takie rozwiązanie MPGuino prawie dokładnie to co chce zrobić. Niestety nie widze kodu który bym mógł dostosować pod siebie.
RE: Chwilowe spalanie benzyny + komp pokladowy - Smaczek - 16-12-2016
Witam,
A pytałem, czy za każdym razem wtryskiwana jest taka sama porcja paliwa!
Jeśli czas wtryskiwania jest różny to przy maksymalnym czasie 24 ms należałoby mierzyć czas stanu niskiego za pomocą funkcji millis(), która powinna być umieszczona wewnątrz funkcji obsługującej przerwanie (stan niski powoduje przerwanie i rozpoczęcie pomiaru czasu, a wysoki kończyć ten pomiar, ponadto sumować czas i zakończyć sumowanie jeśli minie 1 s). Przerwania w przypadku UNO obsługiwane są jedynie przez pin D2 i D3.
Napisałeś, że wtrysk sterowany jest masą. Czyli między wtryskami nie ma na nim żadnego napięcia, ale nie ma też połączenia z masą? Czy też jest jakieś napięcie jest?
Pozdrawiam.
RE: Chwilowe spalanie benzyny + komp pokladowy - Kuter_tm - 16-12-2016
OK sorry zle musialem zrozumieć.
z tego co wiem to, na wtryskiwaczu jest zawsze plus, natomiast odcinana jest masa. W chwili gdy ma podac paliwo, komputer samochodowy podaje na wtrysk mase i on sie otwiera. Taki elektrozawór. Znalazłem projekt komp samochodowego, i mam jego kod. Ale jeszcze za zielony jestem żeby go ogarnać
Link ->http://ecomodder.com/wiki/index.php/MPGuino
i na dole jest dział Custom versions
tam sa rozne kody do pobrania.
Np
Kod: #include <Wire.h>
#include "LiquidCrystal.h"
LiquidCrystal lcd(4, 5, 7, 8, 12, 13);
int analogInput = 2;
int prev = LOW;
int refresh = 1000;
// float vout = 0.0;
float vin = 0.0;
//float R1 = 51000.0; // !! resistance of R1 !!
// float R2 = 5500.0; // !! resistance of R2 !!
// #define VoltageDivider(V);// 6153L // (50k1hm+4k4hm) / 4kOhm * 5V / 1023 * 100000opel
int sensorPin = 1; // select the input pin for the potentiometer
int sensorValue = 0; // the sensor value
int sensorMin = 0; // full tank
int sensorMax = 1023; //empty tank
int DRL = 10;
int value = 0;
byte pompa1[8] = { B00000, B00011, B00010, B00010, B00011, B00011, B00011, B00111};
byte pompa2[8] = { B00000, B11000, B01100, B01010, B11010, B11100, B11000, B11100};
byte diametru[8] = { B00000, B01101, B10010, B10101, B01001, B10110, B00000, B00000 };
byte spate[8] = { B00000, B00000, B00001, B00010, B01111, B01111, B01101, B00010};
byte mijloc[8] = {B00000, B11111, B00000, B00000, B11111, B11111, B11111, B00000};
byte fata[8] = {B00000, B00000, B10000, B01000, B11110, B11111, B10111, B01000};
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
typedef uint8_t boolean;
typedef uint8_t byte;
#define RISING 3
#define FALLING 2
#define loopsPerSecond 2 // how many times will we try and loop in a second
//use with 20mhz
#define cyclesperhour 4500
#define dispadj 800
#define dispadj2 1250
#define looptime 1250000ul/loopsPerSecond //1/2 second
#define myubbr (20000000/16/9600-1)
#define injhold (parms[injectorSettleTimeIdx]*5)/4
#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))
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 doDisplayCustom();
void doDisplayBigInstant();
void doDisplayBigCurrent();
void doTime();
void doDisplayTotal();
void doDisplayBigSpeed();
void doDisplayBigTank();
void doDisplayBigDistance();
void doDisplayBigVolt();
void doDisplaySystemInfo(void);
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);
void tDisplay(void * r);
int memoryTest();
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();
char * uformat(unsigned long val);
unsigned long rformat(char * val);
void editParm(byte parmIdx);
void initGuino();
unsigned long millis2();
void delay2(unsigned long ms);
void delayMicroseconds2(unsigned int us);
void simpletx(char * string);
unsigned long parms[]={95ul,17923ul,3669000ul,3ul,21ul,1240ul,1ul,0ul,50ul,80000000,4200000,1ul};//opel
char * parmLabels[]={"Contrast","VSS Pulses/Km", "MicroSec/Litre","Pulses/2 revs","Injector DelayuS",
"Voltage * 1000 ","VSS Delay ms", "InjTrg 0-Dn 1-Up"," Tank L ","TankKm*100.000 ","Tank L*100.000","DRL 1=ON 0=OFF" };
//"0-USA 1-METRIC","Tank Km * 1000","Tank Litres*1000"};
byte brightness[] = { 0, 15, 128, 255 }; //middle button cycles through these brightness settings
#define brightnessLength (sizeof(brightness)/sizeof(byte)) //array size
byte brightnessIdx = 3;
#define contrastIdx 0 //do contrast first to get display dialed in
#define vssPulsesPerMileIdx 1
volatile unsigned long distancefactor;
#define microSecondsPerGallonIdx 2
volatile unsigned long fuelfactor;
#define injPulsesPer2Revolutions 3
#define injectorSettleTimeIdx 4
#define VoltageIdx 5
volatile unsigned long Coef;
#define vsspauseIdx 6
#define injEdgeIdx 7
#define tankSizeIdx 8
volatile unsigned long L;
#define calibrationDistanceIdx 9
volatile unsigned long tmptankdistance;
#define calibrationFuelIdx 10
volatile unsigned long tmptankfuel;
#define metricIdx=1;
#define drlIdx 11
#define parmsLength (sizeof(parms)/sizeof(unsigned long)) /* //array size */
unsigned long TimeoutBrightness = 36000000;//30 sec
unsigned long TimeoutTrip = 72000000*30;//min * x
unsigned long injectorSettleTime;
unsigned long tmpDRL=parms[drlIdx];
unsigned long V=(parms[VoltageIdx]*7982L)/parms[VoltageIdx];
#define nil 3999999999ul
#define guinosigold 0b10100101
#define guinosig 0b11100111
#define vssBit ( 1 << 0 )
#define lbuttonBit ( 1 << 3 )
#define mbuttonBit ( 1 << 4 )
#define rbuttonBit ( 1 << 5 )
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 << PCINT11);
}
void enableMButton() {
PCMSK1 |= (1 << PCINT12);
}
void enableRButton() {
PCMSK1 |= (1 << PCINT13);
}
//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 1
#define enableMButtonID 2
#define enableRButtonID 3
//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; //rpm
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 vssEOCPulses;//from the speedo
unsigned long vssPulseLength; // only used by instant
//these functions actually return in thousandths,
unsigned long distance();
unsigned long fuel();
unsigned long lkm();
unsigned long mpg();
unsigned long mph();
unsigned long time(); //mmm.ss
unsigned long timeS();
unsigned long timeM();
unsigned long timeH();
unsigned m;
unsigned m1;
unsigned h;
unsigned sec;
unsigned long fuelperdistanceunit( unsigned long multiplier );
unsigned long Range();
unsigned long eocMiles(); //how many "free" miles?
unsigned long idleGallons(); //how many gallons spent at 0 mph?
void update(Trip t);
void reset();
Trip();
};
//LCD prototype
namespace LCD {
void gotoXY(byte x, byte y);
void print(char * string);
void init();
void print(byte value);
void tickleEnable();
void cmdWriteSet();
void LcdCommandWrite(byte value);
void LcdDataWrite(byte value);
byte pushNibble(byte value);
}
;
//main objects we will be working with:
unsigned long injHiStart; //for timing injector pulses
Trip tmpTrip;
Trip instant;
Trip current;
Trip tank;
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, parms[vsspauseIdx]); //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[] = { doDisplayCustom, doDisplayInstantHour,doDisplayConsumTrip,doDisplayCurDistance,doDisplayTripConsum,
doDisplayTripTime,doDisplayDRL,doDisplaySpeed,doDisplayConsumTank,doDisplayTankDistance,doDisplayTankConsum,doDisplayTotalTime,doDisplayRange,};
#define displayFuncSize (sizeof(displayFuncs)/sizeof(pFunc)) //array size
prog_char * displayFuncNames[displayFuncSize];
byte newRun = 0;
void setup(void) {
pinMode(DRL, OUTPUT);
newRun = load();//load the default parameters
byte x = 0;
LCD::LcdCommandWrite(0b00000001); // clear display, set cursor position to zero
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
displayFuncNames[x++] = PSTR(" ");
// analogWrite(BrightnessPin,brightness[brightnessIdx]);
sbi(TCCR1A, COM1A1); //brightness pwm enable
tmpDRL =parms[drlIdx];
OCR1A = brightness[brightnessIdx];
DDRB = (1 << DDB5) | (1 << DDB4) | (1 << DDB1) | (1 << DDB0);
DDRD = (1 << DDD7) | (1 << DDD6) | (1 << DDD5) | (1 << DDD4);
delay2(500);
V=(parms[VoltageIdx]*7982L)/parms[VoltageIdx];
// analogWrite(ContrastPin,parms[contrastIdx]);
sbi(TCCR0A, COM0A1);//contrast pwm enable
OCR0A = parms[contrastIdx];
LCD::init();
LCD::LcdCommandWrite(0b00000001); // clear display, set cursor position to zero
LCD::LcdCommandWrite(0b10000); // set dram to zero
LCD::gotoXY(0, 0);
LCD::print(getStr(PSTR(" Opel Astra F ")));
LCD::gotoXY(0, 1);
LCD::print(getStr(PSTR(" MPGuino v0.86")));
injectorSettleTime = injhold;
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
unsigned long Volt = voltage();
V=(parms[VoltageIdx]*7982L)/parms[VoltageIdx];
distancefactor = parms[vssPulsesPerMileIdx];
fuelfactor = parms[microSecondsPerGallonIdx];
tmpDRL =parms[drlIdx];
L = parms[tankSizeIdx]; //distancefactor = (distancefactor * 1.609344);
fuelfactor = (fuelfactor * 3.78541178);
//low level interrupt enable stuff
PCMSK1 |= (1 << PCINT8);
enableLButton();
enableMButton();
enableRButton();
PCICR |= (1 << PCIE1);
delay2(1500);
}
byte screen = 0;
byte holdDisplay = 0;
void mainloop(void) {
if (newRun != 1)
initGuino();//go through the initialization screen
unsigned long lastActivity = microSeconds();
unsigned long tripHold;
unsigned long tankHold; //state at point of last activity
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();
//send out instantmpg * 1000, instantmph * 1000, the injector/vss raw data
simpletx(format(instantmpg()));
simpletx(",");
simpletx(format(instantmph()));
simpletx(",");
simpletx(format(instant.injHius * 1000));
simpletx(",");
simpletx(format(instant.injPulses * 1000));
simpletx(",");
simpletx(format(instant.vssPulses * 1000));
simpletx("\n");
current.update(instant); //use instant to update current
tank.update(instant); //use instant to update tank
if (instant.vssPulses == 0 && instant.injPulses == 0 && holdDisplay
== 0) {
if (elapsedMicroseconds(lastActivity)
> TimeoutBrightness && lastActivity
!= nil){
OCR1A = brightness[0];
tank.loopCount = tankHold;
current.loopCount = tripHold;
lcd.noDisplay();
}
} else {
if (lastActivity != nil) {//wake up!!!
OCR1A = brightness[brightnessIdx];
tankHold = tank.loopCount;
tripHold = current.loopCount;
lcd.display();
}}
if (instant.vssPulses == 0 && instant.injPulses == 0 && holdDisplay
== 0) {
if (elapsedMicroseconds(lastActivity)
> TimeoutTrip && lastActivity
!= nil) {
lastActivity = nil;
// lcd.noDisplay();
}
} else {
if (lastActivity == nil) {//wake up!!!
lcd.display();
OCR1A = brightness[brightnessIdx];
lastActivity = loopStart;
current.reset();
tank.loopCount = tankHold;
current.update(instant);
tank.update(instant);
} else {
lastActivity = loopStart;
tankHold = tank.loopCount;
}
}
if (holdDisplay == 0) {
displayFuncs[screen](); //call the appropriate display routine
LCD::gotoXY(0, 0);
//see if any buttons were pressed, display a brief message if so
if (!(buttonState & lbuttonBit) && !(buttonState & rbuttonBit)) {// left and right = initialize
LCD::LcdCommandWrite(0b00000001); // clear display, set cursor position to zero
LCD::print(getStr(PSTR("Setup ")));
delay(100000);
// set values for math-less calibration method - which is used when refilling the tank
unsigned long tmptankdistance = tank.distance(); // take a snapshot, in case update occurs during the updates
unsigned long tmptankfuel = tank.fuel();
int tmpdirty = 0;
unsigned long Volt = voltage();
parms[calibrationDistanceIdx] = tmptankdistance; // distance x 1000, for updating parms[vssPulsesPerMileIdx]
parms[calibrationFuelIdx] = tmptankfuel; // fuel x 1000, for updating parms[microSecondsPerGallonIdx]
parms[drlIdx] = tmpDRL;
initGuino();
//}else if(!(buttonState&lbuttonBit) && !(buttonState&rbuttonBit)){// left and right = run lcd init = tank reset
// LCD::print(getStr(PSTR("Init LCD ")));
// LCD::init();
L = parms[tankSizeIdx];
V=(parms[VoltageIdx]*7982L)/1200L;
if (parms[calibrationDistanceIdx] != tmptankdistance)
{
parms[vssPulsesPerMileIdx] = recalculate(parms[vssPulsesPerMileIdx], tmptankdistance, parms[calibrationDistanceIdx]);
tmpdirty = 1;
}
if (parms[calibrationFuelIdx] != tmptankfuel)
{
parms[microSecondsPerGallonIdx] = recalculate(parms[microSecondsPerGallonIdx], tmptankfuel, parms[calibrationFuelIdx]);
tmpdirty = 1;
}
if (tmpdirty)
save(); // save recalculated settings
} else if (!(buttonState & lbuttonBit) && !(buttonState
&mbuttonBit)) {// left and middle = tank reset
tank.reset();
LCD::LcdCommandWrite(0b00000001); // clear display, set cursor position to zero
LCD::print(getStr(PSTR("Tank Reset ")));
delay(100000);
} else if (!(buttonState & mbuttonBit) && !(buttonState
&rbuttonBit)) {// right and middle = current reset
current.reset();
LCD::LcdCommandWrite(0b00000001); // clear display, set cursor position to zero
LCD::print(getStr(PSTR("Current Reset ")));
delay(100000);
} else if (!(buttonState & lbuttonBit)) { //left is rotate through screeens to the left
if (screen != 0)
screen = (screen - 1);
else
screen = displayFuncSize - 1;
LCD::print(getStr(displayFuncNames[screen]));
} else if (!(buttonState & mbuttonBit)) { //middle is cycle through brightness settings
brightnessIdx = (brightnessIdx + 1) % brightnessLength;
OCR1A = brightness[brightnessIdx];
// analogWrite(BrightnessPin,brightness[brightnessIdx]);
LCD::LcdCommandWrite(0b00000001); // clear display, set cursor position to zero
LCD::print(getStr(PSTR("Brightness ")));
LCD::LcdDataWrite('0' + brightnessIdx);
LCD::print(" ");
} else if (!(buttonState & rbuttonBit)) {//right is rotate through screeens to the left
screen = (screen + 1) % displayFuncSize;
LCD::print(getStr(displayFuncNames[screen]));
}
if (buttonState != buttonsUp)
holdDisplay = 1;
} else {
holdDisplay = 0;
}
buttonState = buttonsUp;//reset the buttons
//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))
;//wait for the end of a second to arrive
}
lcd.begin(16, 2);
}
char fBuff[7];//used by format
void dispv(char * usl, char * ml, unsigned long num) {
//LCD::print(parms[metricIdx]==1?ml:usl);
LCD::print(format(num));
}
void dispv_raw(char * usl, char * ml, unsigned long num) {
//LCD::print(parms[metricIdx]==1?ml:usl);
LCD::print(num);
}
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[3] = 0;
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;
}
char* formatt(unsigned long num) {
byte dp = 1;
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) > 1)
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[3] = 0;
fBuff[4] = 0;
return fBuff;
}
void doDisplayCustom() {
char buffer[50];
LCD::print("R ");
LCD::print(ltoa(instantrpm(), buffer, 10));
LCD::print(" SPD ");
LCD::print(ltoa(instantmph(), buffer, 10));
LCD::print(" ");
LCD::gotoXY(0, 1);
LCD::print("Volt ");
LCD::print(formatt(voltage()));
LCD::print(" ");
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
}
void doDisplayInstantHour() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
if(instant.vssPulses < 5)
LCD::gotoXY(0, 0);
if(instant.vssPulses < 5)
LCD::print(" Instant Hour ");
if(instant.vssPulses < 5)
LCD::gotoXY(0, 1);
if(instant.vssPulses < 5)
LCD::print(" ");
if(instant.vssPulses < 5)
LCD::print(formatt(instantgph()));
if(instant.vssPulses < 5)
LCD::print(" L/h ");
if(instant.vssPulses > 5)
LCD::gotoXY(0, 0);
if(instant.vssPulses > 5)
LCD::print(" Instant ");
if(instant.vssPulses > 5)
LCD::gotoXY(0, 1);
if(instant.vssPulses > 5 )
LCD::print(" ");
if(instant.vssPulses > 5 )
LCD::print(formatt(instantfuelperhour()));
if(instant.vssPulses > 5 )
LCD::print(" L% ");
}
void doDisplayTripConsum() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
//char buffer[50];
LCD::gotoXY(0, 0);
LCD::print(" Trip Consum ");
LCD::gotoXY(0, 1);
LCD::print(" ");
LCD::print(formatt(current.fuel()));
LCD::print(" L ");
}
void doDisplayTankConsum() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
lcd.createChar(2,pompa1);
lcd.createChar(3,pompa2);
lcd.createChar(4,spate);
lcd.createChar(5,mijloc);
lcd.createChar(6,fata);
char buffer[50];
LCD::gotoXY(0, 0);
lcd.write(2);
lcd.write(3);
LCD::print("....");
lcd.write(4);
lcd.write(5);
lcd.write(6);
LCD::print(" ");
LCD::gotoXY(0, 1);
LCD::print(" ");
LCD::print(formatt(tank.fuel()));
LCD::print(" L ");
}
void doDisplayRange() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
char buffer[50];
lcd.createChar(2,pompa1);
lcd.createChar(3,pompa2);
lcd.createChar(4,spate);
lcd.createChar(5,mijloc);
lcd.createChar(6,fata);
LCD::gotoXY(0, 0);
LCD::print(" ");
lcd.write(2);
lcd.write(3);
LCD::print(" ");
lcd.write(4);
lcd.write(5);
lcd.write(6);
LCD::print("....");
lcd.write(2);
lcd.write(3);
LCD::print(" ");
LCD::gotoXY(0, 1);
LCD::print(" ");
LCD::print(ltoa(sensorValue, buffer, 10));
LCD::print(" L ");
LCD::print(ltoa(current.Range(), buffer, 10));
LCD::print(" Km ");
}
void doDisplaySpeed() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
lcd.createChar(1, diametru);
char buffer[50];
LCD::gotoXY(0, 0);
LCD::print("Trip Km/h Tank ");
LCD::gotoXY(0, 1);
lcd.write(1);
LCD::print(" ");
LCD::print(ltoa(current.mph(), buffer, 10));
LCD::print(" ");
lcd.write(1);
LCD::print(" ");
LCD::print(ltoa(tank.mph(), buffer, 10));
LCD::print(" ");
}
void doDisplayConsumTrip() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
lcd.createChar(1, diametru);
LCD::gotoXY(0, 0);
LCD::print(" Trip ");
LCD::gotoXY(0, 1);
LCD::print(" ");
lcd.write(1);
LCD::print(" ");
LCD::print(formatt(current.fuelperdistanceunit(100)));
LCD::print(" L% ");
}
void doDisplayTripTime() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
char buffer[50];
LCD::gotoXY(0, 0);
LCD::print(" Trip ");
LCD::gotoXY(0, 1);
LCD::print(" ");
if (current.timeH()<10)
LCD:: print ("0");
LCD::print(ltoa(current.timeH(), buffer, 10));
LCD::print(":");
if (current.timeM()<10)
LCD:: print ("0");
LCD::print(ltoa(current.timeM(), buffer, 10));
LCD::print(":");
if (current.timeS()<10)
LCD:: print ("0");
LCD::print(ltoa(current.timeS(), buffer, 10));
LCD::print(" ");
}
void doDisplayTotalTime (){
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
lcd.createChar(2,pompa1);
lcd.createChar(3,pompa2);
lcd.createChar(4,spate);
lcd.createChar(5,mijloc);
lcd.createChar(6,fata);
char buffer[50];
LCD::gotoXY(0, 0);
lcd.write(2);
lcd.write(3);
LCD::print("....");
lcd.write(4);
lcd.write(5);
lcd.write(6);
LCD::print(" ");
LCD::gotoXY(0, 1);
LCD::print(" ");
if (tank.timeH()<10)
LCD:: print ("0");
LCD::print(ltoa(tank.timeH(), buffer, 10));
LCD::print(":");
if (tank.timeM()<10)
LCD:: print ("0");
LCD::print(ltoa(tank.timeM(), buffer, 10));
LCD::print(":");
if (tank.timeS()<10)
LCD:: print ("0");
LCD::print(ltoa(tank.timeS(), buffer, 10));
LCD::print(" ");
}
void doDisplayConsumTank() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
lcd.createChar(1, diametru);
lcd.createChar(2,pompa1);
lcd.createChar(3,pompa2);
lcd.createChar(4,spate);
lcd.createChar(5,mijloc);
lcd.createChar(6,fata);
LCD::gotoXY(0, 0);
lcd.write(2);
lcd.write(3);
LCD::print("....");
lcd.write(4);
lcd.write(5);
lcd.write(6);
LCD::print(" ");
LCD::gotoXY(0, 1);
LCD::print(" ");
lcd.write(1);
LCD::print(" ");
LCD::print(formatt(tank.fuelperdistanceunit(100)));
LCD::print(" L% ");
}
void doDisplayCurDistance() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
char buffer[50];
LCD::gotoXY(0, 0);
LCD::print(" Trip ");
LCD::gotoXY(0, 1);
LCD::print(" ");
if (current.distance()<9999900)
LCD::print(formatt(current.distance()));
if (current.distance()>9999900)
LCD::print(ltoa(current.distance()/100000, buffer, 10));
LCD::print("Km ");
}
void doDisplayTankDistance() {
if (instant.vssPulses>10 && voltage() > 1380000 && tmpDRL==1) digitalWrite(DRL, HIGH);//set volt to open DRL
if (instant.injPulses==0 && instant.vssPulses==0) digitalWrite(DRL, LOW); //set volt to close DRL
lcd.createChar(2,pompa1);
lcd.createChar(3,pompa2);
lcd.createChar(4,spate);
lcd.createChar(5,mijloc);
lcd.createChar(6,fata);
char buffer[50];
LCD::gotoXY(0, 0);
lcd.write(2);
lcd.write(3);
LCD::print("....");
lcd.write(4);
lcd.write(5);
lcd.write(6);
LCD::print(" ");
LCD::gotoXY(0, 1);
LCD::print(" ");
if (tank.distance()<9999900)
LCD::print(formatt(tank.distance()));
if (tank.distance()>9999900)
LCD::print(ltoa(tank.distance()/100000, buffer, 10));
LCD::print("Km ");
}
void doDisplayDRL(){
digitalWrite(DRL, LOW); //set volt to close DRL
LCD::gotoXY(0, 0);
LCD::print(" LIGHTS OFF ");
LCD::gotoXY(0, 1);
LCD::print(" Volt ");
LCD::print(formatt(voltage()));
LCD::print(" ");
}
//x=0..16, y= 0..1
void LCD::gotoXY(byte x, byte y) {
byte dr = x + 0x80;
if (y == 1)
dr += 0x40;
if (y == 2)
dr += 0x14;
if (y == 3)
dr += 0x54;
LCD::LcdCommandWrite(dr);
}
void LCD::print(char * string) {
byte x = 0;
char c = string[x];
while (c != 0) {
LCD::LcdDataWrite(c);
x++;
c = string[x];
}
}
void LCD::init() {
delay2(16); // wait for more than 15 msec
pushNibble(0b00110000); // send (B0011) to DB7-4
cmdWriteSet();
tickleEnable();
delay2(5); // wait for more than 4.1 msec
pushNibble(0b00110000); // send (B0011) to DB7-4
cmdWriteSet();
tickleEnable();
delay2(1); // wait for more than 100 usec
pushNibble(0b00110000); // send (B0011) to DB7-4
cmdWriteSet();
tickleEnable();
delay2(1); // wait for more than 100 usec
pushNibble(0b00100000); // send (B0010) to DB7-4 for 4bit
cmdWriteSet();
tickleEnable();
delay2(1); // wait for more than 100 usec
// ready to use normal LcdCommandWrite() function now!
LcdCommandWrite(0b00101000); // 4-bit interface, 2 display lines, 5x8 font
LcdCommandWrite(0b00001100); // display control:
LcdCommandWrite(0b00000110); // entry mode set: increment automatically, no display shift
//creating the custom fonts:
LcdCommandWrite(0b01001000); // set cgram
static byte chars[] PROGMEM = {
B11111, B00000, B11111, B11111, B00000, B11111, B00111, B11100,
B11111, B00000, B11111, B11111, B00000, B11111, B01111, B11110,
B00000, B00000, B00000, B11111, B00000, B11111, B11111, B11111,
B00000, B00000, B00000, B11111, B00000, B11111, B11111, B11111,
B00000, B00000, B00000, B11111, B00000, B11111, B11111, B11111,
B00000, B00000, B00000, B11111, B01110, B11111, B11111, B11111,
B00000, B11111, B11111, B01111, B01110, B11110, B11111, B11111,
B00000, B11111, B11111, B00111, B01110, B11100, B11111, B11111};
/* write the character data to the character generator ram */
for(byte x=0;x<8;x++) {
for(byte y=0;y<8;y++) {
LcdDataWrite(pgm_read_byte(&chars[y*8+x]));
}
}
LcdCommandWrite(B00000001); // clear display, set cursor position to zero
LcdCommandWrite(B10000000); // set dram to zero
}
void LCD::tickleEnable() {
// send a pulse to enable PD5
PORTD |= (1 << 5);
delayMicroseconds2(1); // pause 1 ms according to datasheet
PORTD &= ~(1 << 5);
delayMicroseconds2(1); // pause 1 ms according to datasheet
}
void LCD::cmdWriteSet() { //set enable (PD5) low and DI(PD4) low
PORTD &= ~(1 << 5);
delayMicroseconds2(1); // pause 1 ms according to datasheet
PORTD &= ~(1 << 4);
}
byte LCD::pushNibble(byte value) { //db7=PB5, db6=PB4, db5 = PB0, db4 = PD7
value & 128 ? PORTB |= (1 << 5) : PORTB &= ~(1 << 5);
value <<= 1;
value & 128 ? PORTB |= (1 << 4) : PORTB &= ~(1 << 4);
value <<= 1;
value & 128 ? PORTB |= (1 << 0) : PORTB &= ~(1 << 0);
value <<= 1;
value & 128 ? PORTD |= (1 << 7) : PORTD &= ~(1 << 7);
value <<= 1;
return value;
}
void LCD::LcdCommandWrite(byte value) {
value = pushNibble(value);
cmdWriteSet();
tickleEnable();
value = pushNibble(value);
cmdWriteSet();
tickleEnable();
delay2(5);
}
void LCD::LcdDataWrite(byte value) {
PORTD |= (1 << 4); //di on pd4
value = pushNibble(value);
tickleEnable();
value = pushNibble(value);
tickleEnable();
delay2(5);
}
// this function will return the number of bytes currently free in RAM
extern int __bss_end;
extern int *__brkval;
int memoryTest() {
int free_memory;
if ((int) __brkval == 0)
free_memory = ((int) &free_memory) - ((int) &__bss_end);
else
free_memory = ((int) &free_memory) - ((int) __brkval);
return free_memory;
}
Trip::Trip() {
}
//for display computing
unsigned long tmp1[2];
unsigned long tmp2[2];
unsigned long tmp3[2];
unsigned long instantmph() {
//unsigned long vssPulseTimeuS = (lastVSS1 + lastVSS2) / 2;
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]/1000;
}
double voltage(){
value = analogRead(analogInput);
vin = (value * V);
// return vin+3;
}
unsigned long instantmpg() {
unsigned long imph = instantmph();
unsigned long igph = instantgph();
if (igph == 0)
return 0;
if (imph == 0)
return 0;//999999000;
init64(tmp1, 0, 1000ul);
init64(tmp2, 0, igph);
mul64(tmp2, tmp1);
init64(tmp1, 0, imph);
div64(tmp2,tmp1);
//return tmp2[1];
return tmp2[1]/10;//////////pt opel*10
}
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] * 10;
}
unsigned long instantfuelperhour(){
init64(tmp1,0,instInjTot);
init64(tmp2,0,12000000ul);
mul64(tmp1,tmp2);
init64(tmp2,0,1000000ul);
mul64(tmp1,tmp2);
init64(tmp2,0,fuelfactor);
div64(tmp1,tmp2);
init64(tmp2,0,instInjEnd-instInjStart);
div64(tmp1,tmp2);
return tmp1[1]*10;
}
unsigned long instantrpm(){
init64(tmp1,0,instInjCount);
init64(tmp2,0,120000000ul);
mul64(tmp1,tmp2);
init64(tmp2,0,1000ul);
mul64(tmp1,tmp2);
init64(tmp2,0,parms[injPulsesPer2Revolutions]);
div64(tmp1,tmp2);
init64(tmp2,0,instInjEnd-instInjStart);
div64(tmp1,tmp2);
return tmp1[1]/1000;
}
unsigned long recalculate(unsigned long calibrationvalue, unsigned long currentvalue, unsigned long correctvalue)
{
simpletx("recalc ");
simpletx(uformat(currentvalue)); // 0000022211
simpletx(",");
simpletx(uformat(correctvalue)); // 0000022299
simpletx(",");
simpletx(uformat(calibrationvalue)); // 0000009926
simpletx(";");
init64(tmp1,0,currentvalue);
init64(tmp2,0,1000000ul); // multiply to obtain six decimal points of accuracy
mul64(tmp1,tmp2);
init64(tmp2,0,correctvalue);
div64(tmp1,tmp2); // current / correct, resulting fraction in tmp1
// (22211 * 1000000)/22299=996.035 = 996 (the decimal digits are lost)
simpletx(uformat(tmp1[0]));
simpletx(",");
simpletx(uformat(tmp1[1]));
simpletx(";");
init64(tmp2,0,calibrationvalue);
mul64(tmp1,tmp2); // (correction-fraction * 1000000) * original calibration value, result (new calibration value * 1000000) in tmp1
simpletx(uformat(tmp1[0]));
simpletx(",");
simpletx(uformat(tmp1[1]));
simpletx(";");
init64(tmp2,0,1000000ul);
div64(tmp1,tmp2); // back to correct magnitude
simpletx(uformat(tmp1[0]));
simpletx(", return=");
simpletx(uformat(tmp1[1]));
simpletx("\n");
return tmp1[1];
}
unsigned long Trip::distance() {
init64(tmp1, 0, vssPulses);
init64(tmp2, 0, 1000);
mul64(tmp1, tmp2);
init64(tmp2, 0, distancefactor);
div64(tmp1, tmp2);
return tmp1[1]*100;
}
unsigned long Trip::eocMiles() {
init64(tmp1, 0, vssEOCPulses);
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]/1000;
}
unsigned long Trip::fuel() {
init64(tmp1,0,injHiSec);
init64(tmp2,0,1000000);
mul64(tmp1,tmp2);
init64(tmp2,0,injHius);
add64(tmp1,tmp2);
init64(tmp2,0,1000);
mul64(tmp1,tmp2);
init64(tmp2,0,fuelfactor);
div64(tmp1,tmp2);
return (tmp1[1] * 1.609344)*10;
}
unsigned long Trip::Range() {
sensorValue = analogRead(sensorPin);// apply the calibration to the sensor reading
sensorValue = map(sensorValue, sensorMax, sensorMin, 0, L);
sensorValue = constrain(sensorValue, 0, L);
unsigned long restfuel = ((sensorValue)*10000000/tank.fuelperdistanceunit(100));
return restfuel;
}
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];
}
//eocMiles
//idleGallons
unsigned long Trip::fuelperdistanceunit( unsigned long multiplier ){
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(tmp2,0,1000);
mul64(tmp3,tmp2);
init64(tmp1,0,fuelfactor);
init64(tmp2,0,vssPulses);
mul64(tmp1,tmp2);
div64(tmp3,tmp1);
init64(tmp2,0,multiplier); // scale it up (eg: "1" for litres/km or "100" litres/100km
mul64(tmp3,tmp2);
if (tmp3[1] > 150000) tmp3[1] = 150000;
return (tmp3[1] * 1.609344)*10;
}
//return the seconds as a time mmm.ss, eventually hhh:mm too
unsigned long Trip::timeS() {//return seconds;
byte d = 60;
unsigned long seconds = loopCount / loopsPerSecond;
sec=(seconds%d);
return sec;
}
unsigned long Trip::timeM() {//return MINUTES;
byte d=60;
unsigned long minutes = (loopCount / loopsPerSecond)/60;
m=(minutes%d);
return m;
}
unsigned long Trip::timeH() {//return hour;
byte d=999;
byte h =0;
unsigned long hours = (loopCount / loopsPerSecond)/3600;
h=(hours%d);
return h;
}
void Trip::reset() {
loopCount = 0;
injPulses = 0;
injHius = 0;
injHiSec = 0;
vssPulses = 0;
vssPulseLength = 0;
injIdleHiSec = 0;
injIdleHius = 0;
vssEOCPulses = 0;
}
void Trip::update(Trip t) {
loopCount++; //we call update once per loop
vssPulses += t.vssPulses;
vssPulseLength += t.vssPulseLength;
if (t.injPulses == 0) //track distance traveled with engine off
vssEOCPulses += t.vssPulses;
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 gallons spent sitting still
injIdleHius += t.injHius;
if (injIdleHius >= 1000000) { //r
injIdleHiSec++;
injIdleHius -= 1000000;
}
}
}
}
//the standard 64 bit math brings in 5000+ bytes
//these bring in 1214 bytes, and everything is pass 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);
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
return 1;
#endif
byte b = eeprom_read_byte((unsigned char *) 0);
byte c = eeprom_read_byte((unsigned char *) 1);
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;
}
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 editParm(byte parmIdx) {
unsigned long v = parms[parmIdx];
byte p = 9; //right end of 10 digit number
//display label on top line
//set cursor visible
//set pos = 0
//display v
LCD::gotoXY(8, 0);
LCD::print(" ");
LCD::gotoXY(0, 0);
LCD::print(parmLabels[parmIdx]);
LCD::gotoXY(0, 1);
char * fmtv = uformat(v);
LCD::print(fmtv);
LCD::print(" OK XX");
LCD::LcdCommandWrite(0b00001110);
#ifdef cursor_first_nonzero_digit
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;
}
#else
// cursor on the OK
p=10;
#endif
byte keyLock = 1;
while (true) {
if (p < 10)
LCD::gotoXY(p, 1);
if (p == 10)
LCD::gotoXY(11, 1);
if (p == 11)
LCD::gotoXY(14, 1);
if (keyLock == 0) {
if (!(buttonState & lbuttonBit) && !(buttonState & rbuttonBit)) {// left & right
LCD::LcdCommandWrite(0b00001100);
return;
} else if (!(buttonState & lbuttonBit)) {// left
p = p - 1;
if (p == 255)
p = 11;
} else if (!(buttonState & rbuttonBit)) {// right
p = p + 1;
if (p == 12)
p = 0;
} else if (!(buttonState & mbuttonBit)) {// middle
if (p == 11) { //cancel selected
LCD::LcdCommandWrite(0b00001100);
return;
}
if (p == 10) { //ok selected
LCD::LcdCommandWrite(0b00001100);
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;
LCD::gotoXY(0, 1);
LCD::print(fmtv);
LCD::gotoXY(p, 1);
if (parmIdx == contrastIdx)//adjust contrast dynamically
OCR0A = rformat(fmtv);
// analogWrite(ContrastPin,rformat(fmtv));
}
if (buttonState != buttonsUp)
keyLock = 1;
} else {
keyLock = 0;
}
buttonState = buttonsUp;
delay2(125);
}
}
void initGuino() { //edit all the parameters
for (int x = 0; x < parmsLength; x++)
editParm(x);
save();
injectorSettleTime = injhold;
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);
distancefactor = parms[vssPulsesPerMileIdx];
fuelfactor = parms[microSecondsPerGallonIdx];
fuelfactor = (fuelfactor * 3.78541178);
tmpDRL =parms[drlIdx];
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)
;
}
/* Delay for the given number of microseconds. Assumes a 16 MHz clock.
* Disables interrupts, which will disrupt the millis2() function if used
* too frequently. */
void delayMicroseconds2(unsigned int us) {
uint8_t oldSREG;
if (--us == 0)
return;
us <<= 2;
us -= 2;
oldSREG = SREG;
cli();
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
// reenable interrupts.
SREG = oldSREG;
}
void simpletx(char * string) {
if (UCSR0B != (1 << TXEN0)) { //do we need to init the uart?
UBRR0H = (unsigned char) (myubbr >> 8);
UBRR0L = (unsigned char) myubbr;
UCSR0B = (1 << TXEN0);//Enable transmitter
UCSR0C = (3 << UCSZ00);//N81
}
while (*string) {
while (!(UCSR0A & (1 << UDRE0)))
;
UDR0 = *string++; //send the data
}
}
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;
}
Z tego kodu rozumiem że odczyt jest brany z pinu 2, który jest domyślnie wyłączony tzn 0v - low i odświeżanie na pinie to 1 sekunda, co akurat jest chyba blede powinno być 5 a nie 1000ms bo czasem wtryski sa tak krótkie
Dalej juz mało trybie. Sa przyciski / zmiany wyświetlanych rzeczy na LCD, funkcję które akurat mi sa nie potrzebne na chwile obecną. Moge ewentualnie podlaczyć LCD 4x20 i wtedy wszystkie dane wrzucic na lcd.
RE: Chwilowe spalanie benzyny + komp pokladowy - Smaczek - 17-12-2016
Witam,
Nie będę analizować czyjegoś kodu, zwłaszcza, że jest to trochę linijek.
Sygnał na kontroler możesz spróbować pobrać na dwa sposoby:
- tak jak najprawdopodobniej zamierzałeś, czyli podłączyć stabilizator napięcia pod oba złącza wtryskiwacza lub, jeśli napięcie ma stałą wartość, poprzez dzielnik napięcia na dwóch rezystorach,
- tylko do złącza, które jest "masowane" i tu, jak wcześniej napisałem, najlepiej zrobić na tranzystorze (układ- tranzystor jako przełącznik stanów logicznych). Kolektor przez rezystor do 5 V i wyjście z kolektora, a baza przez rezystor do "masowania" wtryskiwacza. Dla tranzystora pnp gdy końcówka wtryskiwacza będzie "wisieć w powietrzu" to nie będzie on przewodzić i na wyjściu będzie 5 V, a podłączenie do masy spowoduje stan niski na wyjściu.
Algorytm pomiaru:
- wyzerowanie sumarycznego czasu,
- odczytujemy wartość dla funkcji millis() i zapisujemy jej wartość do zmiennej start,
- włączamy przerwania,
- zmiana stanu rozpoczyna pomiar czasu (ponownie odczytujemy wartość millis()),
- kolejna zmiana stanu, ponowne odczytanie millis(),
- obliczenie różnicy odczytanych czasów i dodanie go czasu sumarycznego,
- sprawdzenie czy ostatni odczyt czasu różni się od wartości zmiennej start więcej nić 1000 (1 s), a jeśli tak wyłączenie przerwań. Jeśli nie, oczekiwanie na kolejną zmianę stanu,
- obliczenie spalania i zaś wszystko od początku.
Dla większej dokładności lepiej liczyć czas pomiędzy wtryskami, a na końcu odjąć go od 1 sekundy.
Pozdrawiam.
RE: Chwilowe spalanie benzyny + komp pokladowy - Kuter_tm - 29-12-2016
Witam
Dzis ukończyem obudowe i zamontowałem wszystko w samochodzie. Niestety pokazuje mi glupoty. Jak na podencjometrach chodziło dobrze tak teraz jakies dziwne wartości pokazuja mi sie w napięciu.
Zrobiłem dzielnik napiecia i z pomiarów wynika że dla 9V napiecie wyjsciowe to 1,86 dla 12V 2,54 więc dla każdego volta liniowo rośnie o 0,228V tzn. na wejsciu arduino A2. mam teraz napisane tak
setup
float odczytV;
loop
odczytV= analogRead (A2)*5/1023.00*0.228+10;
lcd.setCursor(3,1);
lcd.print(odczytV);
i pokazuje mi jakies brednie. Jak zmienie na
odczytV= analogRead (A2)*5/1023.00;
pokazuje napiecie takie jak pisalem wyżej. Gdy na wejscu arduino nap. wzrosnie o 0,228 to lcd pokazuje 1V wiecej. Chce zrobic pomiar dla aku w wartościach od 10 do 20V
O ile dla afr funkcja F(x) sie sprawdziła tak tu nie idzie... a niby rosnie liniowo
|