PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM-Signal messen



||kugelfisch
16.01.2009, 20:25
Nabend,
ich möchte in meinem Auto mittels des ATMEGA32 den Benzinverbauch messen. Dazu ist es nötig ein PWM-Signal auszuwerten. Die Länge des Signals wird sich im ms-Bereich bewegen (eine ms entspricht 26ul eingespritztem Kraftstoff). Ich habe leider kein Oszilloskop um das genau prüfen zu können.
Für die Berechnung brauche ich also den Zeitabstand von steigender zu fallender Flanke. Über die Suche bin ich zu folgender Verfahrensweise gelangt: per Input-Capture die steigende Flanke erkennen, zeitgleich Timer auslösen, dann per Input-Capture die fallende Flanke erkennen und den Timer stoppen/reseten. Die Differenz der beiden Timerwerte ergibt die Dauer des Impulses. Funktioniert mein Ansatz oder schlagt ihr Alternativen vor?

Ich bin noch relativ neu auf dem Gebiet der AVR-Programmierung, kann mir jemand einen Beispielcode zur Verfügung stellen? Mir geht es nur um die grundlegenden Befehle in Bascom.

pyr0skull
16.01.2009, 20:52
Du kannst den Timer automatisch bei steigender bzw. fallender Flanke auslösen lassen. Musst mal im Datenblatt schauen, da steht das genau drin, hab das selber auch noch nicht gemacht.

Besserwessi
16.01.2009, 21:08
Es gibt von Atmel dazu eine Application note (AVR135). Da wird das Verfahren beschrieben. Vermutlich mit Code in C.
http://www.atmel.com/dyn/products/app_notes.asp?family_id=607

wkrug
17.01.2009, 00:05
@kugelfisch
Dein Ansatz ist im Prinzip schon richtig.
Man stellt den Interrupt ( ICP, INTx ) auf steigende Flanke.
Wird der Interrupt ausgelöst wird der Timer ( bzw. das ICR ) ausgelesen und der Wert abgespeichert. Gleichzeitig wird das Interrupt sensing auf "fallende Flanke" umgestellt.
Tritt dan der Interrupt bei fallender Flanke wiederum auf, liest man den Timer ( ICR ) erneut aus und zieht den vorher abgespeicherten Wert ab.
Das Interrupt Sensing wird für die nächste Messung dann wieder auf "steigende Flanke" gestellt.
Wenn man unsigned Variablen benutzt ist auch die Berechnung bei Überlauf der Timers kein Problem.
Den Timer ( TCNT1 ) per Software auf 0 zu setzen kann u.U. einen Messfehler verursachen.

Ich nehm für solche Sachen gerne den Timer1 mit einem Quarz von 8MHz und einem Prescaler von 8 her, weil dann die Werte direkt in µs ausgegeben werden.

Ein weiteres Problem könnte noch sein, das eine Einspritzdüse während eines Zündvorganges mehrmals mit unterschiedlichen Zeiten einspritzen kann.
Das könnte man eventuell dadurch lösen, das man einen Drehzahlsensor anbringt und die Einspritzzeiten einer Umdrehung aufaddiert.

Grundsätzlich gilt für so eine Zeitmessung, wie für alle Interrupts, die Interruptroutinen so kurz wie möglich zu halten.
Eventuell wäre Assembler sinnvoll.

pyr0skull
17.01.2009, 07:06
Ein weiteres Problem könnte noch sein, das eine Einspritzdüse während eines Zündvorganges mehrmals mit unterschiedlichen Zeiten einspritzen kann.


Das sollte das Ergebnis ja eigentlich nicht verfälschen - solange man die Gesamteinspritzzeit bei einer konstanten Einspritzmenge feststellt, ist es egal wie of die Düse pro Umdrehung einspritzt, es wird ja nur die Gesamtmenge in Relation zur Zeit benötigt.

||kugelfisch
17.01.2009, 10:12
Die Application Note habe ich gelsen und verstehe den Pseudocode auch so weit ganz gut. Das bestätigt mich in meiner geplanten Vorgehensweise.


Ein weiteres Problem könnte noch sein, das eine Einspritzdüse während eines Zündvorganges mehrmals mit unterschiedlichen Zeiten einspritzen kann.

Ich fahre einen alten Audi 80, der verfügt noch über eine Zentraleinspritzung (ähnlich Vergaser). Ich habe für alle 4 Zylinder nur eine Einspritzdüse. Damit dürfte das von dir beschriebene Problem entfallen, trotzdem vielen Dank für den Hinweis.


Mein konkretes Problem ist nach wie vor, dass ich die Theorie verstehe, es aber nicht in Bascom umsetzen kann. Im Wiki gibt es leider auch keinen entsprechenden Artikel zum Theme ICP mit Codebeispielen in Bascom. Hat jemand ein paar entsprechende Codeschnipsel?

||kugelfisch
25.01.2009, 19:03
Ich habe in einem Lehrbuch einen Beispielcode gefunden und versucht diesen auf mein Beispiel umzuschreiben. Ziel ist es die Dauer des High-Pulses an PortB.0 zu messen. Leider funktioniert das Programm in der jetzigen Form nicht. Wo liegt mein Fehler?


$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000


'LCD:
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portc.5 , Db5 = Portc.1 , Db6 = Portc.4 , Db7 = Portc.0 , E = Portc.2 , Rs = Portc.3
Config Lcdbus = 4

'Variable:
Dim Pulswert As Word

'Funktionen:
Declare Function Hochpuls() As Word

'Port B.0:
Config Pinb.0 = Input
Set Portb.0.0
Pulsmesserpin Alias Pinb.0

'Timer1:
Config Timer1 = Timer , Prescale = 1024
Enable Timer1
On Timer1 Interrupttimer1 Nosave
Enable Interrupts

Cls
Do
Cursor Off Noblink
Locate 1 , 1
Pulswert = Hochpuls()
Lcd "Puls:" ; Pulswert
Loop
End


Function Hochpuls() As Word
While Pulsmesserpin <> 1 : Wend 'warte auf Lo-Hi an PB0
Tcnt0 = 0 'reset timer1
Start Timer1
While Pulsmesserpin = 1 : Wend
Stop Timer1
Hochpuls = Tcnt0
End Function Hochpuls()

'Overflow Timer1 stoppt Timer1 und setzt TCNT1 zu Null (timeout)
Interrupttimer1:
!push r24
Stop Timer1
Tcnt0 = 0
!pop r24
Return