Forum: Compiler & IDEs ATmega 168 wie Kennlinie ablegen


von peter (Gast)


Lesenswert?

Hallo Forum

Hab schon die suche bemüht leider konnte ich bzgl. lookup tables nix 
beriedigendes finden
Bin gerade dabei ein einfaches Zündungsstuergerät zu programmieren.
Drehzahlerassung und erkennung des ot laufen schon soweit
nun möchte ich im 1. schritt anhand der drehzahl einen zündwinkel 
ausgeben. Sprich eine Kennlinie in der steht bei der und der Drehzahl so 
der und der Zündwinkel ausgegeben werden.
Wie kann ich das am einfachsten in C realisieren? Gibts dann auch 
möglichkeit zischen den stützstellen zu interpolieren??

Danke ür Eure Antworten

von PCler (Gast)


Lesenswert?

Also wenn Du einen passenden Lookuptable mit Stützstellen schon hast und 
die Funktion dazu, wo liegt dann Dein Problem ?
Oder müssen es Floats sein ?

von Karl heinz B. (kbucheg)


Lesenswert?

peter wrote:
> nun möchte ich im 1. schritt anhand der drehzahl einen zündwinkel
> ausgeben. Sprich eine Kennlinie in der steht bei der und der Drehzahl so
> der und der Zündwinkel ausgegeben werden.

> Gibts dann auch
> möglichkeit zischen den stützstellen zu interpolieren??

Sicher. Ich denke mal lineare Interpolation würde durchaus
ausreichen.

> Wie kann ich das am einfachsten in C realisieren?

Am einfachsten ist es, wenn du den Zündwinkel für Drehzahlen
in einem bestimmten Raster vorgibst. Sagen wir mal für alle
Vielfachen von 500 U/min hast du einen Zündwinkel.

Dann brauchst du noch ein Array, in dem für alle diese Drehzahlen
der zugehörige Zündwinkel abgelegt ist.

uint8_t Winkel[] = {
      80,      /*    0 U/min */
      82,      /*  500       */
      82,      /* 1000       */
      85,      /* 1500       */
      87,      /* 2000       */
      ....
  }

Und dann brauchst du jetzt natürlich noch eine Formel, die
dir, ausgehend von einer bestimmten Drehzahl ausrechnet, an
welcher Stelle im Array der zugehörige Wert zu finden ist.

Könnte zb so aussehen:

   uint16_t Drehzahl;
   uint8_t Index;

   ..... irgendwie kommst du zu deiner Drehzahl

   /* die rechnen wir um in einen Index in die Winkel-Tabelle: */

   Index = Drehzahl / 500;
   einzustellender_Winkel = Winkel[ Index ];

mit dieser einfachen Berechnung kriegst du für Drehzahlen
    0 bis  499    Winkel[0]
  500 bis  999    Winkel[1]
 1000 bis 1499    Winkel[2]
 1500 bis 1999    Winkel[3]
   ....

Wenn dir eine Abstufung von 500 U/min nicht reicht, kannst
du natürlich auch feiner unterteilen.

von Karl heinz B. (kbucheg)


Lesenswert?

PCler wrote:
> Also wenn Du einen passenden Lookuptable mit Stützstellen schon hast und
> die Funktion dazu, wo liegt dann Dein Problem ?

An den mangelnden C-Kenntnissen, bzw Fantasie diese
auch einzusetzen :-)
Es ist schon erstaunlich, mit wie wenig Wissen sich viele
an eine Programmieraufgabe heranwagen.

von PCler (Gast)


Lesenswert?

@ Karl heinz Buchegger:
An sowas hätt' ich nie im Leben gedacht ;)
BTW sollte Heinz nicht auch mit'm großen "H" anfangen ;)
Ist mir nur gerade beim Kopieren aufgefallen ;)
Dein C-Programm ist OK aber solltest Du nicht "krumme" Werte mit einem 
Modulo o.ä. abfangen ?
Sonst kann's haarig werden mit Index = 2,34568 und int8_t ;)
Oder wird automatisch in int8_t umgewandelt ?

von peter (Gast)


Lesenswert?

Hallo

Danke erst mal für die schnellen Antorten


>@Karl heinz Buchegger
>mit dieser einfachen Berechnung kriegst du für Drehzahlen


>   0 bis  499    Winkel[0]
>  500 bis  999    Winkel[1]
> 1000 bis 1499    Winkel[2]
> 1500 bis 1999    Winkel[3]


Das muss ich ja dann mit lauter if oder case abfragen realisieren oder 
gibts da eine elegantere methode?

Sorry für die villeicht banalen fragen aber irgendwie muss man halt 
erfahrungen sammeln :-)


von Marcus (Gast)


Lesenswert?

Wieso if oder case?

Karl Heinz hat dir doch schon beschrieben wir das geht! Du ermittelst 
deine Drehzahl, mithilfe einer Ganzzahldivision erhälst du den Index für 
die LUT. Schau noch mal in dem Post von 20:35 Uhr nach.

Marcus

von peter (Gast)


Lesenswert?

Sorry habs beim 1 mal durchlesen ned gecheckt.


> Index = Drehzahl / 500;


