Forum: Mikrocontroller und Digitale Elektronik Serial Interrupt & Baudrate bei 8051


von Stefan (Gast)


Lesenswert?

Guten Morgen allerseits,
ich habe bei einem AT89C4051 die Aufgabe, dass ich über die UART daten 
empfangen und so schnell wie möglich wegschreiben muss.
ich habe für den Empfang eine ISR geschrieben (pollen des RI Flags in 
der Main ohne eine ISR ist meines erachtens aus performance Gründen 
nicht möglich)
Mein Problem ist nun, dass der Serial Interrupt so schnell nacheinander 
auftritt, dass die die CPU in stolpern gerät (das 4. Byte wird als das 
5. Interpretiert).

Meine überlegung war nun dass ich in der zeit in der der Serial 
Interrupt extrem schnell nacheinander auftritt (16 Byte in Folge) 
einfach in der ISR geblieben wird und nur noch das RI Flag in einer 
while(RI == 0) gepollt wird bis ich das nächste mal den SBUF auslesen 
kann (dadurch würde ich mir den aufwänden Taskswitch spaaren).
Am Anfang der ISR setze ich das RI Flag zurück auf Null, jedoch wird in 
der ISR das RI Flag meiner meinung nach nicht mehr gesetzt.
Laut Datenblatt der 8051 Familie vermute ich nun, dass alle gleich und 
niederprioren Interrupts maskierten werden solange ich noch in der ISR 
bin und das Flag deswegen nicht mehr gesetzt wird.

Kann das sein?
von den neuen ATMega (also der neuen RISC Architektur) weiß ich dass es 
dort möglich ist im Interrupt das gleiche Flag das diesen Interrupt 
ausgelöst hat erneut in dessen ISR abzufragen und dass dieses flag auch 
wieder gesetzt wird ...

Mein 2. Lösungsansatz war, die Fosz zu erhöhen (aktuell läuft die CPU 
auf 16 MHz). Dabei taten sich aber neue Probleme auf.
Die Baudrate mit der Daten auf der UART ankommen beträgt 250kBaud. Von 
anderen Projekten mit der 8051 Architektur weiß ich, dass ich 250kBaud 
nur mit dem Timer2 als Baudrate-Generator erreichen kann.
Außer in dem Sonderfall man hat einen 16MHz Quarz als Fosz und verwendet 
den Mode2 mit 1/64 Teiler das ergibt auch exakt 250kBaud. Genauso war es 
bisher realisiert).
Da der 4051 eine Fosz von 24MHz abkann,  habe ich nun also versucht bei 
einer Fosz von 24MHz eine Baudrate von 250kBaud zu erreichen. Dabei habe 
ich festgestellt dass laut www.atmel.com der 4051 nur 2 Timer hat und 
nicht drei. Da ich es bisher nicht zum laufen gebracht habe vermute ich 
nun dass nur Timer0 und Timer1 im 4051 implementiert sind. Diese beiden 
Timer haben haben aber im Gegensatz zum Timer2 einen höheren 
CLK-Prescaller vorgeschalten (ich glaub es ist ein 1/12 Teiler von Fosz 
vor den beiden Timern im gegensatz zu Timer2 bei dem Fosz nur durch 2 
geteilt wird).


Die Große Frage ist nun:
Gibt eines möglichkeit in der ISR das RI Flag abzufragen oder irgendwie 
in der ISR einen neuen serial Interrupt mitzubekommen.
UND
Wie bekomme ich bei einer Fosz != 16MHz eine Baudrate von 250kBaud bei 
einem AT89C4051 hin??

Viele dank schon mal für eure Mühen ...
Mfg Stefan

von jack (Gast)


Lesenswert?

Nimm einfach den 89LP4052, der hat den Timer2 und ist 6mal so schnell.

von jack (Gast)


Lesenswert?

Mit dem Timer2 hab ich doch etwas übertrieben, er hat nur 2 16-Bit-Timer
Die Befehlszyklen werden aber 12mal so schnell abgearbeitet.

von Peter D. (peda)


Lesenswert?

Stefan wrote:
> Mein Problem ist nun, dass der Serial Interrupt so schnell nacheinander
> auftritt, dass die die CPU in stolpern gerät (das 4. Byte wird als das
> 5. Interpretiert).

Bei 16Mhz und 250kBaud hast Du 53 Zyklen für den Interrupt, sollte 
eigentlich dicke reichen.
Um mehr zu sagen, müßte man Deinen Code sehen.


