Forum: Mikrocontroller und Digitale Elektronik ATTiny2313A UART Receive Probleme


von Benedikt (Gast)


Lesenswert?

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
int main(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
void uart_init(unsigned int baudrate)
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
void uart_putc(unsigned char input)
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
unsigned char uart_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
  return UDR;
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.

von Wusel D. (stefanfrings_de)


Lesenswert?

Hast Du eine ungewollte Loop-Back Verbindung zwischen RxD und TxD?

von Benedikt (Gast)


Lesenswert?

@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?

von Ralf G. (ralg)


Lesenswert?

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.

von i-Troll (c) (Gast)


Lesenswert?

>  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.

von nobi (Gast)


Lesenswert?

ich versteh deien Receive Routine nihct ganz:
1
unsigned char uart_getc()
2
{
3
  /* Wait for data to be received */
4
    while (!(UCSRA & (1<<RXC)));
5
            
6
  uart_putc('d');         //if data is received print "d"
7
      /* Get and return received data from buffer */
8
  return UDR;
9
}
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
1
unsigned char uart_getc()
2
{
3
  unsigned char data;
4
  /* Wait for data to be received */
5
    while (!(UCSRA & (1<<RXC)));
6
  data = UDR;          
7
  uart_putc('d');         //if data is received print "d"
8
      /* Get and return received data from buffer */
9
  return data;
10
}

von Benedikt (Gast)


Lesenswert?

Hier mal mein gekürzter Code:
1
int main(void)
2
{
3
  uart_init(BAUDRATE);
4
  _delay_ms(2000);
5
  uart_putc('a');
6
//  sei();
7
8
  DDRB |= (1<<PORTB0) | (1<<PORTB1) | (1<<PORTB2);
9
    while(1)
10
    {
11
12
  if(UCSRA & (1<<RXC))  //if RXC is '1' data is available and LED is on
13
  PORTB |= (1<<PORTB2);
14
  else          //if RXC is '0' no data is available and LED is off
15
  PORTB &= ~(1<<PORTB2);
16
  
17
18
    uart_getc();
19
    
20
    //LED blink
21
    PORTB |= (1<<PORTB0);
22
    _delay_ms(5000);
23
    PORTB &= ~(1<<PORTB0);
24
    _delay_ms(5000);
25
26
    }
27
}
28
29
void uart_init(unsigned int baudrate)
30
{
31
  //51 = 110011 = Baudrate 9600
32
  UBRRH = 0;
33
  UBRRL = 51;
34
  /* Enable receiver and transmitter */
35
  UCSRB = (1<<RXEN)|(1<<TXEN);//|(1<<RXCIE); (1<<RXEN)|
36
  /* Set frame format: 8data, 1stop bit */
37
  UCSRC = (1<<UCSZ0)|(1<<UCSZ1);
38
}
39
40
void uart_putc(unsigned char input)
41
{
42
  /* Wait for empty transmit buffer */
43
  while ( !( UCSRA & (1<<UDRE)) )
44
  ;
45
  /* Put data into buffer, sends the data */
46
  UDR = input;
47
}
48
49
unsigned char uart_getc()
50
{
51
  /* Wait for data to be received */
52
    while (!(UCSRA & (1<<RXC)));
53
  /* Get and return received data from buffer */
54
  return UDR;
55
}

von spess53 (Gast)


Lesenswert?

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

von nobi (Gast)


Lesenswert?

@spess53

ja, haste recht, sollte somit tatsächlich nicht der Fehler sein,
sieht aber trotzdem komisch aus so :)

von Karl H. (kbuchegg)


Lesenswert?

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
int main(void)
2
{
3
  unsigned char c;
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.

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Benedikt (Gast)


Lesenswert?

@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"?

von Benedikt (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Wusel D. (stefanfrings_de)


Lesenswert?

Also doch ein ungewolltes Loop-Back.

von Benedikt (Gast)


Lesenswert?

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 :-)

von Benedikt (Gast)


Lesenswert?

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.

von nobi (Gast)


Lesenswert?

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.

von Benedikt (Gast)


Lesenswert?

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.

von Michael Kwasnicki (Gast)


Lesenswert?

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.

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.