Skocz do zawartości

Wyświetlanie danych na LCD zakłóca inną funkcję


Vel0

Pomocna odpowiedź

Zbudowałem układ na bazie Arduino Uno, który ma za zadanie:

1. Odczytać prędkość z samochodowego czujnika prędkości (VSS).
2. Zmodyfikować ten sygnał (przeskalować w górę lub w dół o jakąś wartość).
3. Wyświetlić na LCD prędkość (po modyfikacji).
4. Dodatkowo stworzyłem funkcję symulującą odczyt z VSS, żebym mógł łatwo testować w domu bez potrzeby angażowania auta do testów.

I generalnie wszystko działa, z tym że występują jakieś zakłócenia gdy wyświetlam dane na LCD. W momencie odświeżania wyświetlacza występuje impuls który zakłóca sygnał wyjściowy do prędkościomierza co skutkuje skakaniem wskazówki. Jest jakiś konflikt z przerwaniem które wykorzystuje przy modyfikacji sygnału prędkości.

Potrzebuję porady jak rozwiązać ten konflikt. Bez wyświetlania danych na LCD wszystko działa wzorowo.

Konfiguracja w Setup:

void setup() {
  pinMode (13, OUTPUT);                    
  pinMode(speedometerPin, OUTPUT);    
  pinMode(sensorPin, INPUT);                 
  digitalWrite (sensorPin, HIGH);             
  attachInterrupt (1, iSr, FALLING); 
}

Kod odpowiedzialny za wyświetlanie danych na LCD, zakłócenia występują dokładnie co wartość LCDRefreshTime :

LCDRefreshTime = 1000; // milliseconds
void DisplayData () {
  LCDTime = millis();
  if (LCDTime - LCDSavedTime >= LCDRefreshTime) {
     LCDSavedTime = LCDTime;
     lcd.clear();
     lcd.setCursor(0, 0); 
     lcd.print("Speed: " + (String) RoundedKMH + " KM/h"); 
     lcd.setCursor(0, 1);
     lcd.print("Pulses: " + (String) PulseCount + " imp"); 
  } 
}

A tutaj kod odpowiedzialny za przeskalowanie sygnału wyjściowego który wysyła pulsy na licznik:
Kod zapożyczony stąd: https://members.rennlist.com/tom86951/Speedometer Calibrator Page1.html

void ReCalibrateSpeedometer() {
  noInterrupts();                                               
  modInterval=interval;                                    
  interrupts();                                                      
  currentMicros = micros();                             
  if (currentMicros-previousSpeed<1000000) {
	if (currentMicros - previousMicros>((modInterval/2)/calFactor)) { 
	  previousMicros = currentMicros;                                                    
	  if (pulseState == LOW) pulseState = HIGH; else pulseState = LOW;
	    digitalWrite(13, pulseState);         //blink onboard LED                                                         
		digitalWrite(speedometerPin, pulseState);
	}                                  
  }   
}

void iSr() {
  currentSpeed = micros();               
  if (digitalRead(sensorPin) == LOW) {
    if ((currentSpeed - previousSpeed) > debounce) {
        interval = currentSpeed - previousSpeed;      
        previousSpeed = currentSpeed;                       
    }
  }
}
Link do komentarza
Share on other sites

Ale ten program faktycznie działa na przerwaniach (od timera albo zbocza), czy to skrót myślowy?

Zakładam że chodzi o popularny lcd hd44780?

Wyświetlanie na LCD to baaardzoooo długi proces jak dla kontrolera. Jeżeli dodatkowo nie używany jest sygnał BUSY i masz jakiegoś bezpiecznego delaya, to cała rekalibracja zatrzymuje się na dziesiątki milisekund i wszystko się psuje.

Musiałbyś rekalibrować prędkość w prawdziwym przerwaniu i wyświetlać w pętli głównej. Dodatkowo jakaś synchronizacja, żeby wartości nie zmieniały się podczas wyświetlania.

  • Lubię! 1
Link do komentarza
Share on other sites

40 minut temu, kostuch napisał:

Ale ten program faktycznie działa na przerwaniach (od timera albo zbocza), czy to skrót myślowy?

Zakładam że chodzi o popularny lcd hd44780?