> Meine überlegung war nun dass ich in der zeit in der der Serial
> Interrupt extrem schnell nacheinander auftritt (16 Byte in Folge)
> einfach in der ISR geblieben wird und nur noch das RI Flag in einer
> while(RI == 0) gepollt wird bis ich das nächste mal den SBUF auslesen
> kann (dadurch würde ich mir den aufwänden Taskswitch spaaren).

So aufwendig ist das beim 8051 nicht (6 Zyklen), ist ja schließlich kein 
ARM.


> Am Anfang der ISR setze ich das RI Flag zurück auf Null, jedoch wird in
> der ISR das RI Flag meiner meinung nach nicht mehr gesetzt.

Woher hast Du diese (falsche) Meinung?

Es wird natürlich immer gesetzt, sobald ein Byte empfangen wurde (Mitte 
des 9. bzw. des Stopbits).


Peter

von jack (Gast)


Lesenswert?

>Wie bekomme ich bei einer Fosz != 16MHz eine Baudrate von 250kBaud bei
>einem AT89C4051 hin??

Baudrate = 16MHz / 32 * (256 - TH1)

Bei TH1 = 254 ergeben sich 250kBaud

von jack (Gast)


Lesenswert?

Klammer hat gefehlt:

Baudrate = 16MHz / (32 * (256 - TH1))

von Stefan (Gast)


Lesenswert?

> > Am Anfang der ISR setze ich das RI Flag zurück auf Null, jedoch wird in
> > der ISR das RI Flag meiner meinung nach nicht mehr gesetzt.
>
> Woher hast Du diese (falsche) Meinung?
>
> Es wird natürlich immer gesetzt, sobald ein Byte empfangen wurde (Mitte
> des 9. bzw. des Stopbits).

Also eigentlich bin ich davon ausgegangen, dass das RI flag immer 
gesetzt werden muss auch wenn ich in der ISR bin.
Jetzt hab ich das auch ausprobiert und hab folgendes in der ISR gemacht
void Init(void)
{
   SCON =  0x90; // UART Initialisierung  Modus 2 & REN setzen
   EA = 1;  // globale Interruptfreigabe
   RB8 = 1;    // Framing Error rücksetzten
}
void RS_irq(void) interrupt 4 using 2
{
   RI = 0;

   (...)

   while(RI != 1)
      P1_1 = ~P1_1;

   (...)
}

Leider musste ich am Osszi feststellen dass P1_1 mit vollgas pollt und 
auch nicht mehr damit aufhören will ...

Die Überlegung mit dem Ausweichen auf einen anderen Prozessor hatte ich 
auch schon. Da jedoch schon Platinen für viel geld gefertigt worden sind 
wäre die eizigen möglichkeit einen Prozessor mit annähernd identischem 
Pinout zu nehmen.

> >Wie bekomme ich bei einer Fosz != 16MHz eine Baudrate von 250kBaud bei
> >einem AT89C4051 hin??
>
> Baudrate = 16MHz / 32 * (256 - TH1)
>
> Bei TH1 = 254 ergeben sich 250kBaud

Ich hatte das selbe Problem beim Sender die 250kBaud zu erziehlen. Dort 
hatte ich jedoch einen AT89C51RD2 und dieser wunderschöne Typ der 
8051Familie hat 3 Timer (Timer0, Timer1, Timer2). Aus meiner Erfahrung 
bei der Arbeit mit diesem Controller weiß ich, dass Timer0 und Timer1 
einen Festen CLK-Prescaller haben von 12, dadurch ist NUR mit Timer2 die 
Baudrate von 250k zu erreichen (Timer2 hat einen CLK-Prescaller von nur 
2). Deshalb geh ich mal davon aus, dass die beiden Timer des AT98C4051 
auch den CLK/12 haben.
Ist das so richtig?

Und warum komme ich in der ISR nicht mehr aus der while(...) raus?

Im moment bin ich eigentlich der meinung, dass das Erhöhen des Fosz 
nicht möglich ist, auf Grund des Timerproblems. Bitte korrigiert meine 
Meinung wenn ich voll daneben lieg.

Eine weiter Idee die mir gekommen ist, wäre nun die ISR also 
Inline-Assembler zu schreiben. Ich denke die dadurch höhere effizienz 
des codes könnte schon reichen. Problem beim der sache:
1. ich kann kein Assembler
2. das Assembler was mir in den kopf gehämmert wurde hasse ich seither 
:-D

Ganz davon abgesehen verstehe ich nicht warum das RI Flag scheinbar 
nicht mehr gesetzt wird ...

von Stefan (Gast)


Lesenswert?

Achja

schonmal ein ganz dickes DANKESCHÖN an euch alle für eure Mühen

Ich hab in diesem Forum schon bei vielen Problemen Lösungen gefunden
oder richtig gute Hilfe bekommen.

