PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Unlösbares Problem mit PULSEIN ?? Tips gesucht!! Hilfe



m@rkus33
29.05.2006, 14:06
Hallo zusammen,

habe ein Problem bei dem ich nicht weis wie ich es lösen könnte.


Ich möchte mit "Pulsein" in einem Datenlogger einen RC-Kanal auf den Status abfragen.

Eigentlich ja kein Problem, aber....

mein Programm bleibt stehen wenn gar kein Signal anliegt, das muss ich irgendwie lösen. Das kann vorkommen.

Ich kann KEINEN externen INT verwenden - ist schon belegt!
Ich kann den 16bit Timer nicht verwenden - ist auch schon belegt!

Momentan läuft die "Pulsein" abfrage neben dem externen Int, dem Timer1, über den Timer0 (20mal pro Sek.) Der RC-Kanal braucht nicht öfter abgefragt werden, da das zur Statusabfrage reicht und ich fesgestellt habe das über den Timer0 keine Konfilikte mit den INT0 und Timer1 auftreten.

Wie kann ich das Problem lösen, das ohne Puls der Pulsein nicht "hängenbleibt"? Ich habe KEIN Bitwait verwendet.

IDEEN - VORSCHLÄGE?????

Danke

Gruß
Markus

PicNick
29.05.2006, 15:07
"Pulsein" hat nach einem Timeout auf jeden Fall ein Ende, also wirklich hängen sollt# er nicht bleiben, auch ohne Puls.

m@rkus33
29.05.2006, 18:16
Kann es sein, das der Timeout so lange dauert das der Timer0 ihn dann schon wieder zum erneuten warten schickt. Dadurch würde dann irgendwie eine "Dauerschleife" entstehen. Am Terminal sehe ich das die Impulse gezählt werden(nur bei weitem nicht alle) und auch das Datensenden funktioniert. Nur in die Hauptschleife gehts nicht mehr. Das sehe ich an einer LED die eigentlich dann blinken sollte.

Grob sieht mein Programm so aus. Die Config Timer und Interrupt usw. habe ich jetzt mal weggelassen. Das passt scho.

.....
On Int0 Zähleimpulse
On Timer1 Datensenden
On Timer0 RCmessen


Do

"Hauptschleife"

Loop

Zähleimpulse: (kommt von einem Durchflussmesser)
incr A
Return

Datensenden: (werden und sollen nur alle 0,25 Sek. übermittelt werden)
Printbin Stb;B(1);C
Return

RCmessen: (hier ist mein Problem ;) )
Pulsein RC ,Pinc, 4,0

Stimmt da was an der Grundstruktur nicht? Oder gibts da noch einen anderen Trick?

PicNick
29.05.2006, 18:33
Mit der Dauerschleifentheorie könntest du vielleicht recht haben.
Mach den Pulsein in der Hauptschleife und lass ihn vom Timer triggern


DIM trigger as byte

DO "hauptschleife"
if trigger = 1 then
trigger = 0
pulsein rc, pinc, 4, 0
end if
'------ andere Beschäftigung ----
LOOP

RCmessen:
trigger = 1
return

dadurch kann pulsein vom anderen Timer unterbrochen werden und hält nicht den Betrieb auf.

Wenn pulsein wirklich zu lange sein sollte, wird's natürlich eng, da brauchen wir eine andere Idee

FÜr mein Verständnis: Du willst alle 0,05 sekunden sehen, ob sich auf der Rc-Leitung irgendwas tut ?

m@rkus33
29.05.2006, 18:39
Hallo Robert,
beim RC will ich alle 0,05 Sek. sehen ob sich was tut, das "Datensenden" darf nur alle 0,25 Sek. passieren.

Hmm... das mit dem Trigger werde ich mal ausprobieren.

Kann der pulsein dann auch vom INT0 unterbrochen werden?

Gruß
Markus

PicNick
30.05.2006, 08:19
Kann der pulsein dann auch vom INT0 unterbrochen werden?