Wyświetlanie na LCD to baaardzoooo długi proces jak dla kontrolera. Jeżeli dodatkowo nie używany jest sygnał BUSY i masz jakiegoś bezpiecznego delaya, to cała rekalibracja zatrzymuje się na dziesiątki milisekund i wszystko się psuje.

Musiałbyś rekalibrować prędkość w prawdziwym przerwaniu i wyświetlać w pętli głównej. Dodatkowo jakaś synchronizacja, żeby wartości nie zmieniały się podczas wyświetlania.

Jeśli dobrze rozumiem kod odpowiedzialny za rekalibrację (to nie mój kod) to ta funkcja działa na przerwaniu (zbocze opadające): attachInterrupt (1, iSr, FALLING);

LCD to hd44780 sterowany przez i2c, ale sprawdzałem też podłączenie bez i2c i nic to nie zmienia. Wykorzystuję bibliotekę LiquidCrystal.

Co do delaya - tutaj właśnie problem, że żadnego delay nie używam, wszędzie stosuję funkcję millis() i micros() aby nie zatrzymywać nigdzie programu.

Wyświetlanie danych DisplayData() i rekalibracja ReCalibrateSpeedometer() odbywa się w pętli głównej.

Link do komentarza
Share on other sites

Zamiast czyścić za każdym razem ekran aktualizuj tylko wartość zmiennej na wybranych pozycjach 

Ad2 jeśli impulsy pochodzą z transoptora, tj nie z mechanicznego styku to nie potrzebujesz debiuncungu. 

Ad3 mikrokontrolery posiadają liczniki sprzętowe myślę że jest opcja aby z nich skorzystać

Edytowano przez _LM_
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

16 minut temu, Vel0 napisał:

Co do delaya - tutaj właśnie problem, że żadnego delay nie używam, wszędzie stosuję funkcję millis() i micros() aby nie zatrzymywać nigdzie programu.
 

Ty nie, a biblioteka? I2C też nie jest demonem prędkości.

Napisz jakiś prosty kod, który zmierzy ile us/ms zajmuje wyświetlenie na LCD tego co chcesz pokazać.

Link do komentarza
Share on other sites

21 minut temu, Vel0 napisał:

Jeśli dobrze rozumiem kod odpowiedzialny za rekalibrację (to nie mój kod) to ta funkcja działa na przerwaniu (zbocze opadające): attachInterrupt (1, iSr, FALLING);
 

Tak na szybko jeszcze

Jeżeli funkcja iSr() jest wywoływana przy opadającym zboczu, to po co tam warunek:

if (digitalRead(sensorPin) == LOW)

Jak zbocze opadło, to jest LOW 🙂

Straszny ten kod...

  • Lubię! 2
Link do komentarza
Share on other sites

12 minut temu, kostuch napisał:

Straszny ten kod...

pełna zgoda 🙂 

isr()
{
  currentSpeed = micros();
  interval = currentSpeed - prev;
  prev = micros();
}

z palca napisane, choć ja zrobiłbym to na sprzęcie

Edytowano przez _LM_
  • Lubię! 1
Link do komentarza
Share on other sites

@_LM_ @kostuch Dzięki, faktycznie kod w iSr był bez sensu. Ale jego uproszczenie nic nie zmieniło 😉
 

1 godzinę temu, kostuch napisał:

Napisz jakiś prosty kod, który zmierzy ile us/ms zajmuje wyświetlenie na LCD tego co chcesz pokazać.

Wywołanie funkcji wyświetlania danych zajmuje między 4 a 12 us.

T1 = micros(); 
DisplayData();
T2 = micros(); 
T1S = T2-T1;  

Taka wartość nie powinna mieć żadnego wpływu na ruch wskazówki, biorąc pod uwagę że pulsy co około 30000us = ~20 km/h, a 3000us = ~200km/h.

Ale już sama operacja w pętli:

void DisplayData () {
  LCDTime = millis();
  if (LCDTime - LCDSavedTime >= LCDRefreshTime) {
     T1 = micros();
     LCDSavedTime = LCDTime;
     lcd.clear();
     lcd.setCursor(0, 0); 
     lcd.print("Speed: " + (String) RoundedKMH + " KM/h"); 
     lcd.setCursor(0, 1);
     lcd.print("Pulses: " + (String) T1S + " imp"); 
     T2 = micros();  
     T1S = T2-T1; 
  } 
}

