PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Abfrage in Assembler



D.Stolarek
11.10.2004, 09:59
Hi Ihr lieben,

ich wollte mal fragen, wie ich in Assembler in einem Byte die länge eines Bit herausfinden kann, also die Zeit die er braucht zum High-Low wechsel und Low-High?!

Das was ich bisher gemacht habe funktioniert.
Die Schleife die ich probiert hab zu machen geht leider nicht,
da sich der Statuswert und der Wert in W sich kurz vor der abfrage ändert und dadurch gehts nicht.

Das Problem was ich noch habe ist, das mein Timer nicht immer bei 125 anfängt.
Ich brauche aber 125 da ich einen 1/16 Vorteiler habe der dann die Zeit auf ca. 2ms bringt. Beim Anfang des Programms gehts, das der mit 125 starten, aber beim Überlauf springt er auf 0, obwohl ich in einer Abfrage eingestellt habe, das er dann wieder zu dem teil springen soll wo der timer auf 125 gesetzt wird, aber das funktioniert nicht.

Falls Ihr euch den Code anschauen wollt setz ich ihn hier mit rein.
Ich weiss das die Schleife falsch ist, aber ich weiss nicht wie ich das richtig machen soll.





list p=16F84A ; list directive to define processor
#include <p16F84A.inc> ; processor specific variable definitions

__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _RC_OSC

;***** VARIABLE DEFINITIONS *****
w_temp Equ 0x0C ; variable used for context saving
status_temp Equ 0x0D ; variable used for context saving

w_copy Equ 0x20 ; Backup für Akkuregister
s_copy Equ 0x21 ; Backup für Statusregister

T0SC Equ OPTION_REG

ORG 0x000 ; processor reset vector
goto main ; go to beginning of program

; Interrupt routine falls diese mal benötigt wird
ORG 0x004 ; interrupt vector location
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register

movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
retfie ; return from interrupt

main
; PortA wird hier initialisiert
BCF STATUS, RP0 ; RP0=0
CLRF PORTA ; Initialisierung von PortA
; durch löschen des Data latches
BSF STATUS, RP0 ; Markiere Bank 1
MOVLW 0x0F ; nutzen für den DatenVerzeichniss

MOVWF TRISA&0x7f ; SET RA<3:0> als Input
; SET RA4 als Output
; PortB wird hier initialisiert
BCF STATUS, RP0 ; RP0=0
CLRF PORTB ; Initialisierung von PortA
; durch löschen des Data latches
BSF STATUS, RP0 ; Markiere Bank 1
MOVLW 0xCF ; nutzen für den DatenVerzeichniss

MOVWF TRISB&0x7f ; SET RA<3:0> als Input
; SET RB<5:4> als Output
; SET RB<7:6> als Output
TIMER
movwf w_copy ; w retten
swapf STATUS, w ; STATUS retten
movwf s_copy ;
MOVLW 1
NOCHMAL
BCF STATUS, RP0 ; auf Bank 0 wechseln
MOVLW 0x7D ; 0x83 = 131 ; 0x7D = 125
MOVWF TMR0 ; 131 oder 125 müsste hier drin stehen

BSF STATUS, RP0 ; auf Bank 1 wechseln
; BCF OPTION_REG&0x7f, T0SE ; bin mir nich sicher ob ichs brauche beim Vorteiler

; Flanke
BSF OPTION_REG&0x7f, T0SE ; hier wird für RA4 die Low Flanke gewählt
MOVF T0SE, F ; hier wird es unter der Speicherzelle gesichert

; movf TMR0, F ; das ist das Timer-Register

; Vorverteiler Aktivieren
BCF OPTION_REG&0x7f, PSA ; hier mit wird der Vorverteiler auf 0 gesetzt und aktiviert
BCF OPTION_REG&0x7f, PS2 ; damit man den vorverteiler auf 16/1 einstellt
BSF OPTION_REG&0x7f, PS1 ; hier wird PS1 auf 1 gesetzt
BSF OPTION_REG&0x7f, PS0 ; hier wird PS0 auf 1 gesetzt