definitiv. versuch es mal. "Pulsein" in einer ISR Routine ist so oder so nicht gut.

m@rkus33
30.05.2006, 19:16
hallo robert,

funktioniert so perfekt, danke für den Tip!!!

gruß
Markus

m@rkus33
30.05.2006, 19:27
.... hmm so jetzt habe ich aber ein anderes Problem:

Wenn der Int0 kommt, liefert mir Pulsein total falsche Werte. Wenn ich während Pulsein den Int0 disable dann fehlen mir ein haufen Impulse die vom Int0 laufend gemessen werden müssen.

Kann ich den den Timeout für den Pulsein irgendwie verkürzen?

Gruß
Markus

Hanni
30.05.2006, 20:26
Hmm ... wie wäre es, dieses per Hand zu Coden, oder den Code "etwas" zu optimieren ?

Das Problem ist im endeffekt das folgende:

solange du nicht weißt, wie pulsein umgesetzt wird von BASIC ist es defakto "Sackhüpfen im Minenfeld" was hier betrieben wird.

Optimierungsmöglichkeiten wären im übrigen z.B. das entmisten von ISR's etc.

Nachtrag: Wenn dein µC nen Pin Change Interupt hat könnte auch dieser helfen ... aber daran hast du sicherlich schon gedacht.

Grüße,

da Hanni.

m@rkus33
30.05.2006, 22:03
Hi Hanni,

nix für ungut aber irgendwie check ich jetzt nicht was Du damit sagen willst. Fakt ist, das ich erst vor 4 Monaten überhaupt begonnen habe mich mit MCs zu beschäftigen und dabei so nebenbei mir das Bascom proggen selber beigebracht habe. Für nen richtigen Tip wäre ich dankbar, mit nem Satz

solange du nicht weißt, wie pulsein umgesetzt wird von BASIC ist es defakto "Sackhüpfen im Minenfeld" was hier betrieben wird.
kann ich leider gar nix anfangen.

Ich weis zwar wie in Bascom der Pulsein funktioniert aber nicht wie ich daran schrauben kann. (Timeout beeinflussen)

Das die Geschichte mit den Interupt nicht ganz ohne ist, das ist mir auch bekannt. Leider habe ich keine andere Möglichkeit (bis jezt) gefunden.

Wie gesagt ich bin bereit jederzeit dazuzulernen. ;)

gruß
Markus

Hanni
31.05.2006, 12:17
Gemeint ist:

Solange du nicht weisst, was Bascom aus der Anweisung pulsein ... genau macht, also wie es für den Mikrocontroller umgesetzt wird, sehe ich selbst keine Optimierungsmöglichkeiten in dieser Richtung .... (daher Sackhüpfen im Minenfeld).

Ein Flussdiagramm zu dem Thema wäre sicherlich schon mal ein Anfang.

Mal so ne Frage am Rande: für was nen µC willst du das ganze schreiben ?

PicNick
31.05.2006, 13:03
Falls es jemanden interessiert, was Bascom bei "PULSEIN" produziert:
Hat ja drei Loops:
1 Warten auf Pinx != state (count 0-65535)
2 Warten auf Pinx == state (count 0-65535)
3 Warten auf Pinx != state (count 0-65535 mit 10µS Loop)

Um die timeoutwerte zu ändern, müßt man den Code-ändern


// DIM result as WORD
// Pulsein Result , Pind , 2 , 1
LDI ZL,0x30 // PIND
LDI r24,0x02 // PinNr
LDI r16,0xFF // State
CALL PULSEIN
LDI XL,0x60 // addr "result"
LDI XH,0x00
ST X+,r24 // store result
ST X,r25
...............................................


PULSEIN:
CALL Clear_ErrBit
CLR ZH
CLR XL // clear Timout Lo
CLR XH // clear Timout Hi
CALL MakeMask // R24 Mask, R25 neg Mask
AND r16,r24
LDD r0,Z + 1 // DDRD
AND r0,r25 // Make Pin (2) Input
STD Z + 1,r0 // DDRD