Bin wirklich begeister ...

Gruß Stefan

von Peter D. (peda)


Lesenswert?

Stefan wrote:

> Leider musste ich am Osszi feststellen dass P1_1 mit vollgas pollt und
> auch nicht mehr damit aufhören will ...

Kann man an diesen zusammenhanglosen Codefragmenten überhaupt nicht 
erkennen.
Du mußt schon einen lauffähigen Testcode posten (als Anhang!).

Und hau mal das "using 2" weg, das bringt nichts (höchstens Probleme).


> Die Überlegung mit dem Ausweichen auf einen anderen Prozessor hatte ich
> auch schon.

Solange Du nicht weißt, wo das Problem liegt, bringt es nichts. Das 
Problem kann dann auf dem anderen MC genauso auftreten.


> 2). Deshalb geh ich mal davon aus, dass die beiden Timer des AT98C4051
> auch den CLK/12 haben.
> Ist das so richtig?

Ja.


> Und warum komme ich in der ISR nicht mehr aus der while(...) raus?

Code zeigen, ich kann nicht hellsehen.


> Im moment bin ich eigentlich der meinung, dass das Erhöhen des Fosz
> nicht möglich ist, auf Grund des Timerproblems. Bitte korrigiert meine
> Meinung wenn ich voll daneben lieg.

Ja, beim AT89C4051 geht nur 16Mhz für 250kBaud.


> Eine weiter Idee die mir gekommen ist, wäre nun die ISR also
> Inline-Assembler zu schreiben. Ich denke die dadurch höhere effizienz
> des codes könnte schon reichen.

Meistens bringt Umstellen des Programmablaufs wesentlich mehr, als 
Assembler.


> Ganz davon abgesehen verstehe ich nicht warum das RI Flag scheinbar
> nicht mehr gesetzt wird ...

Du sendest dem AT89C4051 aber schon mehrere Bytes?


Peter

von Stefan (Gast)


Lesenswert?

Erst mal Guten Morgen allerseits,

Tut mir wirklich leid, dass ich nicht den vollständigen Code 
veröffentlichen kann, aber da dieser im Rahmen eines Praxissemesters 
entstanden ist, kann ich das leider nicht tun (der Chef hat da deutlich 
was dagegen xD)

Zur Menge der Bytes...
Der datenverkehr sieht so aus, das immer als frame mehrere Hundert bytes 
gesendet werden von welchen ich mir ein paar wenige rauspicken muss und 
intern auf dem CPU-RAM wegschreiben muss. Nach jedem Frame gibt es eine 
ausreichende Pause um die empfangenen Daten zu verarbeiten und auf den 
nächsten Frame zu warten (wird durch das RB8-Bit erkannt)
Solange ich keine Daten speichern muss klappt das ganze wunderbar,
sobald ich jedoch mehr als 4 bytes speicher muss, stolpert die Cpu und 
das 5. Byte wird als 4. interpretiert.

Mir ist natürlich klar dass man (speziall Peter) mir jetzt nicht mehr so 
wirklich weiterhelfen kann, aber wenn ich schon mal weiß, dass auch wenn 
sich die CPU in der ISR befindet das RI-Flag gesetzt werden muss, dann 
ist mir schon sehr geholfe und ich hab nen Punkt wo ich ansetzen kann.
Auch danke an Peter für die klaren Worte bzgl. Timer & Fosz. Damit kann 
ich diese Lösung auch schon mal ausschließen.

Ich danke euch vielmals

Stefan

von Peter D. (peda)


Lesenswert?

Stefan wrote:

> Tut mir wirklich leid, dass ich nicht den vollständigen Code
> veröffentlichen kann

Den will ja auch keiner.

Es ging erstmal nur um den vollständigen Testcode, wo Dein Problem mit 
dem RI-Polling auftritt.


Für ne generelle Einschätzung, ob Du ein Problem hast, braucht man aber 
den kompletten UART-Interrupthandler inclusive aller darin aufgerufenen 
Unterfunktionen.

Auch muß man wissen, ob Du noch weitere Interrupts hast, die nicht eine 
niedere Priorität als der UART-Interrupt haben.

Wenn Du lange Zeiten hast, wo generell Interrupts gesperrt sind oder 
andere  lange Interrupts gleicher Priorität den UART-Interrupt 
verhindern, hat der natürlich kein Chance mehr.


> sobald ich jedoch mehr als 4 bytes speicher muss, stolpert die Cpu und
> das 5. Byte wird als 4. interpretiert.

Kommt drauf an, ob die CPU jedesmal x-dimensionale Feldindexe neu 
berechnen muß oder einfach linear per Pointer zugreift.


Peter

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.