Was würd jezt aber passieren wenn Drehzahl zb 700 ist, Index währ ja 
dann 1,4 also würde ja abgerundet. Wie kann ich dann zwischen 2 
stüzstellen interpolieren??

von Karl H. (kbuchegg)


Lesenswert?

PCler wrote:
> Sonst kann's haarig werden mit Index = 2,34568 und int8_t ;)
> Oder wird automatisch in int8_t umgewandelt ?

Da ist alles Ganzzahl. 1350 / 500 ergibt 2


von PCler (Gast)


Lesenswert?

Das meinte ich mit "krumme" Werte ;)
Ich bin gemein ich weiß ;)

von Karl H. (kbuchegg)


Lesenswert?

peter wrote:
> Sorry habs beim 1 mal durchlesen ned gecheckt.
>
>
>> Index = Drehzahl / 500;
>
>
> Was würd jezt aber passieren wenn Drehzahl zb 700 ist, Index währ ja
> dann 1,4 also würde ja abgerundet. Wie kann ich dann zwischen 2
> stüzstellen interpolieren??

indem du zwischen dem Wert kleiner (diesen Index kriegst du
aus der Division) und dem Wert grösser (das ist dann Index + 1)
interpolierst.

Also: gemessene Drehzahl 1300
  Index = 1300 / 500 -> 2

  Wert[2] -> 82
  Wert[3] -> 85

Und jetzt wird zwischen den beiden Interpoliert.

  2 * 500 -> 1000

  1300 - 1000 -> 300

  ( 85 - 82 ) * 300 / 500 -> 1.8   als Ganzzahl 1

  82 + 1 -> 83


Die Mathe dazu jetzt herzuleiten ist mir ehrlich zu mühselig
auch wenns trivial ist.


von Karl H. (kbuchegg)


Lesenswert?

PCler wrote:
> Das meinte ich mit "krumme" Werte ;)
> Ich bin gemein ich weiß ;)

Nicht wirklich :-)
Die Interpolation ist trivial.

Ich würds aber trotzdem nicht so machen:
Ein Motormanagement sollte wohl so schnell wie
möcglich auf veränderte Drehzahlen reagieren.
Wenn 500 U/min Auflösung nicht reichen, dann geh
ich halt runter auf 100 oder 50. Die Tabelle im Excel
aufstellen, geht wohl schneller als wenn der µC sich
da durch Divisionen durchquälen muss.

von PCler (Gast)


Lesenswert?

@ Karl heinz Buchegger:
Bist Du Dir wirklich sicher das uint8_t var = 1300 / 500 ZWEI ergeben ?
Weil da kommt ja eigentlich 2,6 heraus ??
Sorry aber in "normalem" C kracht das ziemlich !
Außer Du nimmst uint8_t var = (uint8_t) 1300 / 500 ...
Oder steh' ich gerade auf'm Schlauch ?

von Karl H. (kbuchegg)


Lesenswert?

> Bist Du Dir wirklich sicher das uint8_t var = 1300 / 500 ZWEI ergeben ?

Ja, ich bin mir absolut sicher

> Weil da kommt ja eigentlich 2,6 heraus ??

Nicht wirklich.
1300 ist ein int. 500 ist ein int. Also wird die Division
als int-Division ausgeführt. Und das ergibt nun mal 2.

> Sorry aber in "normalem" C kracht das ziemlich !

Äh. Nein. So sind die C-Regeln. Das ist schon seit
Zeiten von K&R so (also seit den 60-er Jahren).

> Außer Du nimmst uint8_t var = (uint8_t) 1300 / 500 ...

Das ändert überhaupt nichts. Ist nach wie vor eine int Division.


Ah. OK
Ich hätte vielleicht dazu schreiben sollen, dass Zahlen
ohne einen Kommapunkt bei mir immer int sind. Wenn ich
eine Kommazahl haben will schreibe ich immer einen Dezimalpunkt:

   1300.0 / 500.0

ist daher was anderes als

   1300 / 500


Klärt das das Missverständniss auf?

von PCler (Gast)


Lesenswert?

@All:
Sorry, hab's gerade selbst nachgesehen:
http://www.csee.usf.edu/~eschrich/cis4930/faq/intdivision.html
Also Karl-Heinz hat recht ;)
Ich muß wohl irgendwie was verwechselt haben ;)
Wobei es ja heißt das iterative Sprachen immer ineinander übersetzt 
werden können ...
Aber wie heißt es So schön:
C:
1
Shoot urself in the foot.
PENG

Pascal:
The compiler wont let u shoot urself in the foot.

Sorry,
PCler

von Karl H. (kbuchegg)


Lesenswert?

> C
> Pascal

Aaaah. Jetzt weiss ich woher der Wind weht :-)

In Pascal ist das anders. Stimmt.

von Karl H. (kbuchegg)


Lesenswert?

>
>   ( 85 - 82 ) * 300 / 500 -> 1.8   als Ganzzahl 1
>
>   82 + 1 -> 83
>

Wenn du die 1.8 gerundet haben möchtest, dann musst
du noch eine Rundungskorrektur anbringen.

 ( ( 85 - 82 ) * 300 + 250 ) / 500


Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.