L_0x00D8: // ------------- Loop 1
LDD r0,Z + 0 // PIND
AND r0,r24 // PIND & Mask
EOR r0,r16 // (PIND & Mask) ^ State
BRNE L_0x00E6 // Ok PIN != State
ADIW XL,0x0001 // Timeout counter++
BREQ L_0x0118 // elapsed->ERR-Exit
RJMP L_0x00D8 // cont'd Loop
L_0x00E6:
CLR XL // clear Timout Lo
CLR XH // clear Timout Hi

L_0x00EA: // ------------- Loop 2
LDD r0,Z + 0 // PIND
AND r0,r24 // PIND & Mask
EOR r0,r16 // (PIND & Mask) ^ State
BREQ L_0x00F8 // Ok PIN == State
ADIW XL,0x0001 // Timeout counter++
BREQ L_0x0118 // elapsed->ERR-Exit
RJMP L_0x00EA // cont'd Loop
L_0x00F8:
CLR XL // clear Timout Lo
CLR XH // clear Timout Hi

L_0x00FC: ------------ 10 µS Loop 3
PUSH ZL // Save
PUSH ZH
LDI ZL,0x20 // calc from $XTAL
LDI ZH,0x00
CALL L_0x009C // 10 µS Idle
POP ZH // Restore
POP ZL
LDD r0,Z + 0 // PIND
AND r0,r24 // PIND & Mask
EOR r0,r16 // (PIND & Mask) ^ State
BRNE L_0x011C // OK, Pulsein done *********
ADIW XL,0x0001 // PulseCounter++
BRNE L_0x00FC // cont'd Loop
L_0x0118:
CALL Set_ErrBit
L_0x011C:
MOV r24,XL // result --> R24:r25
MOV r25,XH
RET // that's it

// idle Loop
L_0x009C:
SBIW ZL,0x0001
BRNE L_0x009C
RET
Set_ErrBit:
SET
BLD r6,2
RET
Clear_ErrBit:
CLT
BLD r6,2
RET
MakeMask:
LDI r25,0x01
AND r24,r24
BREQ L_0x00BC
CLC
L_0x00B6:
ROL r25
DEC r24
BRNE L_0x00B6
L_0x00BC:
MOV r24,r25
COM r25
RET

Hanni
31.05.2006, 15:15
Hmm, also wohl die denkbar schlechteste Lösung für zeitkritische Geschichten .... (durch das Polling)

Vorschlag:

Versuch den Timer 1 frei zu bekommen.

So wie ich das anhand deines Codeschnipslels sehe, verwendest du den Timer 1 defakto nur dazu um die Datenübertragung anzustoßen (oder führst du die in der ISR aus ?!)

Ich denke mal, dieses könnte man durchaus in einen andere Timer verlegen.

Ansonsten rük mal bitte ein paar Infos darüb er raus, was für Parameter du nun genau messen willst. Vielleicht hab ich ja dann noch ne zündende Idee.

Grüße,
da Hanni.

m@rkus33
31.05.2006, 16:17
Hi Hanni,

ahh jetzt verstehe ich die Aussage ;)

Also im Moment führe ich die Datenübertragung im ISR aus. Ich könnte aber auch die Datenübertragung durch den ISR triggern lassen. Das Dumme war, das die Messung des RC-Kanals erst nachdem alles fertig war (Code und HW) mit eingeführt werden musste.

Das Ding macht folgendes (eigentlich nix berauschendes)

Über einen Durchflussmesser kommen Impulse, die der MC über den INT0 zählt. Anhand der gezählten Impulse werden dann Verbauchs- und Bevorratungsberechnungen durchgeführt. Zus. wird die Funktion des Durchflussmessers überwacht, also ob sich das Ding noch dreht oder nicht. Das wird unter anderem auch in der ISR des Timer1 gemacht. Also alle 0,25 Sek. werden die Zählerstände alt und neu verglichen und dann die Daten gesandt.

