Hallo, hier etwas was mich viel Zeit gekostet hat. Vieleicht hilft es jemand in der Zukunft. Ich brauche für eine Anwendung 4 serielle Schnittstellen. Ich habe einen ATMega32 und einen TL16C554 genommen. Lief auf Anhieb, den 554 benutze ich schon länger an einem ATMega128 wo aber der Bus benutzt wird. PortB vom ATMega32 ist der Datenport vom 554 und muss dementsprechend von Input auf Output und zurück umgeschaltet werden. Alles lief interruptgesteuert super bis ich ein 0xFF empfangen habe. Um die Sache abzukürzen, laut Datenblatt kann der Port nicht einfach von Input auf Output und umgekehrt geschaltet werden (RTFM ich weiss...), es muss ein Zwischenzustand programmiert werden. Bitte beachten, ich habe das vorher nirgendwo gelesen oder gehört. Peter
und wie wird das dann programmiert? kannst du mal den auszug aus dem code hier rein schreiben? und was für einen zwischenzustand meinst du?
Umschalten auf Output: //Transition DDRB = 0x00; PORTB = 0xff; //Output DDRB = 0xff; //Byte output PORTB = TL_byte; ..... Umschalten auf Input: //Input DDRB = 0x00; PORTB = 0x00; //Byte input TL_byte = PINB; Peter
"Um die Sache abzukürzen, laut Datenblatt kann der Port nicht einfach von Input auf Output und umgekehrt geschaltet werden (RTFM ich weiss...), es muss ein Zwischenzustand programmiert werden." Das wäre mir aber das allerneueste. Wo steht denn das im M32-Datenblatt ? Zum Umschalten muß nur das DDRx-Register geschrieben werden, sonst nix. Deine Leseroutine ist fehlerhaft, so muß es richtig sein: 1. DDRx auf Eingang schalten 2. /IOR = 0 3. NOP, damit die Daten stabil anliegen 4. PINx einlesen 5. /IOR = 1 6. DDRx auf Ausgang Setzt Du /IOR = 0 vor der Umschaltung als Eingang, gibt es Datenkämpfe. Peter
Hier ein Auszug beim ATmega8: When switching between tri-state ({DDxn, PORTxn} = 0b00) and output high ({DDxn, PORTxn} = 0b11), an intermediate state with either pull-up enabled ({DDxn, PORTxn} = 0b01) or output low ({DDxn, PORTxn} = 0b10) must occur. Normally, the pull-up enabled state is fully acceptable, as a high-impedant environment will not notice the difference between a strong high driver and a pull-up. If this is not the case, the PUD bit in the SFIOR Register can be set to disable all pull-ups in all ports. Switching between input with pull-up and output low generates the same problem. The user must use either the tri-state ({DDxn, PORTxn} = 0b00) or the output high state ({DDxn, PORTxn} = 0b11) as an intermediate step. Gut möglich, dass es beim Mega32 genauso ist. Viele Grüsse Harry
Hallo Harry, habe fix mal beim Mega32 nachgesehen es ist auch so. Aber wo ich nicht durchblicke: Was meinen die mit Tri-State, bzw. was soll da für ein Zustand am Port herrschen? Gruß Stevko
Der Tristate-Zustand ist folgender: DDRX auf 0 PORTX auf 0 interne Pull-Ups enabled DDRX auf 0 PORTX auf 1 MW
Die Betonung liegt aber auf: "Normally, the pull-up enabled state is fully acceptable" D.h. nur wenn es dem angeschlossenen IC nicht wurscht ist, muß man Maßnahmen ergreifen ! Üblicher Weise ist Peripherie-ICs der Datenbus aber wurscht, wenn /IOW und /IOR = 1. Und in Deinem Fall ist es auch so und Du darfst beliebig auf DDRx schreiben, solange /IOW = /IOR = 1 ist. Hauptsache DDRx = 0x00 während der gesamten Zeit, wo /IOR = 0 ist, sonst sind ja beide ICs Ausgänge und kämpfen gegeneinander. Peter
Bei normaler Portrichtungsumschaltung mit DIR = 0x00 bzw 0xFF konnte nach Empfang von 0xFF nicht mehr auf Output umgeschaltet werden. Das Problem trat ja nicht bei allen anderen Bitkombinationen, sondern nur bei 0xFF auch. Steht ja auch eigentlich so im Datenblatt. Ich will auch keine Diskussion hier entfachen, es ging erst nachdem der Port wie das Programmbeispiel zeigt, programmiert wurde. Wers nicht glaubt solls einfach überlesen. Peter
@Michael Wilhelm und Peter Dannegger ok, das war verständlich @Peter Habe ich Deine Seitenangabe überlesen? Ist das nur bei PortB oder bei allen Ports? Interessiert mich, da bei meinem Mega32 alle Ports voll sind und teilweise auch zwischen Out/In geschaltet wird. Gruß Stevko
Hallo Stevko, das Problem tritt laut Datenblatt bei allen Ports auf aber nur wenn du den ganzen Port umschaltest und den Mode änderst Wenn du einzelne Bits umschaltest macht das keine Probleme. Ich wollte in diesem Forum auf diese Besonderheit hinweisen, es hat mich eine Menge Zeit gekostet diesen Fehler zu finden. Im meinem anfänglichen Programm habe ich einfach den Port zwischen Input ohne Pullup und Output mit Pullup umgeschaltet. Wenn du dir das Datenblatt anschaust ist das nicht erlaubt. Ich konnte dann nichts mehr ausgeben. Peter
@Peter "Ich will auch keine Diskussion hier entfachen, es ging erst nachdem der Port wie das Programmbeispiel zeigt, programmiert wurde." wenn es hilft, den echten Fehler zu finden, warum nicht ? Poste dochmal den kompletten Code zum Lesen und Schreiben eines Bytes inclusive der wichtigen /IOR und /IOW Signale und nicht nur die Fragmente, mit denen keiner was anfangen kann. Jedenfalls, wenn Du ohne /IOR = 0 zu setzen sofort nach der Richtungsumschaltung auslesen kannst, dann must Du es ja davor gesetzt haben und damit haben 2 Ausgänge gegeneinander gekämpft. Völlig klar, daß man damit Fehlfunktionen provoziert. Figure 4 und 5 im TL16C554 Datenblatt zeigen ja sehr schön das richtige Signalspiel. Peter
P.S.: Poste bitte auch den vorherigen Code, der nicht ging, damit man den Unterschied erkennen kann. Peter
BTW, es hat auch nicht funktioniert mit Input mit Pullup und Output mit Pullup. Laut Datenblatt muss auch hier ein Zwischenstatus programmiert werden. Peter
Hier auf vielfachen Wunsch, allerdings hier mit PortA //---------------------------------------------------------- void TL_WR_A(char TL_reg, char TL_byte) { //Transition DDRA = 0x00; PORTA = 0xff; //Output DDRA = 0xff; //Set the register PORTB = ((PINB & 0b11111000)| TL_reg); //Byte output PORTA = TL_byte; TL_CSA_Low; //CS active TL_WR_Low; #asm("nop"); TL_WR_High; TL_CSA_High; //CS inactive } //---------------------------------------------------------- char TL_RD_A(char TL_reg) { char TL_byte; //Input DDRA = 0x00; PORTA = 0x00; //Set the register PORTB = ((PINB & 0b11111000) | TL_reg); TL_CSA_Low; //CS active TL_RD_Low; #asm("nop"); #asm("nop"); TL_byte = PINA; TL_RD_High; TL_CSA_High; //CS inactive return TL_byte; } Das folgende hat nicht funktioniert: //---------------------------------------------------------- void TL_WR_A(char TL_reg, char TL_byte) { //Set the register PORTB = ((PINB & 0b11111000) | TL_reg); //Data dir output DDRA = DIR_OUTPUT; //Byte output PORTA = TL_byte; TL_CSA_Low; //CS active TL_WR_Low; #asm("nop"); TL_WR_High; TL_CSA_High; //CS inactive } //---------------------------------------------------------- char TL_RD_A(char TL_reg) { char TL_byte; //Set the register PORTB = ((PINB & 0b11111000) | TL_reg); //Data dir input DDRA = DIR_INPUT; TL_CSA_Low; //CS active TL_RD_Low; #asm("nop"); #asm("nop"); TL_byte = PINA; TL_RD_High; TL_CSA_High; //CS inactive return TL_byte; } Der Unterschied liegt nur in der Art der Programmierung der Richtungsumkehr. Peter
Hallo, hier wird das Datenblatt falsch interpretiert. Es muss kein Zwischenzustand programmiert werden, sondern es muss zwangsläufig ein Zwischenzustand auftreten, da man zum Umschalten gewisser Portzustände den Inhalt zweier Register (DDRx und PORTx) ändern muss. Und das geht halt nur hintereinander. Wenn man z.B. ein Port von Input mit Pullup (DDRx=0, PORTx=1) auf Output von Null (DDRx=1, PORTx=9) umschalten will, dann muss zwischendurch entweder der Zustand Input ohne Pullup (DDRx=0, PORTx=0) oder der Zustand Output von 1 (DDRx=1, PORTx=1) auftreten, je nachdem in welcher Reihenfolge man die Register umsetzt. Das muss man wissen und bedenken. - Mehr will uns das Datenblatt nicht sagen - Die Funktion des Ports hat da nix mit zu tun. Man kann die Reihenfolge der Umschaltung wählen wie mann will, oder besser, wie es je nach angeschlossener Hardware sinnvoll ist. Peters Probleme haben ihre Ursache ausserhalb des AVRs. MfG Willi
Nun da sind ja doch weitere erhebliche Unterschiede: Einmal wird 0x00 / 0xFF benutzt, das andere mal DIR_INPUT / DIR_OUTPUT Dann wird PORTB maskiert vor der Richtungsumschaltung, das andere mal danach. Für eine Maskierung sollte man aber immer das PORTX Register nehmen, da Eingänge ja einen anderen Pegel haben können. Für eine richtige Überprüfung müßte man nun sämtliche unbekannten Ausdrücke kennen: DIR_INPUT, DIR_OUTPUT, TL_reg, TL_CSA_Low usw. DDRB ist auch noch wichtig. 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.