To około 11-13ms i taka wartość to faktycznie już może mieć wpływ na sygnał, tym bardziej że po przeanalizowaniu biblioteki LiquidCrystal faktycznie jest tam kilka razy wykorzystany delay() i delaymicrosecond().

Poszukam jakiejś innej biblioteki, ale coś czuję że prędzej przerobię to wykorzystując Timer sprzętowy jak sugeruje LM.
 

  • Lubię! 1
Link do komentarza
Share on other sites

Spróbuj jeszcze tego co pisałem wyżej też 

2 godziny temu, _LM_ napisał:

Zamiast czyścić za każdym razem ekran aktualizuj tylko wartość zmiennej na wybranych pozycjach 

Bo na pewno nie musisz czyścić całego wyświetlacza 

A i jeszcze jedna rzecz chyba najważniejsza: kiedy robisz odczyt zmiennej w main, może się zdarzyć że w tym momencie wpadnie przerwanie, nie będę tego tłumaczył tutaj, ale jest to typowy przykład kiedy połowa zmiennej może zostać nadpisana podczas trwania przerwania. W tym celu stosuje się dostęp atomowy, poszukaj ATOMIC_BLOCK i jak się go używa. Bo czuję po kościach że w tym miejscu jest problem. 

Edytowano przez _LM_
Link do komentarza
Share on other sites

Przed chwilą, _LM_ napisał:

Spróbuj jeszcze tego co pisałem wyżej też 

Bo na pewno nie musisz czyścić całego wyświetlacza 

Sprawdziłem to jako pierwsze i nie ma to żadnego wpływu. Zakłócenie występuje nawet jak w funkcji DisplayData() zostawię tylko lcd.print("Test: "); bez żadnego czyszczenia i przestawiania kursora.

Link do komentarza
Share on other sites

Ja w ogóle widzę coś dziwnego.

Z tego co wynika z kodu (szkoda że niekompletnego), dostarczasz sygnał na wejscie Arduino, i kopiujesz go na wyjście, do którego podłączony jest prędkościomierz.

Trochę się takimi układami bawiłem (motocykl), ale ja po prostu podłączałem wejście do linii czujnik - prędkościomierz. Arduino (czy potem RPi Pico) zajmował się swoimi sprawami (np. sterowaniem olejarką), a prędkościomierz (taki chiński kolorowy) działał niezależnie.

Może coś w tę stronę?

  • Lubię! 1
Link do komentarza
Share on other sites

3 minuty temu, ethanak napisał:

Ja w ogóle widzę coś dziwnego.

Z tego co wynika z kodu (szkoda że niekompletnego), dostarczasz sygnał na wejscie Arduino, i kopiujesz go na wyjście, do którego podłączony jest prędkościomierz.

Trochę się takimi układami bawiłem (motocykl), ale ja po prostu podłączałem wejście do linii czujnik - prędkościomierz. Arduino (czy potem RPi Pico) zajmował się swoimi sprawami (np. sterowaniem olejarką), a prędkościomierz (taki chiński kolorowy) działał niezależnie.

Może coś w tę stronę?

Sygnał z linii czujnik-prędkościomierz muszę zmodyfikować bo licznik przekłamuje o kilkanaście procent (100km/h wg GPS = 120km/h na liczniku) dlatego przepuszczam go przez mikrokontroler. A jak już to robię to przy okazji tej całej zabawy chcę wyświetlić kilka parametrów na wyświetlaczu który będzie na desce (taki mini komputer pokładowy).

Link do komentarza
Share on other sites

17 godzin temu, Vel0 napisał:

zakłóca sygnał wyjściowy do prędkościomierza co skutkuje skakaniem wskazówki

Na drogi raczej nie powinno takie coś wyjeżdżać. W sensie modyfikowane czymkolwiek po drodze.

Edytowano przez matsobdev
Link do komentarza
Share on other sites

1 minutę temu, Vel0 napisał:

Sygnał z linii czujnik-prędkościomierz muszę zmodyfikować bo licznik przekłamuje o kilkanaście procent (100km/h wg GPS = 120km/h na liczniku)

Zależy co za samochód, to w ustawianiach ABS itp. czy ogólnie BSI będzie można zakodować rozmiar kół (felg, opon). 5 km/h rozumiem, to jest zawsze, ale coś jest nie tak.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.