; Timer
; BSF OPTION_REG&0x7f, T0CS ; T0SC wird auf 1 gesetzt damit der Vorverteiler mit benutzt werden kann
BCF OPTION_REG&0x7f, T0CS ; hier wird in der Speicherzelle T0SC die 0 gesetzt
MOVF T0CS, F ; nun wird es unter der Speicherzelle gesichert

NOP

ADDWF TMR0,W ; +1 ergibt 0x00 in w, wenn TMR0=0xFF
MOVLW 1
BTFSS STATUS,Z ; Sprung, wenn Z-Flag gesetzt
GOTO TIMER
GOTO NOCHMAL
END



Ich hoffe Ihr könnt mir helfen.
Ich bin total verzweifelt und bin für jede Hilfe von Euch DANKBAR.

Danke für Eure Hilfe schonmal.

Mit freundlichen Grüßen
Damian Stolarek

PS.:
Bitte Helft mir

D.Stolarek
19.10.2004, 08:08
Wie kann ich meinen Timer so machen, das er nur zählt, von einem bis zum anderen Flag?

Wie sieht eine Abfrage aus, die beim Timerwert 125 anfängt, damit ich eine Zeit von ca 2ms zählen kann?

Jooker
21.10.2004, 19:54
www.sprut.de
da gibt es Beispiel zu Timern

D.Stolarek
22.10.2004, 08:13
hi jooker

der timer funktioniert nur die abfrage für den timer geht nicht
danke aber trotzdem

ich brauche halt die abfrage damit der erste punkt den ich schrieb geht.

mit freundlichen grüßen
damian stolarek

stegr
22.10.2004, 13:06
Was für einen PIC nimmst du denn?
evtl. könntest du das mit Capture&Compare machen...
Das mit dem Timer wird etwas problematisch, da du ja dann nur den 0-1-Wechsel mitbekommst und nicht den 1-0-Wechsel...

Prinzipiell hast du zwei Möglichkeiten: du fragst in einer Endlosschleife immer den Status ab und startest dann, wenn ein 0-1-Wechsel stattgefunden hat, den Timer und hälst ihn später wieder an (beim 1-0-Wechsel), liest ihn aus, setzt ihn auf null. Natürlich kannst du das ganze auch noch etwas ressourcenschonender machen, indem du nen zweiten Timer nimmst und damit nur alle x µs den Status abfragst. Kommt immer drauf an, wie dein Eingangssignal aussieht.
Alternative: Du hängst an dein Eingangssignal nen RC-Glied und misst am PIC einfach per AD-Wandler den Wert. Daraus kannst du dir dann ausrechnen, wie das Tastverhältnis ist. Wenn du dann noch auf nen Interrupt-Pin dein Eingangssignal drauf legst, kannst du auch messen, wie groß die Frequenz ist. Dadurch kannst du dann wieder deine einzelnen Zeiten berechnen. Die Frage ist dabei halt, ob du die absoluten Zeiten brauchst, oder ob dir das Verhältnis (nennt sich Duty-Cycle) reicht.

22.10.2004, 13:24
Hallo,

leider steige ich durch Deinen Assembler-Quelltext nicht vollständig durch, aber was den Timer betrifft würde ich nach möglichkeit einen Auto-Reload-Modus wählen.
Das Highbyte des Timers beinhaltet den Nachladewert (125 in Deinem Fall) und das Lobbyte ist der eigentliche Timer. Nach Überlauf läd der sich dann selbst mit dem Wert aus dem Highbyte.

Ciao
Patrick

Bomberman
22.10.2004, 13:27
Falls Fragen zum letzten Beitrag sind, - der war von mir.
Ich werde permanent ausgelogged - vielleicht kann mir da mal jemand helfen *g*