So nun muss der MC (Mega8) zus. den RC-Kanal überwachen und bei überschreiten eines bestimmten Wertes dies über den Datentransfer melden.

Das alles funktioniert bisher einwandfrei, bis auf das Problem, das bei fehlendem Pulsein alles etwas durcheinanderholpert und durch die lange Wartezeit des Timeouts viele Impulse über den INT0 nicht gezählt werden.

Ich könnte aber vor der Hauptschleife noch eine Pulseinabfrage machen, wenn kein Impuls anliegt dann einfach den Pulsein in der Hauptschleife disablen. Wäre glaub ich die einfachste Variante.

Hanni
31.05.2006, 17:24
Also, zählen von Impulsen über INT0 (Durchflussmesser) und
Messen von Impulsen aus dem RC Kanal (also Impulsbreite o.ä.)?

m@rkus33
01.06.2006, 14:38
Genau so ist es.

PicNick
01.06.2006, 14:45
Was hast du denn in den Haupt "do...Loop" schleife noch alles zu tun ?
Vielleicht könnt man die beiden Funktionen zusammenführen und gewissermassen gleichzeitig tun.

-tomas-
01.06.2006, 15:01
@PicNick
Danke für deinen kommentierten ASM-Code

m@rkus33
Warum wird in diesem Forum immer viel diskutiert und nur so wenig Code veröffentlicht? Hier wird doch kaum jemand kommerzielle Interessen verfolgen?
Jeder erfindet das Fahrrad für sich neu und schreibt zum Schluss
"Danke, jetzt hab ich es."

m@rkus33
01.06.2006, 17:28
@tomas

ich habe einfach ein schlechtes Gefühl, wenn ich den gesamten Code hier reinstelle. Da habe ich bisher mehrere Monate gebraucht um das Ganze zu entwickeln ( Hard- und Software) und es ist da wo ich es einsetze (kein kommerzielles Intresse!) bisher einmalig. Ich möchte nur nicht das das irgendwo einfach kopiert wird.

@PickNick

ja auch nochmal Danke für den Code. Ich bin nur noch nicht fit genug um den wirklich zu kapieren... kommt noch (hoffe ich ;) )

In meiner Do- Loop passiert nicht besonders viel.

Do

Start ADC
U-Wert einlesen
Stop ADC

vergleich U-Wert mit bisherigen Werten, nach tiefster Wert und
aktueller Wert

Zählergebnisse Impulse mit Vorgaben verglichen

RC- Kanal mit Pulsein gemessen (nur der reine Wert, keine Umrechnung in ms)

RC-Kanal Wert mit Vorgabe vergleichen und Statusmeldung bei Schwellwert Unter- bzw. Überschreitung

Loop

OnInt0:

incr Zähler für Impulsmessung
Return

OnTimer: (alle 0,25 sek.)

Daten (Zählerstand Impulsmessung, Werte U, Statuswerte Durchflussmesser, RC Kanal) werden über RS232 gesendet und über Funk telemetriert.

Gruß
Markus

Hanni
01.06.2006, 17:46
Hmm, mögliche Lösungsansätze:

Man könnte z.B. die Durchfluss Impulse als Takt für den Timer 0 missbrauchen.

Desweiteren erzeugt man sich mit einem beliebigen weiterem Timer eine "Referenzzeit" welche dann dafür genutzt werden könnte um:

a) Die Anzahl der Impulse innerhalb einer bestimmten Zeit zu speichern.
b) um die Impulsbreite des RC Impulses zu messen.

Den RC Impuls würde ich über einen Flankengesteuerten externen Interupt messen. (man muss halt nach jedem Impuls die Flanke wechseln).

Die Datenübertragung würde ich übrigens in den Main Loop packen.

