Powell
24.09.2010, 01:16
Hallo zusammen!
Ich habe gerade folgendes Projekt im Bau, und würde mich freuen wenn wir hier mal ein bisschen über Möglichkeiten der Umsetzung sprechen können.
Um folgendes gehts:
Ein Frequenzsignal (kommt ursprünglich von einer Ottomotor-Zündanlage) wird durch ein aktives Filter geschickt, am Ende kommt ein schönes Rechtecksignal mit definierter Signalbreite und Variablem Abstand raus (die Zeit zwischen zwei Signalen ist also umgekehrt proportional zur Frequenz).
Diese Zeit wird nun mittels ATMEGA8 mit Bascom programmiert gemessen, und mit dem PULSEIN-Befehl ausgegeben (der dezimalwert entspricht der Zeit zwischen zwei Flanken in der Einheit [10µs])
Bis hierhin habe ich die Schaltung am Laufen. Ich wertete das ganze über ein LCD Display aus, welches 3x pro sekunde über die Timer ISR aktualisiert wird.
Nun fängt es an mit den Praxisproblemen:
Die Anwendung ist sehr Zeitkritisch. Wenn ich es laufen lasse, tauchen immer mal wieder "Lücken" auf, d.h. mir wird eine Frequenz von 0 angezeigt, obwohl das nicht stimmt. Wenn ich im Hauptprogramm eine Mittelung vornehme (die letzten 5 Pulsabstand-Werte werden addiert und durch 5 geteilt) wird es etwas besser, verschwindet jedoch noch nicht ganz.
Meine Vermutung: Es kommt ein Impuls in diesem Falle genau dann, wenn das Programm in der ISR ist, der Pulsabstand wird nicht aufgenommen. Wenn das öfters passiert (genauergesagt wenn 635,55ms kein Impuls registriert wird) gibt es einen Timeout (laut Bascom hilfe). Das Display zeigt mir eine 0 an.
Nun gilt es wohl das Programm zu optimieren, heißt den controller sich möglichst auf diese Pulsweitenmessung konzentrieren zu lassen.
Gleichzeitig möchte ich aber dass eine Ausgabe des Wertes erfolgt. Wie kann ich das also bestmöglich realisieren?
Eine Idee war, dass ich das Signal an einen zweiten Controller sende, der mir dann in aller ruhe als Anzeigetreiber dient. Nur in welcher form kann dieser wert gesendet werden? Als Analogwert und im anderen uC wieder ADC rückkonvertieren? Bestimmt nicht optimal. Oder als Frequenz und dann wieder rückkonvertierung? Stelle ich mir auch nicht so besonders geeignet vor. Auch dieses Senden muss ja möglichst wenig Takte beanspruchen.
Mit kommunikation zwischen zwei Controllern hab ich mich bisher noch gar nicht beschäftigt....
Sollte erst mal genug Input sein, hoffe ihr habt ein paar gute Vorschläge für mich.
Hier noch der Code:
'---------------------------------------------------------
$regfile = "m8def.dat"
$crystal = 16000000 'Quarz: 16,000 MHz
'---------------------------------------------------------
Config Pinc.0 = Input
Dim Pulsbreite As Long
'Config Adc = Single , Prescaler = Auto , Reference = Internal
'Start Adc
Dim A As Word
Dim B As Word
Dim C As Word
Dim D As Word
Dim E As Word
Dim Schnitt As Word
Dim N As Long
'===========================================
'++++++++FÜR LCD Verwendung:++++++++++++++++
'Config Lcdpin = Pin , E = Portc.3 , E2 = Portd.7 , Rs = Portc.2 , Db4 = Portd.2 , Db5 = Portd.3 , Db6 = Portd.4 , Db7 = Portd.5
'Config Lcd = 20 * 4a , Chipset = Ks077
'Config Lcdbus = 4
'Config Pind.6 = Output 'RW=0 (für LCD erforderlich)
'Portd.6 = 0
'Config Pind.7 = Output 'LCD Licht ein
'Portd.7 = 1
'Initlcd
'Cursor Off
'Cls
'------------------------------------------------------------
'+++++++ISR Config: Springt 3x pro sec in ISR um etwas auszuführen (z.B. LCD Betrieb)++++++++
'Config Timer1 = Timer , Prescale = 64 '16Mhz / 64 = 3 Hz Konfiguriere Timer0
'Enable Timer1 'schalte Den Timer0 Ein
'On Timer1 Isr_von_timer1 'verzweige Bei Timer0 überlauf Zu Isr_von_timer0
'Enable Interrupts
'============================================
Do
Pulsein Pulsbreite , Pinc , 0 , 1 'Pulsein Abfrage an PC0
'------ Umrechnungsfaktor auf U/min: ----------
If Pulsbreite > 400 Then 'Pulsbreite = 6.000.000 / Drehzahl
N = 6000000 / Pulsbreite 'PB(3000/min)=2000, (4000)=1500, (5000)=1200, (6000)=1000, (7000)=857, (8000)=750, (9000)=667, (10000)=600, (11000)=545, (12000)=500, (13000)=462, (14000)=429, (15000)=400, (16000)=375
End If
'-----------------------------------------------
E = D
D = C
C = B
B = A
A = N 'Bildung eines Mittelwerts der letzten 5 Zündungen
Schnitt = A + B
Schnitt = Schnitt + C
Schnitt = Schnitt + D
Schnitt = Schnitt + E
Schnitt = Schnitt / 5
If Schnitt < 6000 Then
Portd.7 = 1
Else
Portd.7 = 0
End If
Loop
Isr_von_timer1:
'ISR von Timer0
Timer1 = 0
Locate 1 , 3
Lcd " "
Locate 1 , 1
Lcd "c=" ; Schnitt
Return
End
Ich habe gerade folgendes Projekt im Bau, und würde mich freuen wenn wir hier mal ein bisschen über Möglichkeiten der Umsetzung sprechen können.
Um folgendes gehts:
Ein Frequenzsignal (kommt ursprünglich von einer Ottomotor-Zündanlage) wird durch ein aktives Filter geschickt, am Ende kommt ein schönes Rechtecksignal mit definierter Signalbreite und Variablem Abstand raus (die Zeit zwischen zwei Signalen ist also umgekehrt proportional zur Frequenz).
Diese Zeit wird nun mittels ATMEGA8 mit Bascom programmiert gemessen, und mit dem PULSEIN-Befehl ausgegeben (der dezimalwert entspricht der Zeit zwischen zwei Flanken in der Einheit [10µs])
Bis hierhin habe ich die Schaltung am Laufen. Ich wertete das ganze über ein LCD Display aus, welches 3x pro sekunde über die Timer ISR aktualisiert wird.
Nun fängt es an mit den Praxisproblemen:
Die Anwendung ist sehr Zeitkritisch. Wenn ich es laufen lasse, tauchen immer mal wieder "Lücken" auf, d.h. mir wird eine Frequenz von 0 angezeigt, obwohl das nicht stimmt. Wenn ich im Hauptprogramm eine Mittelung vornehme (die letzten 5 Pulsabstand-Werte werden addiert und durch 5 geteilt) wird es etwas besser, verschwindet jedoch noch nicht ganz.
Meine Vermutung: Es kommt ein Impuls in diesem Falle genau dann, wenn das Programm in der ISR ist, der Pulsabstand wird nicht aufgenommen. Wenn das öfters passiert (genauergesagt wenn 635,55ms kein Impuls registriert wird) gibt es einen Timeout (laut Bascom hilfe). Das Display zeigt mir eine 0 an.
Nun gilt es wohl das Programm zu optimieren, heißt den controller sich möglichst auf diese Pulsweitenmessung konzentrieren zu lassen.
Gleichzeitig möchte ich aber dass eine Ausgabe des Wertes erfolgt. Wie kann ich das also bestmöglich realisieren?
Eine Idee war, dass ich das Signal an einen zweiten Controller sende, der mir dann in aller ruhe als Anzeigetreiber dient. Nur in welcher form kann dieser wert gesendet werden? Als Analogwert und im anderen uC wieder ADC rückkonvertieren? Bestimmt nicht optimal. Oder als Frequenz und dann wieder rückkonvertierung? Stelle ich mir auch nicht so besonders geeignet vor. Auch dieses Senden muss ja möglichst wenig Takte beanspruchen.
Mit kommunikation zwischen zwei Controllern hab ich mich bisher noch gar nicht beschäftigt....
Sollte erst mal genug Input sein, hoffe ihr habt ein paar gute Vorschläge für mich.
Hier noch der Code:
'---------------------------------------------------------
$regfile = "m8def.dat"
$crystal = 16000000 'Quarz: 16,000 MHz
'---------------------------------------------------------
Config Pinc.0 = Input
Dim Pulsbreite As Long
'Config Adc = Single , Prescaler = Auto , Reference = Internal
'Start Adc
Dim A As Word
Dim B As Word
Dim C As Word
Dim D As Word
Dim E As Word
Dim Schnitt As Word
Dim N As Long
'===========================================
'++++++++FÜR LCD Verwendung:++++++++++++++++
'Config Lcdpin = Pin , E = Portc.3 , E2 = Portd.7 , Rs = Portc.2 , Db4 = Portd.2 , Db5 = Portd.3 , Db6 = Portd.4 , Db7 = Portd.5
'Config Lcd = 20 * 4a , Chipset = Ks077
'Config Lcdbus = 4
'Config Pind.6 = Output 'RW=0 (für LCD erforderlich)
'Portd.6 = 0
'Config Pind.7 = Output 'LCD Licht ein
'Portd.7 = 1
'Initlcd
'Cursor Off
'Cls
'------------------------------------------------------------
'+++++++ISR Config: Springt 3x pro sec in ISR um etwas auszuführen (z.B. LCD Betrieb)++++++++
'Config Timer1 = Timer , Prescale = 64 '16Mhz / 64 = 3 Hz Konfiguriere Timer0
'Enable Timer1 'schalte Den Timer0 Ein
'On Timer1 Isr_von_timer1 'verzweige Bei Timer0 überlauf Zu Isr_von_timer0
'Enable Interrupts
'============================================
Do
Pulsein Pulsbreite , Pinc , 0 , 1 'Pulsein Abfrage an PC0
'------ Umrechnungsfaktor auf U/min: ----------
If Pulsbreite > 400 Then 'Pulsbreite = 6.000.000 / Drehzahl
N = 6000000 / Pulsbreite 'PB(3000/min)=2000, (4000)=1500, (5000)=1200, (6000)=1000, (7000)=857, (8000)=750, (9000)=667, (10000)=600, (11000)=545, (12000)=500, (13000)=462, (14000)=429, (15000)=400, (16000)=375
End If
'-----------------------------------------------
E = D
D = C
C = B
B = A
A = N 'Bildung eines Mittelwerts der letzten 5 Zündungen
Schnitt = A + B
Schnitt = Schnitt + C
Schnitt = Schnitt + D
Schnitt = Schnitt + E
Schnitt = Schnitt / 5
If Schnitt < 6000 Then
Portd.7 = 1
Else
Portd.7 = 0
End If
Loop
Isr_von_timer1:
'ISR von Timer0
Timer1 = 0
Locate 1 , 3
Lcd " "
Locate 1 , 1
Lcd "c=" ; Schnitt
Return
End