D.Stolarek
27.10.2004, 09:37
hi leute,
ich verwende den pic 16f84a.
also ich weiss das ich den status den status abfragen müsste.
ich weiss nur nich wie ich das richtig anstelle.
wie mache ich den das, das er das automatisch macht?
ich bin voll noob in assembler, obwohl ich mir sprut durchgelesen habe steige ich immernoch nich durch.
mit kleineren projekten kann ich nich anfangen denn mir fehlt die zeit dafür. deswegen hoffe ich, das ich mit der hilfe von foren weiter komme und wenigstens ein teil fertig bekomme bis mein praktikum vorrüber ist.

mit freundlichen grüßen
damian stolarek

stegr
28.10.2004, 10:22
1.) Tutorials sind wirklich sinnvoll und es ist besser, wenn du mal zwei Stunden in nen Tutorial steckst, anstelle zwei Tage auf ne Antwort zu warten.

2.) Ich weiss nicht, ob ich genau verstanden habe, was du machen willst.
Auslesen von Portpins ist ja kein Problem. Da muss man nur daran denken, dass man Direktionsregister setzt (TRISA, TRISB, ...).
Angenommen du wölltest den Pin RB1 als Eingang nehmen, dann muss das TRISB auf b'11111101' setzen.

movlw B'1111101' ; RB1
movwf TRISB
Beachten musst du dabei, dass sich die TRIS-Register in Bank 1 befinden und nicht in Bank 0, d.h. du musst vorher noch die Bank umschalten.)

Nächster Schritt ist das clearen der Pins, die als Eingang genutzt werden sollen. z.B. mit
clrf PORTB

Und dann kannst du z.B. mittels

movfw RB1
btfsc STATUS, Z ; Test ob Zero-Flag gesetzt. Wenn nicht gesetzt, überspringe nächsten Befehl.
goto nicht_gesetzt
goto gesetzt


den Status des Pins abfragen.

Ich weiss nicht, ob es das ist, was du wissen wolltest... wenn nicht, dann solltest du bitte nochmal genauer sagen, was du machen willst.

D.Stolarek
28.10.2004, 10:38
hi,
das kann ich schonmal nutzen, um zu sagen, wann überhaupt was gestartet werden soll.

mir stellt sich aber die frage, wie ich nun in dem byte der gesendet wurde die länge der bits herausfinden kann. nirgends hab ich was davon gelesen.

wenn mir dabei einer helfen könnte wäre ich demjenigen überausdankbar.

ich habe mir sprut.de schon sehr oft durchgelesen und ich verstehe halt wie er es meint aber wie ich das in meine aufgabe einbringen soll das ist die frage aller fragen die ich mir stelle.

also bitte helft mir weiter. es muss doch hier leute geben für die sowas ein klacks ist.

mit freundlichen grüßen
damian stolarek

stegr
28.10.2004, 10:55
Also, wenn ich es richtig verstanden habe, brauchst du die Länge der Bits um festzustellen, ob sich das Signal geändert hat oder nicht. Also ob du 111 oder 11 empfangen hast.
Wenn du das wissen willst, dann musst du zumindest die Gesamtlänge wissen.

Ich geh mal davon aus, dass du von irgendwo Daten einlesen willst. Dafür hat man typischerweise eine zweite Leitung mit Clock, oder man hat eine definierte Länge der einzelnen Bits.
Wenn man beides nicht hat, benutzt man ein anderes Verfahren: Schau dir da mal die Manchester-Kodierung an, die arbeitet über steigende und fallende Flanken.

Mal doch einfach mal ein Bildchen, damit man mal das ganze System überblicken kann...

D.Stolarek
28.10.2004, 11:26
also hier ist ein bild
die 1 ist 2ms lang
die 2 ist 1ms lang
die 3 ist 0,5ms lang

es gibt 4 byte die empfangen werden.
beim 1. byte ist nur mit bit längen bestückt von 2ms.
bei den anderen 3 byte sind die 1ms und 0,5ms.

wenn das dritte byte gewesen ist fängts wieder beim 1ten an, wo wieder 2ms gefunden werden.
das programm soll dann gestartet werden, wenn ich in der abfrage herausfinde das das 2ms dauert bis flag wechsel eintritt.