So, nun stellt sich allerdings die Frage, ob dieses theoretisch mit deiner bisherigen Hardware realisierbar wäre.

Grüße,

da Hanni.

-tomas-
01.06.2006, 17:53
m@rkus33
Eine letzte Anmerkung (bevor der Admin mich wegen off-topic ermahnt):
Wir dürfen nicht vergessen, welchen Nutzen wir selber aus der Community beziehen.
...übrigens ist ein Code allein noch kein Nachbau-Projekt.

m@rkus33
01.06.2006, 21:49
@Hanni

erstmal Danke für Deinen Vorschlag.
Wenn ich das jetzt richtig verstanden habe, dann müsste ich Hardwaretechnisch an den PIN des INT0 den RC-Impuls legen und an den bisherigen RC-Impuls den Durchflussimpuls. Richtig? Also nur tauschen.

Damit wäre der Durchflussmesser an einem Pin den ich für den Timer proggen kann und der RC-Impuls am Hardware INT0 Pin.
Das ginge ohne Probleme, einfach die Stecker tauschen :)

Wenn ich die Datenübertragung ins Main-Loop lege müsste ich dann mit "Waitms250" arbeiten. Dann wäre der Sendetakt in etwa gleich.

Was ich jetzt noch nicht ganz verstanden habe ist die Geschichte mit den beiden Timern. Ich vermute mal, den Timer0 über die Durchflussimpulse als Counter verwenden. Bei jedem Überlauf den Wert sichern und mit dem nächsten Überlaufwert addieren. Zus. beim Überlauf die Impulsbreite messen.

Hmm... mit dem Thema Flankenwechsel und Impulsbreitenmessung, da muss ich glaub ich noch etwas hier im Forum stöbern und die Hilfe von Bascom noch etwas in Anspruch nehmen. ;)

Toll wäre es, wenn es ohne Hardwareänderungen ginge. Ok Stecker tauschen wäre kein Thema.

Merci und Gruß
Markus

Hanni
02.06.2006, 20:00
Hmm, das Waitms könnte man auch weglassen.

Hier mal ein möglicher Lösungsansatz für die oben beschriebene Vorgehensweise:

Timer0 = Durchflusszähler (den Durchflussimpuls als Takt missbrauchen - T0 Eingang - PIN PD 4)
Timer1 = ein Referenz Zeit Zähler mit einer Schrittweite von z.B. 8µs und einer Gesamtdurchlaufdauer, die sich leicht zum Weiterrechen verwenden lässt (z.B. 0,5 Sek).
INT0 = RC Impuls

Am Anfang den INT0 aus steigende Flanke konfigurieren.
Irgendwann kommt die steigende Flanke des RC Impulses -> der Interupt löst aus und man landet in der ISR vom INT0.

In dieser den Zählerstand von Timer 1 sichern und den INT0 auf die fallende Flanke konfigurieren.

Irgendwann ist der RC Impuls beendet. (fallende Flanke). diese löst wiederum einen Interupt aus und man landet in der ISR.

in dieser dann den gesicherten Zählerstand vom aktuellem Zählerstand des Timer1 abziehen, das Ergebniss abspeichern und den Interupt anschliessend wieder auf die steigende Flanke konfigureren.

Der Referenzzeit Zähler erreicht irgendwann einen Überlauf.
Dieser löst einen Interupt aus. In der ISR Prüft man nun, ob insgesamt schon 25 Sekunden rum sind (mittels eines Zählbytes). Wenn nicht, Zählbyte = Zählbyte+1, wenn ja, Zählbyte = 0 und ein Flag zum Starten der Übertragung setzen.

Main Loop:

Wenn das Flag zum Starten der Datenübertragung gesetzt ist:
- Durchflusszähler auslesen und reseten
- die Durchflussdaten auswerten
- sonstige notwendige Daten errechnen
- Daten übertragen.
- das Flag löschen.

