• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Niedokładność pomiarowa - problem z odczytywaniem impulsow
#21
(14-08-2018, 20:00)qbic napisał(a): Zainteresowałem się Arduino, ponieważ wszystko na tej platformie wydawało się łatwiejsze - gotowe funkcje, biblioteki, dostępność materiałów.
Arduino to jak Windows. Każde zadanie z osobna realizuje poprawnie, kilka juz nie. To oczywiście wina bibliotek a nie uC.

(14-08-2018, 20:00)qbic napisał(a): Chętnie dowiem się więcej o warstwie sprzętowej (?) Arduino i mikrokontrolerów ogolnie
W EdW jest aktualnie kurs Arduino i C na AVR. W poprzednich latach był wyły kursy AVR. W BTC sa książki o AVR.
 
Odpowiedź
#22
Możesz spokojnie dalej zliczać długość impulsu wtryskiwaczy korzystając z funkcji millis lub bardziej micros. Robiąc sprzętowo pomiar drogi procek i tak nie ma już obciążenia w pętli głównej. Korzystając z Arduino zrobisz lepszy komputer pokładowy niż jest w nowych samochodach, narzekaniem się nie przejmuj. W starym autku miałem bardzo responsywny wskaźnik spalania chwilowego i średniego w X.Xl/km. W nowym na hiper-zajebistym ekranie pokazują mi się jedynie słupki z informacją cyfrową jedynie o aktualnym średnim spalaniu aktualizowanym co 10s, chwilowe jest w postaci burgrafa z którego można się domyślać wartości 5,10,20,30. Trzeba pamiętać o resecie parametrów w kilku punktach po tankowaniu, inaczej może nas spotkać niespodzianka, jak ktoś lubi stać rzadko na stacji paliw.
Arduino i tak jest lepsze na początek niż cokolwiek wymyślone do tej pory dla amatorów. Pan ES2 zajmuje się elektroniką od przed wojny i robi to zawodowo. Oczywiście musi mieć inne podejście, bo robi to komercyjnie. Jak Twój komputer wyliczy błędnie spalanie to będziesz wiedział dlaczego i pretensjami go nie zajeździsz. Sam starając się zrobić wszystko na 100% możesz nie zrobić tego nigdy, a tak jutro możesz zacząć testować aktualną wersję i ewentualnie rozpocząć pracę nad lepszą.
Pewnie będzie jakiś błąd, pojeździsz, popatrzysz, wprowadzisz korekty. To i tak jest konieczne, bo przecież nie wiesz jak ma się suma długości wtrysku/s do rzeczywistej ilości paliwa, zrobisz sobie jedną trasę, skalibrujesz i powinno działać OK.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#23
(14-08-2018, 20:56)kaczakat napisał(a): Pan ES2 zajmuje się elektroniką od przed wojny i robi to zawodowo.

Przed wojną (1981) miałem 8 lat, elektroniką się nie zajmowałem ale lutownicą transformatorową potrafiłem się posługiwać.
Zawodowo, zajmuje się dość krótko, bo od 2002roku amatorsko tak od 1985..87.
 
Odpowiedź
#24
Kodu jeszcze nie zamieściłem ponieważ stwierdziłem ze najpierw zaznajomie się lepiej z tematem przerwań i timerow.
Wtedy sprobuje napisac program z ich wykorzystaniem.
Jednoczenie nie chciałbym by temat został zamknięty, kod zamieszczę kiedy go dopracuje. Warto żeby ktoś z doświadczeniem ma niego spojrzał Smile
 
Odpowiedź
#25
(16-08-2018, 20:39)qbic napisał(a): kod zamieszczę kiedy go dopracuje. Warto żeby ktoś z doświadczeniem ma niego spojrzał Smile
Zamieś, przyda się innym.
 
Odpowiedź
#26
W takim razie zamieszczam:

Kod:
#include <LiquidCrystal.h>
#include <Timers.h>

//lcd and timer objects declaration
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
Timers <4> timer;

//variables for calculating speed
volatile uint16_t impulsCounter = 0;
uint64_t overallImpulsCounter = 0;
uint16_t impulsesPerMeter = 1685;

//variables for calculating fuel comsumption
uint16_t injectorImpulsLength = 0;
uint16_t maxFuelConsumption = 3724; //max fuel cons. equals 37,24 [l/h], this value is multiplied by 100

//variables for calculating distance
uint32_t distanceMeters = 0;
uint8_t distanceHundretMeters = 0;
uint32_t distanceKilometers = 0;