ich hoffe das hilft etwas.

mit freundlichen grüßen
d.stolarek

stegr
28.10.2004, 13:16
Wenn du nicht auf den Status prüfst, sondern über nen Interrupt auf ne Flanke gehst, sollte das ganze einfacher sein.

Programmablauf wäre folgender:
- steigende Flanke -> Interrupt
- Interruptserviceroutine startet Timer
- nächste steigende Flanke -> Interrupt
- Timer anhalten und Wert auslesen.
- Wert mit Soll-Wert für 2ms (abzgl. vergleichen usw.)
- Wenn gleich, dann das eigentliche Programm starten
- sonst Timer rücksetzen und wieder starten
- und auf nächste steigende Flanke warten...

D.Stolarek
28.10.2004, 14:28
ja so dachte ich das auch aber wie kann ich den sowas umsetzen??

wie kann ich den nachfragen ob flanke nun oben oder unten ist?
wie stope ich den timer?
wie erstelle ich den die abfrage richtig?

bin totaler noob in dem bereich der programmierung
bitte hilf mir

stegr
28.10.2004, 17:05
Damit du was bei lernst, musst du das Programm schon selber schreiben...

aber ich geb dir ein paar Tips:
- wie kann ich den nachfragen ob flanke nun oben oder unten ist?
Die Flanke hat kein oben oder unten, sondern nur eine Richtung:
Flanke nach oben oder Flanke nach unten. Das ist genau der Moment, in dem von Low nach High bzw. von High nach Low umgeschaltet wird.
Der externe Interrupt-Eingang reagiert auf steigende Flanken (d.h auf Wechsel von Low nach High). Wie du Interrupts verwendest, findest du auf www.sprut.de

- wie stope ich den timer?
Es gibt ein Register, in dem die globalen Eigenschaften der Timer stehen. In diesem Register gibt es auch ein "Timer enable". Du musst darauf achten, dass du evtl. einen 16-bit-Timer verwenden musst; das hängt aber von deinem takt ab.

- wie erstelle ich den die abfrage richtig?
Wenn ein Interrupt ausgelöst wird, springt das Program an die ISR-Einsprungadresse. Das ist beim PIC nur eine. Du musst also selber unterscheiden, was für ein Interrupt das war. Dazu musst du schaun, ob im Interrupt-Service-Register das für den ext. Interrupt entsprechende Bit gesetzt ist. Die Abfrage geht wie oben schon beschrieben über "Test Bit, skip if clear" bzw. "Test Bit, skip if set" (btfsc bzw. btfss).

Fritzli
28.10.2004, 22:22
Hallo


- wie stope ich den timer?
Es gibt ein Register, in dem die globalen Eigenschaften der Timer stehen. In diesem Register gibt es auch ein "Timer enable". Du musst darauf achten, dass du evtl. einen 16-bit-Timer verwenden musst; das hängt aber von deinem takt ab.

Das wird nicht funktionieren. Er verwendet einen 18F84A. Der hat nur TMR0 und der hat kein Enable.

Um die Zeiten zwischen zwei Flanken zu messen würde ich, wie jemand oben empfohlen hat, bei einer ersten 0-1 Flanke den TMR0 resetten und bei der zweiten Flanke den TMR0 retten (also kopieren) und dann mit dem kopierten Wert weiterarbeiten.

um den Timer zu löschen:
clrf TMR0

um den Timer ins W-Register zu retten:
movf TMR0, W


Gruess
Felix

D.Stolarek
01.11.2004, 10:57
Hi Leute,
danke nochmals für die Hilfe.
Nun habe ich eine andere Frage.
Wie kann ich an einem Eingang einen Flankenwechsel überprüfen?
Also sowas wie Manchester Code oder so.
Danke schonmal im Vorraus.

Interrupts habe ich nich hinbekommen deswegen versuche ich an einem normalen pin dies zu überprüfen.

Stegr du schriebst mal das:

Programmablauf wäre folgender:
- steigende Flanke -> Interrupt
- Interruptserviceroutine startet Timer
.....

