Hallo zusammen,
ich habe einen ATTiny2313A mit externem 8MHz Quarz. Fuses sind folgende
gestzt: SPIEN, SUT_CKSEL (EXTXOSC_8MHZ_XX_14CK_65MS)
Das Senden vom Tiny an meine Konsole läuft nach korrekter
Baudrateneinstellung auch. Nur empfängt der 2313A leider falsche bzw.
keine Daten.
Hier mal mein Code:
1
intmain(void)
2
{
3
uart_init(BAUDRATE);
4
DDRB|=(1<<PORTB0)|(1<<PORTB1)|(1<<PORTB2);
5
while(1)
6
{
7
uart_putc('t');
8
uart_getc();
9
PORTB|=(1<<PORTB0);
10
_delay_ms(5000);
11
PORTB&=~(1<<PORTB0);
12
_delay_ms(5000);
13
}
14
}
15
16
voiduart_init(unsignedintbaudrate)
17
{
18
//51 = 110011 = Baudrate 9600
19
UBRRH=0;
20
UBRRL=51;
21
/* Enable receiver and transmitter */
22
UCSRB=(1<<RXEN)|(1<<TXEN);//|(1<<RXCIE);
23
/* Set frame format: 8data, 1stop bit */
24
UCSRC=(1<<UCSZ0)|(1<<UCSZ1);
25
}
26
27
voiduart_putc(unsignedcharinput)
28
{
29
/* Wait for empty transmit buffer */
30
while(!(UCSRA&(1<<UDRE)))
31
;
32
/* Put data into buffer, sends the data */
33
UDR=input;
34
}
35
36
unsignedcharuart_getc()
37
{
38
/* Wait for data to be received */
39
while(!(UCSRA&(1<<RXC)));
40
41
uart_putc('d');//if data is received print "d"
42
/* Get and return received data from buffer */
43
returnUDR;
44
}
Prinzipiell sollte das Programm doch wie folgt ablaufen:
Auf Konsole wird 't' ausgeben, dann sollte auf eine Eingabe gewartet
werden, daraufhin LED blinken lassen. Und danach das ganze wieder von
vorn.
Das Programm läuft aber wie folgt ab:
Konsole zeigt "tdtdtdtd[...]" an und die LED blinkt schön nebenher. Das
'd' aus der Konsole kommt aus der uart_getc() Funktion und zeigt an das
das RXC Flag '1' ist und Daten empfangen wurden.
Jedoch sende ich keinerlei Daten, über die Konsole, an den Tiny.
Habe ich einen groben Schnitzer in meinem Code, irgendwas vergessen zu
setzten oder stimmt meine ganze Logik nicht?
Gleich mal Danke für die Hilfe.
@Stefan Frings: Nicht das ich wüsste.
Ich habe in der zwischenzeit mal ein bisschen rumgespielt:
Ich habe mal nur TX aktiviert und mit dem foglendem Code blinkt und
sendet er nix (soll auch so ein):
1
uart_getc();//hier kommt er nicht raus, da RXC == '0'
2
uart_putc('b');
Wenn ich hingegen nur
1
uart_putc('b');
im Code habe, sendet er mir wie gewollt mein 'b'.
Wenn RX deaktiviert ist, ist auch RXC '0', sobald ich aber RX aktiviere
ist RXC dauerhaft auf '1'.
RXC sollte doch automatisch auf '0' gehen sobald ich die Daten aus UDR
auslese oder?
Nimm erstmal das 'uart_putc('d');' aus der 'uart_getc();' raus und
schreib's als extra Funktion dahinter. Das gehört dort nicht hin. Sieht
gruselig aus und ich glaube, UDR muss beim Empfang auch erstmal gelesen
werden. Sollte aber nicht der Fehler sein.
> while (!(UCSRA & (1<<RXC)));>> uart_putc('d'); //if data is received print "d"> /* Get and return received data from buffer */> return UDR;
Ist natuerlich quatsch. Warten bis gut, dann schreiben und nachher
lesen.
Der Befehl : return UDR; ist ein effektives Lesen des UART Registers.
damit wartest Du, bis etwas empfnagen wurde, überschreibst das UDR
register über uart_putc() und gibst dann UDR zurück ?
vieleicht hättest Du zunächst UDR auslesen sollen?
Meines wissens wird das RXC durch lesen von UDR gelöscht, due
beschreibst es vor dem Auslesen
Hi
>damit wartest Du, bis etwas empfnagen wurde, überschreibst das UDR>register über uart_putc() und gibst dann UDR zurück ?
UDR für TX und UDR für RX sin nicht die gleichen Register. Da wird
nichts überschrieben.
MfG Spess
Benedikt schrieb:> Hier mal mein gekürzter Code:
und?
Was tut sich?
Dir ist hoffentlich schon klar, dass es nach dem Drücken einer Taste bis
zu 10 Sekunden dauern kann, bis deine LED an PB2 angeht? Und 10 Sekunden
können laaaaang sein.
Warum denn so kompliziert:
1
intmain(void)
2
{
3
unsignedcharc;
4
5
uart_init(BAUDRATE);
6
_delay_ms(2000);
7
uart_putc('a');
8
9
// sei(); // wozu? Hast du irgendwo Interrupts? Nein? Dann gib sie auch nicht frei
10
11
while(1)
12
{
13
c=uart_getc();
14
15
uart_putc(c);
16
}
17
}
Für einen ersten Test sollte das reichen.
Wenn du unterscheiden willst, ob du auf ein lokales Echo hereinfällst
oder ob das was am Terminal erscheint auch wirklich vom µC stammt, dann
mach zb.
1
uart_putc(c+1);
dann schickt der µC das jeweils nächste Zeichen im ASCII Code zurück: Du
drückst die Taste a und der µC schickt ein b zurück. Das macht kein
lokales Echo.
> Jedoch sende ich keinerlei Daten, über die Konsole, an den Tiny.
Verkabelung checken.
Irgendwo müssen die Pulse ja herkommen, die die UART durcheinander
bringen.
@Karl Heinz Buchegger: Das habe ich direkt als erstes getestet, aber das
funktioniert einfach nicht.
Mit dem Code den ich oben gepostet habe funktioniert wie erwarte immer
noch nichts.
Die LED die RXC anzeigt leuchtet dauerhaft.
Die LED am Port0 blinkt vor sich hin und zeigt an das er nicht irgendwo
hängt sonder immer wieder durchläuft.
Daraus schließe ich, dass der RXC Flag dauerhaft auf '1' ist.
Hardwar:
Wenn ich RX und TX an meinem USB<->UART Kabel kurzschließe bekomme ich
meine Eingaben auch wieder zurück. Daraus schließe ich das es nicht
defekt ist.
Ach ja, wie oben zu sehen ist, läuft der Tiny mit 8 MHz und das
Clockdivde Flag ist nicht gesetzt. Daher sind die 5s auch keine 5
sondern nur ca. 0,6s.
Die einzigen Dinge die mir noch einfallen sind:
Wenn TX funktioniert sollte doch alles so eingestellt sein, dass RX auch
funktioniert. Oder müssen für RX noch zusätzlich Flags, Fuses oder
ähnliches gesetzt werden? (jetzt mal von RXEN abgesehen)
Kann die CKDIV Fuse irgendwie den RX "stören"?
Ich glaub ich habe mein Fehler gefunden:
Wenn ich kein UART Kabel anschließe, dann wird auch bei uart_getc()
gewartet. Wenn ich es kurz anschließe, oder nur eine der Brücken anfasse
bekommt er sofort gültige Daten und rennt weiter.
Wenn ich RX und TX auf dem Steckbrett kurzschließe läuft er schön durch
und kommuniziert auch richtig.
Bisher war mein UART immer recht stabil, aber der ist wohl ein
Sensibelchen.
Habt ihr eine Idee warum? Dürfte doch garnicht der Fall sein.
Benedikt schrieb:> Wenn ich RX und TX auf dem Steckbrett kurzschließe läuft er schön durch> und kommuniziert auch richtig.
Du hast aber hoffentlich auch die Masse vom Kabel mit der Masse deiner
Schaltung verbunden?
(Und auf der anderen Seite vom Kabel auch?)
GND muss immer über alle Schaltungen durchverbunden werden. Spannungen
sind Potentialdifferenzen! D.h. sie beziehen sich auf ein 0, das nicht
weiter definiert ist. Erst dadurch, dass man die Massen aller
Schaltungen verbindet, stellt man sicher, dass sich alle Schaltungen
immer auf dasselbe Potential als 0-Punkt mit ihren Spannungen beziehen.
Ja sollte alles so passen aber vielleicht habe ich einen Wackler in
meinem Kabel.
Ich werde es nächste Woche mal mit einem RS232 Anschluss versuchen, bzw.
daheim mal das Kabel durchchecken.
Ich glaube mir ist vorerst geholfen.
Danke für die vielen Ideen, falls noch Probleme auftreten werde ich mich
nochmal melden :-)
Ich hätte noch eine kleine Frage :-)
Ihr dürft gerne lachen, aber braucht der RX des µC einen Pullup auf 5V?
Nach ein paar Messungen und rumspielen ist mir aufgefallen das mein RX
auf 2,4V hängt und nicht auf 5V wie es sein sollte.
Jetzt habe ich einen Pullup auf 5V drangehängt und siehe da er läuft.
Mal ne blöde Frage,
was hast Du denn für nen RS232 Transceiver auf deinem Board?
2,4V ist det min. High Pegel bei TTL, bei CMOS Eingängen benötigst Du
ca. 0,9*VCC als High Pegel - also > 4V bei 5V Versorgung, den kannst Du
evtl durch einen exteren Pull Up anheben, und Deine Schaltung
funktioniert, aber richtig Gut ist das nicht.
Eingentlich solltest Du keine Pull Ups benötigen, weil der Transceiver
die korrekten Pegel zur Verfuegung stellt.
Ich verwende ein Siemens DCA-510 als USB-UART-Wandler.
Bisher hatte ich eben noch nie Probleme mit dem und jetzt auf einmal
schon.
Vielleicht hatte ich bisher nur Glück und es ist mir nie aufgefallen.
Ich werde mir demnächst ein paar USB-UART-Wandler mit dem FT232RL
basteln, da sollte es dann hoffentlich keine Probleme mehr geben.
Ich hatte auch eine längliche Odyssee hinter mich gebracht, bis ich das
USART richtig verwenden konnte.
Ich verwende eine Raspberry Pi als AVR-Programmer mit der Hilfe von
avrdude und der SPI-Schnittstelle am GPIO der Raspberry Pi. Ebenso
verwendete ich die UART-Schnittstelle der Pi für die serielle
Kommunikation. Als Serielles-Terminal habe ich minicom verwendet, weil
man da ganz "komfortabel" (hust) die Übertragungsparameter einstellen
kann.
Das Beispiel AVR 306 (zu finden auf der Seite von Atmel) funktionierte
nicht. Das zog längere Analysen nach sich. Die erste Feststellung war,
dass die Daten ATtiny2313 -> RPi ohne Probleme kommen. Wenn ich aber
Daten von RPi -> ATtiny2313 senden wollte, ging es nicht. Die MCU
vollführte einen reset. Eine Analyse mit einem Digitalen Oszilloskop
ergab nichts. Die Timings von den empfangenen Daten waren identisch zu
dennen, die ich zur MCU zu senden versuchte.
Ich habe das Programm dann so weit reduziert, dass ich nur noch eine
blinkende LED hatte. Ohne jegliches weitere drum herum, auch kein UART
und nichts. Selbst DANN vollführte die MCU einen Reset, wenn ich Daten
auf den RX-Pin geschickt habe.
LÖSUNG:
Sobald ich den RESET-Pin nach dem Programmieren von der RPi gelöst habe,
funktioniert die Kommunikation über UART einwandfrei.