void setup() {
 Serial.begin(9600);

 //pins declaration
 pinMode(2, INPUT_PULLUP); //speedometer impulsator pin
 pinMode(3, INPUT_PULLUP); //injectors impulses pin

 //start screen
 lcd.begin(16,2);
 lcd.setCursor(0,0);
 lcd.print("ASTRA F    X14XE");
 delay(3000);
 lcd.clear();

 //global interrupts
 attachInterrupt(digitalPinToInterrupt(2), speedImpulsIncrement, FALLING);

 //threads  
 timer.attach(0,1,measureInjectorImpuls);
 timer.attach(1,500,calculateSpeedAndFuelConsumption);
 timer.attach(2,1,calculateDistance);
 timer.attach(3,1000,displayDistance);
}


//measurment methods
void speedImpulsIncrement() {
 impulsCounter++;
}

void measureInjectorImpuls() {
 if(digitalRead(3) == LOW)
   injectorImpulsLength++;
}

//calculating methods
void calculateSpeedAndFuelConsumption() {
 uint8_t speedOfVehicle = 0;
 
 bool motion = false;
 uint8_t consumptionPerHour = 0;
 uint8_t consumptionPerHour_point = 0;
 uint8_t consumptionPer100KM = 0;
 uint8_t consumptionPer100KM_point = 0;

 Serial.print(injectorImpulsLength);
 Serial.print(" ms\t");
 
 noInterrupts();
 //calculating speed
 speedOfVehicle = impulsCounter * 720 / impulsesPerMeter; //km/h
 overallImpulsCounter += impulsCounter;
 impulsCounter = 0;

 //calculating fuel consumption
 consumptionPerHour = maxFuelConsumption * injectorImpulsLength / 5000;
 consumptionPer100KM = consumptionPerHour * 100 / speedOfVehicle;
 injectorImpulsLength = 0;
 interrupts();

 Serial.print(speedOfVehicle);
 Serial.print(" km/h\t");
 
 consumptionPerHour_point = consumptionPerHour % 10;
 consumptionPerHour = consumptionPerHour / 10;
 
 consumptionPer100KM_point = consumptionPer100KM % 10;
 consumptionPer100KM = consumptionPer100KM / 10;
   
 if(speedOfVehicle <= 1) {
   motion = false;
   displayFuelConsumption(motion, consumptionPerHour, consumptionPerHour_point);
 } else {
   motion = true;
   displayFuelConsumption(motion, consumptionPer100KM, consumptionPer100KM_point);
 }
 
 displaySpeed(speedOfVehicle);
 
}

void calculateDistance() {
 distanceMeters = overallImpulsCounter * 100 / impulsesPerMeter;
 distanceHundretMeters = overallImpulsCounter / impulsesPerMeter;
 distanceHundretMeters = distanceHundretMeters % 10;
 distanceKilometers = overallImpulsCounter / (impulsesPerMeter * 10);

 if(distanceKilometers >= 1) {
   timer.updateInterval(1,5000); //calculateDistance interval
   timer.updateInterval(2,5000); //displayDistance interval
 }  
}

void calculateFuelConsumption() {
 
 
}

//displaying methods
void displaySpeed(uint8_t speedOfVehicle) {
 clearLine(0);
 lcd.setCursor(0,0);
 lcd.print("SPEED:");

 if(speedOfVehicle < 10)
   lcd.setCursor(10,0);
 else if(speedOfVehicle >=10 && speedOfVehicle < 100)
   lcd.setCursor(9,0);
 else if(speedOfVehicle >=100 && speedOfVehicle < 1000)
   lcd.setCursor(8,0);  

 lcd.print(speedOfVehicle);
 lcd.print(" KM/H");
}

void displayDistance() {
 clearLine(1);
 lcd.setCursor(0,1);
 lcd.print("TRIP:");
 
 if(distanceHundretMeters == 0 && distanceKilometers == 0) {
   if(distanceMeters < 10)
     lcd.setCursor(13,1);
   else if(distanceMeters >=10 && distanceMeters < 100)
     lcd.setCursor(12,1);
   else if(distanceMeters >=100 && distanceMeters < 1000)
     lcd.setCursor(11,1);

   lcd.print(distanceMeters);
   lcd.print(" M");    
 }
 else {
   if(distanceKilometers < 10)
     lcd.setCursor(10,1);
   else if(distanceKilometers >=10 && distanceKilometers < 100)
     lcd.setCursor(9,1);
   else if(distanceKilometers >=100 && distanceKilometers < 1000)
     lcd.setCursor(8,1);
   else if(distanceKilometers >=1000 && distanceKilometers < 10000)
     lcd.setCursor(7,1);

    lcd.print(distanceKilometers);
    lcd.print(".");
    lcd.print(distanceHundretMeters);
    lcd.print(" KM");  
 }
}

void displayFuelConsumption(bool motion, uint8_t consumption, uint8_t consumption_point) {
 if(motion) {
   Serial.print("\t");
   Serial.print(consumption);
   Serial.print(".");
   Serial.print(consumption_point);
   Serial.println(" [l/100km]");
 } else {
   Serial.print("\t");
   Serial.print(consumption);
   Serial.print(".");
   Serial.print(consumption_point);
   Serial.println(" [l/h]");    
 }
}