Nun Ja, wie überprüfe ich den, ob da eine steigende Flanke ist?
Wie mache ich einen Interrupt richtig, hab das mal ausprobiert hat aber nich funktioniert?
Am besten wäre wirklich ohne Interrupts.

Gruß
damian stolarek

01.11.2004, 16:51
Port abfragen
XOR mit Wert von vorher, gibt nur 1, wenn Änderung
In diesem Fall: Wenn vorher 0 --> steigende
1 ---> fallende Flanke
Entprellen z.B: Vergleich nur dann, wenn wenigstens n-mal KEINE änderung war :-)

D.Stolarek
02.11.2004, 09:01
@Gast
Sorry, aber ich verstehe nichts von dem was du da geschrieben hast.
Welcher Wert von vorher?
Also ein Pin wird bei mir als Eingang gesetzt und darauf wird dann ein FunkSignal gesendet.

Eine Rieeeesseenn Frage an die FunkExperten, Wie macht ihr das, das der bei einem PIC empfangt und diese dann überprüft um diese Werte weiter zu bearbeiten und zu nutzen.

Gruß
D.Stolarek

02.11.2004, 10:04
Interrupts...

wenn man Interrupts verwendet, ist es kein Problem auf steigende oder fallende Flanken zu detektieren (kann man im Datenblatt bzw. im User Guide nachlesen).

ansonsten hat unser lieber Gast schon gesagt wie es geht:

Du pollst den Pin (d.h. fragst ihn ständig ab) und speicherst den Status des Pins im RAM. Dann nimmst du den aktuellen Wert am PIN und vergleichst ihn mit dem vorherigen (im RAM abgelegten) Wert. Wenn die gleich sind, gabs keine Änderung, bedeutet: Flanken gibt es nur wenn sich was ändert.
=> Wahrheitstabelle:

Xalt | Xneu | Resultat (Änderung?)
0 | 0 | keine Änderung (0)
0 | 1 | steigende Flanke (1)
1 | 0 | fallende Flanke (1)
1 | 1 | keine Änderung (0)

und diese Wahrheitstabelle entspricht der für XOR (XOR= Exklusiv-Oder).
D.h. du kannst mittels XOR schnell überprüfen, ob sich was geändert hat.
Wenn sich nichts geändert hat, dann wieder den Wert auslesen und wieder XOR, wenn sich nichts geändert hat... (usw.)
Vorteil von der Verwendung von XOR: gegenüber der Methode durch subtrahieren und auf das Zero-Flag schauen: Es geht sehr viel schneller...
Wenn sich was ändert, dann hast du eine Flanke (entweder fallend oder steigend).
D.h. du gehst jetzt hin und speicherst den Wert im RAM als Xalt zwischen (denn es kann ja immer der böse Timer-Interrupr kommen und dein pollen unterbrechen). Dann brauchst du nur noch schaun, ob dein Xalt ne 1 ist (dann wars vorher ne 0) oder ne 0 (dann wars vorher ne 1). Daraus kannst du dann ablesen welche Flanke es war.
Und mittels btfsc kannst du dann das Bit Xalt prüfen und schauen, wohin du springen musst (d.h. welcher Programmabschnitt ausgeführt werden muss).

So, aber eigentlich will ich dir nicht alle Arbeit abnehmen und du sollst dir selber auch ein paar Gedanken machen...

Daher les einfach mal das Datenblatt durch (vielleicht nicht das ganze, aber zumindest die dich betreffenden Teile).

Und du solltest dir überlegen, was du mittels Interrupts machen willst, und was du per Schleife machen willst (also pollen). Überleg dir das mal und schreib es hier hin. Ich sag dir dann schon, wenns falsch ist ;)

stegr
02.11.2004, 10:08
Interrupts...

wenn man Interrupts verwendet, ist es kein Problem auf steigende oder fallende Flanken zu detektieren (kann man im Datenblatt bzw. im User Guide nachlesen).

ansonsten hat unser lieber Gast schon gesagt wie es geht:

