Hallo,
ich habe ein Problem mit dem UART des ALVIDI AT90CAN128-16AU Board.
Ich kann Daten an den Controller richtig versenden, aber keine vom
Controller zum PC. Manchmal kommt etwas an, aber nur falsche Zeichen.
Ich kann zwar mit dem Oszilloskop auf der Senseleitung Signale sehen,
die sind jedoch sehr kurz. Ich hab mich im Datenblatt und anderen Foren
bei ähnlichen Problemen eingelesen und bin der Meinung, dass der UART
richtig
eingestellt ist.
Das ist der gesamte Code für den UART. Wenn ich ein Zeichen senden
möchte,
rufe ich nur die Funktion send_char('c'); auf.
Da das empfangen richtig funktioniert, müsste die Baudrate eigentlich
richtig sein.
Ich bin mit meinem Latein am Ende. Mit den LED's auf dem Board konnte
ich sehen, dass die Funktion send_char(); vollständig abgearbeitet wird.
Hallo Jens,
auf den ersten Blick sehe ich auch keinen Fehler.
Aber alternativ zum
Jens schrieb:> while(!(UCSR0A & (1<<UDRE0)));//Wait for empty transmit buffer
kannst Du mal
while(!(UCSR0A & (1<<TXC0)); ausprobieren.
// wenn 1 dann zurücksetzen.
USCR0A |= (1<<TXC0); // Datenblatt unter UART-Discriptionregister.
Dieses Flag muss bewußt mit 1 beschrieben werden, um es zu löschen.
Hier solltest Du Deine LED toggeln lassen, damit Du auf dem Scope etwas
sehen kannst, dass die Bytes alle gesendet worden sind. Oder Du zählst
einen PORT hoch (inkrementieren) und gibst ihn LEDs aus. Anhand derer
kannst Du dann nachzählen (binär natürlich) wie viele Bytes tatsächlich
gesendet worden sind.
Ansonsten empfehle ich Dir die Anschaffung eines Debuggers. So ein
Dragon kostet nur 50-60 Euro. Die Dinger sind eine große Hilfe.
Wie Du festgestellt hast, dass Du korrekt vom PC empfängst?
Mit welcher Baudrate und Quarzfreguenz arbeitest Du?
So ein Verhalten wäre erklärlich, wenn nach dem send_char() ein sleep
käme. Und im Falle daß ein Bootlader installiert ist, wäre es sicher
besser die Register beim Init nicht zu verodern. 19.2kB@16MHz ? Fuses
richtig gesetzt ?
Danke für die Antworten.
Ich arbeite mit einer Baufrate von 19200 bei einer Frequenz von 16MHz.
Im Hauptprogramm wird permanent abgefragt, ob ein Byte angekommen ist.
Ich frage dann nach den übertragenen Befehlen ab und setze bei Erfolg
eine LED. Ausserdem wird dann ein Pulsbreitenmuster an einem Ausgang
geändert. So weit
funktioniert alles. Bei einem Befehl soll allerdings eine Antwort
gesendet werden, die jedoch nicht ankommt.
Die Fuse-Bits hab ich im Anhang als Bild engehängt. Ich glaube bei dem
Board wird ein Bootloader verwendet, allerdings weiß ich nicht gut
darüber bescheid. Welche Register sollte ich denn nicht ändern?
@cskulkw: Ich habe es so ausprobiert:
1
while(!(UCSR0A&(1<<TXC0)));
2
UDR0=i;
3
UCSR0A|=(1<<TXC0);
hat allerdings nicht geholfen. Das Programm läuft nicht weiter. Es
scheint als wäre das eine Endlosschleife.
Hallo Jens,
wenn Du meinen Vorschlag benutzt, dann mußt Du erst die Daten in das
UDR0 laden und dann auf das Gesendet-Bit prüfen.
UDR0 = i;
while(!(UCSR0A & (1<<TXC0)));
UCSR0A |= (1<<TXC0);
Ich gebe zu, daß ich daran nicht gedacht hatte. Wenn nach der
Initialisierung noch nichts gesendet worden ist, dann wird das Flag noch
nicht gesetzt sein. Insofern erklärt sich mir die Endlosschleife.
Bei jedem erfolgreichen Durchlauf würde ich eine Variable mitzählen
lassen und auf einem Port ausgeben, wenn Du das umsetzen kannst.
...
Jens schrieb:> Welche Register sollte ich denn nicht ändern?
Ändern schon, ich wollte nur darauf hinweisen, daß das hier:
1
UCSR0B|=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
2
UCSR0C|=(1<<UCSZ01)|(1<<UCSZ00);
bei einem Bootlader gefährlich ist, denn es bleiben vom BL ggf. gesetzte
Registerinhalte in UCSR0B/0C durch das "oder" erhalten.
Wenn man die Inhalte genau bestimmen möchte, dann würde man nur "=" ohne
"|" schreiben.
Die Endlosschleife ist mit der Änderung weg, aber es kommt auch so
nichts an. Das Mitzählen ist nur sehr begrenzt möglich. Ich hab nur vier
LED's zur Verfügung.
@MWS:
Ach das hast du damit gemeint. Ich war mir da nicht ganz sicher. Ich hab
die Variante ohne | auch schon ausprobiert. Es blieb aber bei dem selben
Ergebnis.
Jens schrieb:> Ich kann Daten an den Controller richtig versenden
Das impliziert zwar, daß die Registereinstellungen passen, nur wenn ein
Bootlader drauf ist, dann würde ich schon sichergehen wollen, daß jedes
der beteiligten Register neu initialisiert wurde, da gehört auch UCSR0A
und darin U2X0 und MPCM0 dazu.
Wie umfangreich ist denn der gesamte Code ? Meist ist der Fehler im
nicht geposteten Teil.
Da geb ich dir Recht. Ich poste dann mal das komplette Hauptprogramm.
Ich werd die Register mal setzen und poste dann das Ergebnis.
Der Controller soll bei den Befehl "con" alle Variablen über die UART
senden. Der Rest des Codes funktioniert. Der Controller gelangt auch zu
den Aufrufen der send_char() Funktionen.
1
/***** MAIN ******************************************************************/
2
intmain(void){
3
4
/***** The first initalization *****************************/
5
DDRB=0xFF;//Port B is configured as an output port
6
DDRE=0xFF;//Port E is configured as an output port
7
DDRF=0xFF;//Port D is configured as an output port
Daraus ist nicht viel zu erkennen, außer den paar UART-Ausgabeaufrufen.
Seit wann hast Du denn das Problem ? Sieht mir doch wie einigermaßen
fortgeschrittener Code aus, der zudem das UART benötigt, das muss Dir
doch schon länger aufgefallen sein.
Die HW-Seite sollte man zuerst überprüfen, da gibt's 2 Jumper am UART,
sind die richtig gesteckt ? Auch geht das UART an den ISP, da ist auch
nichts verbunden ?
Ich würde versuchen ob die Kommunikation über den PC ohne Controller
klappt. Schau Dir den Schaltplan zu dem Modul an. Man könnte über einen
Kontakt des Jumpers an Out des MAX3232 wieder auf den anderen Kontakt
des Jumpers an In zurückschleifen. Damit sieht man dann im Terminal ob
die Verbindung PC/MAX und zurück ok ist.
Auch wär's sinnvoll einen abgespeckten Code zu schreiben, der nur den
Fehler des UART's zeigt und dann eine compilierbare Version hier
einstellen, sonst ist das wie im Trüben fischen.
Der Fehler ist mir erst seit ein paar Tagen bekannt. Ich habe aber noch
keine funktionierende Version gehabt, da ich es erst vor kurzem
fertiggestellt habe.
Die Register habe ich jetzt wie folgt geändert.
UCSR0B=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0)|(0<<RXB80)|(0<<TXB80)|(0<<UCSZ2);//Enable receiver and transmitter
5
UCSR0C=(0<<UMSEL0)|(0<<UPM00)|(0<<UPM01)|(1<<UCSZ01)|(1<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01)|(0<<UCSZ02);//Set frame format: 8data, 1stop bit
6
UCSR0A=(0<<U2X0)|(0<<MPCM0)|(0<<UDRE0);
7
read=buffer;//Initialization of the pointer
8
write=buffer;
9
}
Die Jumper sind richtig gesetzt, das habe ich schon mehrmals geprüft.
Den Programmer ziehe ich immer wieder ab, sodass am ISP ebenfalls nichts
verbunden ist.
Den Code werde ich mal auf ein Minimum herabsetzen. Den letzten Teil
habe ich nicht verstanden. Ich soll quasi die TxD und RxD Leitungen
kurzschliessen, aber die Verbindung über das RS232-Kabel bestehen
lassen, damit ich das abgeschickte Zeichen im Terminal auch empfange?
Jens schrieb:> Den letzten Teil> habe ich nicht verstanden. Ich soll quasi die TxD und RxD Leitungen> kurzschliessen, aber die Verbindung über das RS232-Kabel bestehen> lassen, damit ich das abgeschickte Zeichen im Terminal auch empfange?
Ja, genau. Ein Loopback-Test. Ich fand 2 Schaltpläne, einmal mit
externen Ram, einmal ohne, bei beiden sind es aber R12/R13 470 Ohm, die
vom MAX auf die Jumper gehen, verbindet man diese an den Jumpern
miteinander, so müssen eingegebene Zeichen am Terminal erscheinen. Wenn
das nicht klappen würde, braucht man an der SW nicht groß weitersuchen.
Hab' mir die Fusesettings von oben nochmal angesehen, wenn Du nichts
verändert hast, dürftest Du sowieso keine Probleme mit dem Bootlader
bzw. mit Überresten davon bekommen, da der ausgeschaltet ist, BOOTRST =
1.
Die Fuse Bits sind genauso wie im Bild gesetzt.
Ich habe jetzt einfach die beiden Kabel RxD und TxD vom RS232-Kabel das
am PC angeschlossen ist kurzgeschlossen. Die abgesendeten Zeichen kamen
nicht an. Allerdings bin ich mir jetzt nicht sicher ob ich es richtig
gemacht habe.
Ich habe HTerm verwendet. Im Bild sind die Einstellungen zu sehen.
Jens schrieb:> Allerdings bin ich mir jetzt nicht sicher ob ich es richtig> gemacht habe.
Das Zusammenschließen oder die Benutzung von HTerm ?
Aber mir ist da auch ein faux-pas unterlaufen, sorr. Hab's gerade
gemerkt als ich die Zeichnung für Dich gemacht hab'. Nicht die
Widerstände untereinander verbinden, sondern so wie in der Zeichnung.
Konnte aber nix passieren, außer daß es halt nicht geht.
Jens schrieb:> Ok dann hab ich es richtig gemacht. Da kam nichts am Terminal an.
Einstellungen HTerm alle ok ?
Würd' mir zyklisch immer nur ein Zeichen schicken lassen, außer Du bist
sicher, daß der Empfang klappt.
Evtl. wär' jetzt ein guter Zeitpunkt die Kabelverbindung PC/µC zu
prüfen, man kann selbiges auch direkt mit dem Kabel machen, also Brücke
TX/RX, natürlich ohne angeschlossenen MAX. Sollte das dann gehen, wäre
der Fehler im oder in der Elektrik zum MAX zu suchen.
Serielles Kabel auch an Pin 34 & 36, DB S. 4 angeschlossen ?
Ich finde die Beschreibung des DB's irreführend, wenn man auf Seite 2
schaut, steht bei PE0..1 Pin 9 & 10 auch RS232, wobei RS232 da nix zu
suchen hat, denn das sind die µC-Pins und die haben TTL-Level.
RS232 hat üblicherweise ~ +-12V und ist gegenüber RDX/TXD invertiert,
genau dafür braucht's ja den MAX.
Der Empfang klappt definitiv. Die direkte Brücke am Kabel hab ich auch
schon getestet. Hat auch nicht geklappt. Mit dem HTerm kenn ich mich
nicht aus, kann auch ein Bedienungsfehler sein.
Die Anschlüsse am Controller hab ich geprüft, die ist definitiv richtig.
Mit dem Datenblatt hast du Recht, ist ein wenig irreführend. Ich werd
als nächstes mal das Kabel auf einen Bruch testen. Das kann ich
allerdings erst morgen machen, da ich kein Messgerät habe.
Ansonsten werde ich mal den zweiten UART ausprobieren.
Vielen Dank, dass du dir die Zeit genommen hast mir zu helfen. Ich werde
dann morgen berichten.
Jetzt funktioniert auch die Datenübertragung vom Controller zum PC. Das
RS232-Kabel hatte einen Kabelbruch. Nach dem Austausch hat alles
reibungslos funktioniert.
Vielen Dank an alle, die mir geholfen haben.