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
Nimm einfach den 89LP4052, der hat den Timer2 und ist 6mal so schnell.
Mit dem Timer2 hab ich doch etwas übertrieben, er hat nur 2 16-Bit-Timer Die Befehlszyklen werden aber 12mal so schnell abgearbeitet.
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
>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
> > 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 ...
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.