Du pollst den Pin (d.h. fragst ihn ständig ab) und speicherst den Status des Pins im RAM. Dann nimmst du den aktuellen Wert am PIN und vergleichst ihn mit dem vorherigen (im RAM abgelegten) Wert. Wenn die gleich sind, gabs keine Änderung, bedeutet: Flanken gibt es nur wenn sich was ändert.
=> Wahrheitstabelle:

Xalt | Xneu | Resultat (Änderung?)
0 | 0 | keine Änderung (0)
0 | 1 | steigende Flanke (1)
1 | 0 | fallende Flanke (1)
1 | 1 | keine Änderung (0)

und diese Wahrheitstabelle entspricht der für XOR (XOR= Exklusiv-Oder).
D.h. du kannst mittels XOR schnell überprüfen, ob sich was geändert hat.
Wenn sich nichts geändert hat, dann wieder den Wert auslesen und wieder XOR, wenn sich nichts geändert hat... (usw.)
Vorteil von der Verwendung von XOR: gegenüber der Methode durch subtrahieren und auf das Zero-Flag schauen: Es geht sehr viel schneller...
Wenn sich was ändert, dann hast du eine Flanke (entweder fallend oder steigend).
D.h. du gehst jetzt hin und speicherst den Wert im RAM als Xalt zwischen (denn es kann ja immer der böse Timer-Interrupr kommen und dein pollen unterbrechen). Dann brauchst du nur noch schaun, ob dein Xalt ne 1 ist (dann wars vorher ne 0) oder ne 0 (dann wars vorher ne 1). Daraus kannst du dann ablesen welche Flanke es war.
Und mittels btfsc kannst du dann das Bit Xalt prüfen und schauen, wohin du springen musst (d.h. welcher Programmabschnitt ausgeführt werden muss).

So, aber eigentlich will ich dir nicht alle Arbeit abnehmen und du sollst dir selber auch ein paar Gedanken machen...

Daher les einfach mal das Datenblatt durch (vielleicht nicht das ganze, aber zumindest die dich betreffenden Teile).

Und du solltest dir überlegen, was du mittels Interrupts machen willst, und was du per Schleife machen willst (also pollen). Überleg dir das mal und schreib es hier hin. Ich sag dir dann schon, wenns falsch ist ;)

^^mein Beitrag; der Beitrag von "Gast" dort oben aber nicht... 8-[

so langsam sollte ich jetzt auf allen 3 von mir genutzten Rechnern eingeloggt sein O:)

02.11.2004, 10:08
Wenn es eine Änderung gegeben hat, geht der wert vom Port nach "VORHER" für die nächste abfrage (schleife)

Du kannst auch zwei Schleifen machen, eine lauert auf "1", die andere auf "0".

MAIN
clrf PORTx

WAIT_1
btfsc PORTx, pin-Nr
b WAIT_2
incf TIMER_low
b WAIT_1
WAIT_2
btfss PORTx, pin-Nr
b gotcha
incf TIMER_hi
b WAIT_2
gotcha ; pin is jetzt wieder auf LOW
; work out counter-values
b MAIN ; auf ein neues

die Counter-Werte hängen jetzt natürlich von der Befehlsanzahl etc. ab,
aber viel kürzer wird das ganze wohl nicht gehen.

D.Stolarek
02.11.2004, 10:18
Hi Gast Nr.2,

habe schon vor einigen wochen versucht einen interrupt für den timer zu nehmen, aber ich bekam es einfach nicht hin.
deswegen habe ich mich entschlossen, zu versuchen alles ohne interrupts zu machen, sondern nur durch schleifen und anderem kram.

durch deine erklärung weiss ich nun was der Gast Nr.1 meinte.
danke dafür ^^.

Danke Leute
Bin zulangsam mit Tippen gewesen und habs nich gemerkt das ihr was geschrieben habt.
Danke Nochmal an Gast der da auch nen Code reingesetzt hat Dankedankedanke
ihr seid wirklich eine Große hilfe ^^

Gruß
D.Stolarek