Forum: Mikrocontroller und Digitale Elektronik exact timing - 8051 - synchronisierte Zustandsmaschine


von daniel (Gast)


Angehängte Dateien:

Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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:
1
dseg at 30h
2
  countdown50:  ds 1
3
  countdown150: ds 1
4
  countdown250: ds 1
5
cseg
6
..
7
  djnz   countdown50, m1
8
  mov    countdown50, #50
9
.. do 0,5s tasks
10
m1:
11
  djnz   countdown150, m2
12
  mov    countdown150, #150
13
.. do 1,5s tasks
14
m2:
15
  djnz   countdown250, m3
16
  mov    countdown250, #250
17
.. do 2,5s tasks
18
m3:
19
..


Peter

von daniel (Gast)


Lesenswert?

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:
1
PUSH  ACC
2
PUSH  PSW
3
; timer reload
4
CLR   EA
5
CLR   TR0 ; stop by 16 bit addition
6
MOV   A, #256 - TO_RELOAD_LOW + 6  ; 5 MC(MOV,ADD,..) + 1 MC(RUN) ??
7
ADD   TL0, A
8
MOV   A, #256 - TO_REALOAD_HIGH     ; 
9
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

von daniel (Gast)


Lesenswert?

Hi,
Nun noch zu dem Problem der Main:
1
MAIN:  
2
  ; main task - execute States
3
  JBC  STATEBIT,  STATEM
4
  ; check of recieve datagram
5
  JBC    RECVBIT,  JRECV
6
  ; check of byte send finished
7
  JBC  SENDBIT,  JSEND
8
  SJMP   MAIN
9
  ; 8 MC
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 !

von daniel (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von daniel (Gast)


Lesenswert?

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

von daniel (Gast)


Lesenswert?

Hi,
es muss
TH0 = FF + 8 - 24
TL = FF - 00
sein.

Daniel

von daniel (Gast)


Lesenswert?

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

von daniel (Gast)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.