Wenn das Flag nicht gesetzt ist:
- warten, bis das Flag gesetzt ist.

Ansonsten kann ich dir nur empfehlen, das Datenblatt (http://atmel.com/dyn/resources/prod_documents/doc2486.pdf)vom ATMEGA 8 mal wieder rauszukramen und dort mal die Seiten 67 (externer Interupt 0) und die Seiten 69 ff. (Timer 0) mal durchzulesen.

Grüße,

da Hanni.

m@rkus33
03.06.2006, 10:29
Hallo Hanni,


ja das klingt wirklich gut! Das hab ich kapiert ;). Die Referenzzeit habe ich umgesetzt und funktioniert prima. Jetzt muss ich nur noch schauen wie ich am einfachsten den Durchflusszähler auf TO bekomme. Den habe ich dummerweise nicht mit einem Lötpad versehen. Das war wirklich dumm von mir, alle anderen freien Pins haben eins, nur der nicht. Ok, mache ich halt ne neue LP.

Das mit RC auf INT0 werde ich heute mal ausprobieren.

Vielen, vielen Dank für den Lösungsansatz ich denke das funktioniert.

Hanni
03.06.2006, 10:36
Na dann viel Erfolg.

Grüße,

da Hanni.

m@rkus33
05.06.2006, 19:39
Hi Hanni,

konnte mal etwas spielen. Jetzt habe ich nur eine (ganz dumme) Frage:

Ich habe den Timer0 als Counter konfiguriert, leider zählt er nicht. Was hab ich falsch gemacht. Ich möchte das er bei jedem Impuls den Wert nur um eins erhöht.

Impuls liegt nun an Pind.4

So sieht der Timerteil im Code aus:

Dim Impulse as Long

Config Pind.4 = Input
Portd.4 = 1

Config Timer0 = Counter, Edge = Falling, Prescale = 1024
Timer0 = 254

On Timer0 dfm
Enable Interrups
Enable Timer0

Do

"Hauptschleife"...bla,bla

Loop


dfm:

Incr Impulse
Timer0 = 254
Return


Bin ich jetzt doof? Ich kann da keinen Fehler erkennen ????

Gruß
Markus

Hanni
06.06.2006, 12:00
Ne, doof biste nicht. Du hast nur einen kleinen Denkfehjler drin.

Wenn der Timer als Counter konfiguriert ist, hast du den Prescaler nicht zur Verfügung.
Dieses liegt darin begründet, das du auch dieses defakto im TCCR Register mit den Bits CS?0 - CS?2 einstellst. Schau mal ins Datenblatt, dann siehst du sofort was ich meine.


Grüße,

Da Hanni.

m@rkus33
06.06.2006, 20:03
Mensch, ich bin doch doof.... Prescaler raus und schon gehts. Hmm, jetzt hab ich alles umgebaut aber mit dem Pulsein werde ich nicht glücklich.

Jetzt läuft der Durchflussmesser auf dem Timer1, der Sendetakt der RS232 Daten kommt vom Timer0, den INT0 habe ich komplett entfern.

Komisch ist, das der Pulsein ab ca. 500 I/min vom Durchflussmesser gar nicht mehr misst. Ich habe die Vermutung, das die Zeit die zwischen den Impulsen vom Durchflussmesser ab dieser Grenze einfach zu kurz wird um die RC-Impulsmessung per Pulsein zu erlauben. Kann das sein?

Ich dachte das die Zählung der Durchflussmesser Impulse jetzt über den Timer1 "nebenbei" laufen kann.

Auch eine Änderung des Quarzes auf 7.3728 Mhz hat nix gebracht. Da macht der Pulsein gar nicht mehr mit. ?????

Ich werd noch verrückt, irgendwas mach ich doch da falsch... oder nicht?




Gruß
Markus

Hanni
06.06.2006, 21:30
Wie gesagt: Versuch den RC Impuls auf den INT0 zu legen und miss die Impulsbreite.