Hallo,
die Fakten: AT89C2051 - 11.0952 Mhz(Timer 1 fuer Baudrate) - Timer0 fuer
5 Sekunden-Zyklus( Zyklus beinhaltet 4 Zustaende aller 2,5 sek, 2 x 0,5
sek, und 1,5 sek)
fuer den Baudratengenerator (9600Baud) verwende ich den Wert
0xFD, ist dieser richtig? der Timer arbeitet im Autoreload Modus
nun das Hauptproblem:
der Timer 0:
Ich habe mich auf den Zaehlerwert von 9246dez festgelegt, somit habe
ich einen 10 ms Interrupt. Timer wird also mit 65536 - 9246 = 56290dez
(0xDBE1) geladen und gestartet.
Um mein Zuklus mit einzelnen Zustandszeiten zu erhalten habe ich noch
ein Register fuer die Zaehlerwerte
somit fuer:
2500ms -> 250 im Register, 500ms -> 50 und 1500ms -> 150
Die ISR sieht folgendermassen aus: SIEHE CODE.TXT
Wie muss ich das Nachladeproblem behandeln ? muss zum zahler noch 6
Maschienenzyklen dazuaddiert werden? Muss ich bei DEC TCOUNT etwas mit
den Startwerten beachten, also Startwert + 1 ?
Nun zu den Zustaenden im Zuklus nach dem das STATEBIT gesetzt ist geht
es zurueck in die Main: SIEHE CODE.TXT
Kann ich das besser loesen? Ausserdem ist hier das Problem das ich
undefinierte Zeit verliere, wenn das Statebit gesetzt ist. Da ich nicht
weiss bei welchen Befehl er sich gerade befindet, bzw wie lange es
dauert bis das STATBIT mittels JBC seine Wirkung zeigt.
Dann springt er in die Auswertung fuer die Zustaende. Ich wollte auf die
Bits in jedem State die mit SYNC gekennzeichnet sind, die genauen Zeiten
von 2,5 nachster Zustand 0,5 nachster 1,5 dann nochmal 0,5 und wieder
von vorn, erreichen. Wie ist es moeglich an diesen SYNC - Punkten den
genauen Zeitwert zu haben? Probleme dazu macht mir der Code in der Main,
da es unmoeglich wird, zu wissen, wieviel Zeit in der Main verbraucht
wird bis zu den Sprung in die Zustandsauswertung.
Ausserdem muss in der Zustandanweissung alle Zustaende fuer eine
synchronisation aufeinander abgeglichen werden. So dass (CJNE
Auswertungen) bis zur Abarbeitung von Zustand 1 genausviel Zeit vergeht
wie zur Abarbeitung von Zustand 3. Dies habe ich versucht mit NOP
Befehlen auszugleichen. Ist die Ueberlegung richtig oder hab ich da
Fehler im Code, bzw. kann man das einfacher machen?
Kann es Probleme geben bei einem leicht ungenauen Zeittiming, dass mir
der Zyklus von 5 Sekunden auseinander drifftet oder die Zeiten der
inneren Zustaende sich verschieben?
Ist ein bisschen viel aber diese Fragen beschaftigen mich schon sehr
lange und es will mir keine Loesung dazu einfallen.
Fuer Tipps und Hinweise bin ich sehr dankbar und auch fuer das Erdulden
diesen langen Beitrages ;)
Daniel
daniel wrote:
> Wie muss ich das Nachladeproblem behandeln ? muss zum zahler noch 6> Maschienenzyklen dazuaddiert werden?
Mit "MOV TH0, #T0TH0", "MOV TL0, #T0TL0" hast Du schon verloren, da die
Interrupteintrittszeit keine Konstante ist, richtig ist nur die
Addition:
http://home.tiscali.de/peterd/appl/soft/clock/index.htm
Um mein Zuklus mit einzelnen Zustandszeiten zu erhalten habe ich noch
ein Register fuer die Zaehlerwerte
somit fuer:
2500ms -> 250 im Register, 500ms -> 50 und 1500ms -> 150
Dann nimm doch einfach 3 Bytes zum zählen:
Hi,
ich danke Ihnen erst mal sehr fuer Ihre schnelle Antwort.
Die Beispiele hatte ich mir gestern abend angeschaut, habe sie aber
nicht verstanden. Doch das mit der Addition habe ich jetzt verstanden.
Diese `+2` steht wohl fuer den Befehl ADD a, th0 ?
in meinem Fall sozusagen:
ADDC THO, A ; ?? braucht er die High -> Low Reihenfolge?
10
; 5 machine cycles since timer stop
11
SETB TR0
12
SETB EA
13
14
DJNZ TIMER_REGISTER, IT0END ; timer register leer nicht springen
15
SETB TIME_EXEEDED ; die main weiss nun das sie was machen soll...
16
POP PSW
17
POP ACC
18
RETI
Ist das richtig mit den Realoden unter Beachtung das der Timer gestoppt
ist?
Ich denke in meinem Fall ist es nicht noetig, die drei Bytes zu nutzen,
da ich bis zum naechsten Ueberlauf 9426 MC Zeit habe, das Register
Nachzuladen. Ist die Annahme richtig?
Ausserdem hat er nur 128 kb RAM und ab 30h steht mein Serial Recieve
Buffer , ab 40h mein Serial Send Buffer und ab 50h der STACK.
Vielen Dank
Daniel
Wenn man vom Timer Interrupt zurueck kommt, ist es undefiniert bei
welchen Befehl er gerade ist und wie lange es dauert, bis das STATEBIT
(in der Timer 0 ISR gesetzt) seine Wirkung zeigt.
Kann man das auch anders loesen? ist es moeglich ein variablen
Sprungbefehl zu erzeugen. Zum beispiel so in der Main:
Main:
springe zu Adresse ; adresse kann variabel sein
Adresse kann sein: MAIN oder STATEM oder RECVBIT oder ...
Ist sowas moeglich? Kann man die Adressen vorher wissen oder kann der
Compiler solche MARKEN umwandeln fuer mein Sprungziel.
JMP arbeitet ja auch nur mit festen Adressen.
Muss so etwas mit einer Sprungtabelle geloest werden? Zum Beispiel so:
1
MOV DPTR, #JUMP_TABLE ; Adresse der Sprungtabelle
2
MOV A, INDEX_NUMBER ; index welche sprung man aus Tabelle moechte
3
RL A ; teile durch 2 - Sprungeintraege brauchen 2 Byte platz
4
JMP @A + DPTR
5
JUMP_TABLE: ; hier beginnt die Tabelle
6
AJMP MAIN
7
AJMP STATEM
8
AJMP RECVBYTE
9
AJMP SENDBYTE
10
.
11
.
12
.
Das waere wohl die einzige loesung eines variablen sprungzieles oder
geht es einfacher ?
Wie muss ich in meiner Zustandsabarbeitung, die Synchronisation zwischen
alle SYNC punkten erstellen? geht es so mit dem auszaehlen und den NOP
Befehlen?
Das auszaehlen der Machinenzyklen hat ein Problem wenn ich einen Sprung
mache und ein Bit setze oder nicht setze. Wie mus ich das bearbeiten
oder beachten ?
1
S0TASK:
2
MOV A, CHBYTE; ; HIGH-BYTE der Ausgabe nummer
3
RRC A ; SHIFT RIGHT
4
JNC NO_BIT ; wie ist diese Sprung bei der Zaehlung
5
;der Machinenzyklen zu beachten??
6
SETB NUMHB0 ; mitzaehlen oder nicht?!
7
; 5 MC
8
NO_BIT:
9
MOV NUML, CLBYTE ; 8 BITS SET LOW BYTE
10
SETB SIGA ;SIGNAL A SET- SYNC - auf das Bit soll die Zeit (SYNCHRONISATION)
11
; des aktuellen Zustandes gelten
SIEHE CODE.TXT aus dem STARTBEITRAG
Vielen Dank fuer Tipps und Hinweise
Daniel
PS: Oben ist beim Source die Marke IT0END vergessen, muss natuerlich vor
POP PSW !
Hallo,
die Fragen zu dem Timer- Code hat sich erledigt habe das Beispiel fuer
16 bit Timer 0 auf
http://home.tiscali.de/peterd/appl/soft/clock/index.htm uebersehen.
Statt XCH - Befehl kann man doch auch MOV nehmen oder ist es wichtig das
sie getauscht werden?
Die Frage zu der Synchronisation besteht jedoch weiterhin.
Vielen Dank
Daniel
daniel wrote:
> Statt XCH - Befehl kann man doch auch MOV nehmen oder ist es wichtig das> sie getauscht werden?
Ohne XCH muß man noch extra den ACCU sichern (PUSH+POP).
> Die Frage zu der Synchronisation besteht jedoch weiterhin.
Wie genau muß denn die Synchronität sein (in CPU-Zyklen) ?
Peter
Hallo,
gerade noch einen fatalen Fehler entdeckt!
bei 11,0592 Mhz muss er 9216dez (2400hex) Takte zaehlen fuer 10ms
Overflow. Damit meine Teilerwerte im Register stimmen
Also fuer die Reloadwerte:
TH0 = FF - 8 - 24
TL0 = FF - 00
Daniel
Hallo,
ja die Synchronitaet soll zwischen den einzelnen Zustaenden genau(in CPU
Zyklen) sein. Das bedeutet das der Zustand 3 genau die selbe Zeit
braucht wie der Zustand 1, da diese ja nacheinander abgefragt werden. Im
Code-Beispiel Code.txt habe ich diese Zeilen mit SYNC markiert. Nach
Ablauf der Zeit soll ein Zustand abgearbeitet werden. Sozusagen soll
kein Unterschied in CPU-Zyklen zwischen den einzelnen Zustaenden sein.
Speicherplatz fuer die unzaehligen NOP Befehle habe ich im Code-Bereich.
Bis zu Abarbeitung bleiben alle Interrupts ausser der Timer gesperrt. Da
auch in den Zustaenden die Teilerzeiten ins Register geladen werden.
Ich denke nicht das es passieren kann, dass der Timer Interrupt vor dem
Nachladen der Teilerzeiten eintritt (somit eine ungueltige Zeit
entsteht) da dieser erst nach 9000 CPU-Zyclen eintritt, der Code aber
weniger als 100 CPU- Zyklen betraegt.
CPU-Zyklen sind im Code mit MC(Machine Cycles) geschrieben.
Vielen Dank fuer die guten Antworten
Daniel
Hallo,
vielen Dank fuer die Hilfe. Es war mir tatsaechlich moeglich die
einelnen Zustaenden auf einander zu Synchronisieren mit plus/minus 2 CPU
Zyklen verschiebung innerhalb des Gesammtzykluses.
Die Main wurde in soweit abgeandert das sie fast konstante Zeiten
liefert.
1
;MAIN
2
MAIN:
3
JBC JMPBIT, MAINJMP
4
SJMP MAIN
5
MAINJMP:
6
MOV DPTR, #JUMP_TABLE
7
MOV A, INDEX_NUMBER
8
RL A
9
JMP @A + DPTR
10
; 6 MC
11
JUMP_TABLE:
12
AJMP MAIN ; INDEX 0 - MAIN
13
AJMP STATEM ; INDEX 1 - STATEMACHINE
14
AJMP RECVBYTE ; INDEX 2 - RECIVE BYTE
15
AJMP SENDBYTE ; INDEX 3 - RECIVE BYTE
16
SJMP MAIN
17
; 6 MC
Sinn dieser Praezision ist nur der, das es moeglich ist Code mit
prazisen Zeiten zu haben. Gibt ja schon genuegend andere
Zeitungenauigkeiten, die man nicht ausmertzen kann. Wie der Quarz und
die Temperaturabhaengigkeit.
Vielen Dank Peter fuer die sehr guten und sehr hilfreichen Antworten!
Daniel
Hallo,
es hat sich bei mir noch eine Frage ergeben.
Kann es passieren das sich die Gesammt-Zykluszeit aendert? Oder
verschiebt? Zum Beispiel nach einem Jahr die nicht mehr Zykluszeit 5 sek
betraegt sondern 5,5 sek ?
Es arbeitet nach diesem Prinzip:
Der Timer loest ein Ueberlauf aus -> ein Teilerregister wird
decrementiert (-1) -> Teilerregister null, wird ein Bit gesetzt -> durch
das Bit wird in der Main ein Sprung ausgeloest -> springt in den
aktuellen Ablaufzustand -> hier wird ein Bit gesetzt was der User als
Output zu sehen bekommt (synchronisiert auf diese Bit) -> Teilerregister
wird mit neuem Wert geladen -> ... im aktuellen Zustand -> zurueck in
Main, Bit- Polling
Somit haengt doch die Zeit alleinig vom Timer ab, also kann sie sich
nicht verschieben (nur in Ungenauigkeiten zum Quarz hin ).
Das Bit fuer den User auf das er synchronisiert, kommt dann im
Gesamtzyklus mal 1 CPU - Zyklus eher oder auch nicht, haengt von der
Auswertung vorher ab.
An der Gesamtzykluszeit aendert sich dadurch aber nichts, oder?.
Wenn man nun fuer diesen Ablauf, nach einem Jahr die Gesamtzykluszeit
misst, muesste diese doch immer noch gleich sein, oder?
Vielen Dank falls mir jemand meine Annahmen bestaetigen koennte oder mir
sagen koennte ob ein Fehler in den Annahmen sind.
Daniel
Hallo,
ich nehme an es wird sich wohl niemand mehr zu meiner Frage aeussern.
Der Beitrag ist wahrscheinlich schon unter der Deadline der ersten
Seite.
Naja, aber trotzdem vielen Dank fuer das super Forum hier !
Daniel