void clearLine(uint8_t line) {
 lcd.setCursor(0,line);
 lcd.print("                ");
}


//loop method
void loop() {
 timer.process();

}


Mam nadzieje, że jest czytelny Smile
Pozbyłem się wszystkich zmiennych typu float, double. Prędkość zliczam za pomocą przerwań (działa bez zarzutu, mimo że używam funkcji wbudowanych arduino obsugujących przerwania).

Co do spalania, tak wiem, mało dokładnie zliczam czas trwania impulsow, jednak jest to wersja tymczasowa. Bardziej zastanawia mnie dlaczego walnie czasem bubla w stylu (fragment danych wychodzących -> injectorImpulsLength, speedOfVehicle, fuelConsumption) :

23 ms    9 km/h      4.4 [l/100km]
23 ms    10 km/h    4.0 [l/100km]
20 ms    10 km/h    1.0 [l/100km]
22 ms    10 km/h    3.0 [l/100km]
21 ms    11 km/h    1.8 [l/100km]
23 ms    11 km/h    3.6 [l/100km]

Jakby źle wykonywały się obliczenia?
 
Odpowiedź
#27
Funkcjami micros sprawdź czy czas trwania funkcji związanych z wyświetlaniem/drukowaniem na serial nie zakłóca pomiarów. Jeśli np. zliczasz przez pełne 0,5s 10 razy, a potem wyświetlasz, to w tej połówce sekundy liczenie możesz sobie odpuścić i założyć że jest takie jak wcześniejsze/późniejsze, średnia z nich.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#28
(17-08-2018, 20:35)kaczakat napisał(a): Funkcjami micros sprawdź czy czas trwania funkcji związanych z wyświetlaniem/drukowaniem na serial nie zakłóca pomiarów.

Skoro liczny na przerwaniach, dlaczego niby jakieś funkcje wywoływane z pętli głównej miałby zakłócać liczenie?
 
Odpowiedź
#29
Do użytkownika kaczakat:
Chciałbym żeby pomiar był jak najbardziej płynny (?), chciałbym uzyskać odświeżanie co około pół sekundy. W takim razie pomierze wszystko, a interwały sprobuje skrócić(np. 100ms, co piąty wyświetlanie na lcd/serial).

Do użytkownika es2:
Chodzi zapewne o funkcje związana z liczeniem długości impulsu wtryskiwaczy. Wykonuje się co 1 ms, wiec zakładam ze obciąża pętle główna. Przerwania obsługują pomiar impulsów prędkości. Do pomiaru długości impulsów wtryskiwaczy będę chciał zastosować timer.

Niestety podczas debugowania (czyli przejażdżki Smile) wczoraj wieczorem pękło mi łączenie wydechu z jednym z katalizatorów, wiec teraz mam jescze do rozwiązania problem natury mechanicznej.
 
Odpowiedź
#30
Rzadko oglądam długie kody źródłowe na tym forum, bo ich wyświetlanie jest niedopracowane jak Arduino (nie można wyświetlić całości kodu, nie można jednym kliknięciem zaznaczyć całości aby obejrzeć w edytorze tekstu, itd). Administratorzy powinni zajrzeć na Elektrodę, tam jest to zrobione bardzo dobrze.
Poświęciłem się i obejrzałem kod. Masz poważny błąd w idei jego działania. Czasochłonne operacje robisz na przerwaniach.
Kod:
//threads  
timer.attach(0,1,measureInjectorImpuls);
timer.attach(1,500,calculateSpeedAndFuelConsumption);
timer.attach(2,1,calculateDistance);
timer.attach(3,1000,displayDistance);
Nie ważne, że wyświetlanie jest wykonywane co sekundę, ważne, ze wykonuje się ponad 1ms. Biblioteki obsługi LCD dla Arduino sa tak kiepskie, że szkoda gadać. Przeważnie znajdziesz tam delay a to dyskwalifikuje ich użycie w przeraniach w tym przypadku. AVR nie ma wielopoziomowego systemu przerwań. Gdyby miał, to dla wyświetlania ustawiasz niski priorytet i po sprawie. Pseudo wielopoziomowość (w Arduino wszystko jest pseudo: pseudo debugowanie, pseudo wielopoziomowość) możesz uzyskać odpowiednio deklarując przerwania ale może być problem z USART.
Wywal czasochłonne operacje do pętli głównej. W niej, korzystając z millis np sekundę i wyświetlaj wyniki pomiarów.

ZAPAMIĘTAJ generalna zasadę "Przerwania powinny wykonywać się szybko". Są oczywiście pewne odstępstwa ale nie w tym przypadku.
W przerwaniu zliczaj więc impulsy, w przerwaniu co np sekundę przepisuj wynik zliczania do zmiennej dostępnej w programie głównym i przygotuj następny pomiar.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości