Atmega8A UART sendet nur Müll

Gast #5713275
Lesenswert?

Hallo zusammen,

ich schaffe es einfach nicht eine vernünfitge UART Ausgabe 
hinzubekommen. Vielleicht könnte mal jemand auf den Code schauen. In 
Putty empfange ich nur Mist, wo eigentlich das Wort "Hallo" erscheinen 
sollte. Die Baudrate ist 19200 eingestellt, der Atmega8A läuft mit einem 
8 MHz Quarz (extern).
Als Kabel zwischen AVR und PC verwende ich ein "TTL-232R-5V" von FTDI. 
Dort habe ich GND, RX und TX belegt.

1
//uart.h
2

3
#ifndef UART_H_
4
#define UART_H_
5

6
#define BAUD 19200UL //Baudrate
7

8
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)  //clevers Runden
9
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))    //reale Baudrate
10
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)    //Fehler in Promille, 1000=kein Fehler
11

12
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
13
#error Systematischer Fehler der Baudrate ist groesser 1% und damit zu hoch!
14
#endif
15

16
#endif /* UART_H_ */
1
//uart.c:
2

3
#include <avr/io.h>
4
#include "uart.h"
5

6

7

8

9
void uart_init(void)
10
{
11
  UBRRH = UBRR_VAL >> 8;
12
  UBRRL = UBRR_VAL & 0xFF;
13
  
14
  // UART TX einschalten
15
  UCSRB |= (1 << TXEN);
16
  //Frame Format: Asynchron 8N1
17
  UCSRC |= (1<<URSEL) | (1<<UCSZ0)|(1<<UCSZ1);
18
}
19

20

21
int uart_putc(unsigned char c)
22
{
23
  while (!( UCSRA & (1<<UDRE)));  //warten bis Senden möglich
24
  {
25
    
26
  }
27
  
28
  UDR = c;              //sende Zeichen
29
  return 0;
30
}
31

32

33
void uart_puts (char *s)
34
{
35
  while (*s)
36
  {  /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
37
    uart_putc(*s);
38
    s++;
39
  }
40
}

1
//main.c:
2

3
#include <avr/io.h>
4
#include "uart.h"
5

6

7
int main(void)
8
{
9
  
10
  uart_init();
11

12

13
    while (1) 
14
    {
15
    uart_puts("Hallo");
16
    
17
  }
18
}
(Firma: matzetronics) #5713286
Lesenswert?

Wenn du bei putty mal die Baudrate von 2400 einstellst - was passiert 
dann?

Um dem Empfänger eine Chance aufs Erkennen des Startbits zu geben (im 
Moment sendest du ja einen endlosen Bitstrom), kannst du auch mal ein 
kleines Delay in der Hauptschleife vor oder nach dem uart_puts() 
einfügen.

Karl M. schrieb:
> was ist hier wohl falsch ?
> while (!( UCSRA & (1<<UDRE))); //<===  //warten bis Senden möglich
>   {
>
>   }

Tja, da muss der TE sich wohl entscheiden. Entweder Semikolon oder 
geschweifte Klammern :-P
Beitrag #5713322 wurde von einem Moderator gelöscht.
Gast #5713333
Lesenswert?

Ein 10 Sekunden Delay ist schon drinnen.
1
 while (1) 
2
    {
3
    _delay_ms(10000);
4
    uart_puts("Hallo");
5
    }


Auch habe ich hier das Semikolon entfernt:
1
int uart_putc(unsigned char c)
2
{
3
  while (!( UCSRA & (1<<UDRE)))  //warten bis Senden möglich
4
  {
5
    
6
  }
7
  
8
  UDR = c;      //sende Zeichen
9
  return 0;
10
}
Gast #5713334
Lesenswert?

Lars schrieb:
> //uart.c:
>
> #include <avr/io.h>
> #include "uart.h"
>
> void uart_init(void)
> {
>   UBRRH = UBRR_VAL >> 8;
>   UBRRL = UBRR_VAL & 0xFF;
>
>   // UART TX einschalten
>   UCSRB |= (1 << TXEN);
>   //Frame Format: Asynchron 8N1
>   UCSRC |= (1<<URSEL) | (1<<UCSZ0)|(1<<UCSZ1);
> }
>

Es könnte sein, dass du die Zuweisung an UBRRH und UBRRL noch casten 
müsstest auf uint8.

Z. B. so: UBRRH = (uint8_t)(UBRRVAL >> 8);
#5713337
Lesenswert?

Lars schrieb:
> Ein 10 Sekunden Delay ist schon drinnen. while (1)
>     {
>     _delay_ms(10000);
>     uart_puts("Hallo");
>     }

Das ist Unsinn, es reichen ein paar Millisekunden, ggf. 1s, damit man 
als Mensch im Terminalprogramm nicht mit Text überflutet wird.

>Auch habe ich hier das Semikolon entfernt:

Ist nebensächlich. Du hättest einfach die Klammern entfernen können, 
aber auch die haben logisch nicht geschadet. Sie waren nur überlüssig.

int uart_putc(unsigned char c)
{
  while (!( UCSRA & (1<<UDRE)));  //warten bis Senden möglich
  UDR = c;      //sende Zeichen
  return 0;
}
#5713415
Lesenswert?

Hi,
schon testweise einmal das angegebene Programm ausprobiert?

https://www.mikrocontroller.net/articles/AVR-Tutorial:_UART

Wenn es nicht klappt, liegt es vielleicht am Putty-Terminalprogramm und 
dessen Einstellungen.
Probiere einmal Teraterm aus.
Bei mir machte Hyperterminal immer "Jitter". D. h. einmal Zeichen 
richtig, dann einmal LSB falsch. Weil Flanke wackelte.
Teraterm machte das nicht. Bügelt den Fehler aus.

ciao
gustav
#5713425
Lesenswert?

Karl B. schrieb:
> Bei mir machte Hyperterminal immer "Jitter". D. h. einmal Zeichen
> richtig, dann einmal LSB falsch. Weil Flanke wackelte.
> Teraterm machte das nicht. Bügelt den Fehler aus.

Kann ich mir hier irgendwie nicht vorstellen,
wie das Terminal-Programm die Hardware entsprechend beeinflussen soll.
(von der korrekten Übermittlung der Parameter für Baudrate ... 
abgesehen)
Gast #5713428
Lesenswert?

Ich habe dein Programm mal genommen und auf meinen ATmega8 geschmissen.

Nach Konfiguration der Konstante F_CPU über die Gnu Compiler Symbols 
(mit der Quarzfrequenz 7,3728MHz, die ich habe) kommt ein Hallo sehr 
zuverlässig raus.

Du hast womöglich F_CPU nicht (an der richtigen Stelle?) definiert oder 
die CKDIV-Fuse gesetzt. Der Takt an deiner CPU scheint nicht so zu sein, 
wie du denkst.

Probe: toggle ne LED einmal die Sekunde per delay_ms(1000). Stimmt die 
Taktfrequenz? Dann ist es was anderes bei dir.
Gast #5713471
Lesenswert?

Danke Karl,

dann liegt es scheinbar nicht am Code.
Ich habe jetzt mal den internen 1 MHz Takt des AVR verwenwendet. Dieser 
ist unter Symbols mit "F_CPU=1000000UL" definiert. Ferner habe ich die 
Baudrate auf 2400 reduziert.

Im Terminal kommt damit leider auch nur der selbe "Mist" an.

Der Takt an sich scheint zu stimmen, durch das delay kommt alle 10 
Sekunden der Datensatz.
Gast #5713479
Lesenswert?

Junge, nimm ein Oszilloskop und schaue ob auf der Uart TX die richtigen 
Zeichen rauskommen und ob der Takt überhaupt korrekt ist. Das ist doch 
ein Rumstochern hier. Wenn du dort 18243 statt 19200 hast, weißt du was 
los ist.

Es gibt heutzutage auch Oszilloskope, die eine UART dekodieren und dir 
in Echtzeit anzeigen, was du überträgst.
#5713532
Lesenswert?

// UART TX einschalten
  UCSRB |= (1 << TXEN);
  //Frame Format: Asynchron 8N1
  UCSRC |= (1<<URSEL) | (1<<UCSZ0)|(1<<UCSZ1);

würde ich anders machen
  // UART TX einschalten
  UCSRB = (1 << TXEN);
  //Frame Format: Asynchron 8N1
  UCSRC = (1<<URSEL) | (1<<UCSZ0)|(1<<UCSZ1);

Bei deiner Version bleiben womöglich Bits stehen vom letzten Lauf. Oder 
gehst du immer von einem harten Reset aus? Defensiv programmieren!
#5713779
Lesenswert?

Lars schrieb:
> Habe statt "Hallo" jetzt "xxxxx" geschrieben. Anbei das Ergebnis.

Schwer vorstellbar, wie aus einem 'x' 0x78 ein 0xE8 wird.

Ich nehme an du hast kein Oszilloskop zur Hand?

Ich würde dann erst mal ein einziges 'U' (0b01010101) schicken, und 
schauen, was dabei raus kommt. (wiederholt im x Sekundenabstand)

Möglich wäre auch die Zeit der Übertragung von vielen Zeichen über eine 
LED am TX zu messen und daraus die Baudrate grob zu schätzen.
Gast #5713948
Lesenswert?

Lars schrieb:
> Anbei das Ergebnis.
das sieht sehr stark nach einem invertieren Signal aus (wirklich schwer 
vorstellbar, da das erste Datenbit dann zum Startbit wird usw.). Evtl. 
ist im FTDI-Treiber Rx auf invertiert eingestellt.
Ansonsten neben dem von Volker vorgeschlagenem 'U' auch 0xF0 und 0x0F 
ausprobieren.
Gast #5714321
Lesenswert?

Läuft der mega8 denn wirklich mit dem externen 8 MHz-Quarz?

Der Baudraten-Mist lässt sich leicht erklären, wenn zwar ein
Quarz dranhängt, aber der interne RC-Oszillator benutzt
wird und mit CKSEL3:0 zu F-CPU = 1, 2, 4, (oder 8) MHz
geschaltet ist.

Ohne Oszi hilft es dann nur, einen Hardware-Timer so zu
programmieren, dass er auf einem Port-Pin im Sekundentakt
eine LED aufblitzen lässt.

Der 16-Bit Timer1 mit Vorteiler 1/256 als CTC mit
MAX-Count = 31249 könnte das bewerkstelligen. Das kann man
über ein paar Minuten mit dem Sekundentakt einer Uhr
vergleichen.
Bei echten 8 MHz läuft das synchron!
Taktfehler im Prozentbereich (die RS232 außer Takt bringen)
fallen damit schnell auf.
Gast #5714365
Lesenswert?

Jakob schrieb:
> Ohne Oszi hilft es dann nur, einen Hardware-Timer so zu
> programmieren, dass er auf einem Port-Pin im Sekundentakt
> eine LED aufblitzen lässt.

In Zeiten von C auf dem µC, wird man wohl einfacher ein delay() zusammen 
mit dem Blinken einer LED verwenden. Das reicht um einen grob falschen 
Quarz oder Teiler zu identifizieren.
Bei Preisen von unter 6€ für einen elementaren Logikanalysator gibt es 
heutzutage eigentlich keinen vernünftigen Grund, auch nur 1/2h damit zu 
verbringen, über Timing und Polarität von einem UART-Signal rum zu 
rätseln.
Gast #5714368
Lesenswert?

Volker S. schrieb:
> Schwer vorstellbar, wie aus einem 'x' 0x78 ein 0xE8 wird.
Da das Messergebnis trotz Hinweis und Dokumentation als "erster Gedanke" 
weiterhin so viele Fragezeichen verursacht ein Versuch mit Zeichen zu 
beschreiben was passiert wenn 'x' bzw. 'xx' 100% taktgenau/100% 
invertiert gesendet (ex)oder empfangen wird:
1
$78:0111.1000           ; 'x'
2
r:  0001.1110            ; lsb first (praktisch rückwärts)
3
f: sooo1 111oE sooo1 111oE ^^^^; 'xx'framed:+(s)tart/(E)ndbit + idle(^)
4
i: ^^^^s ooo1o 111Es ooo1o oooe; invertiert(s=startbit Erkennung)
5
rec:   | 00010 111+| 00010 000-; 'netto' Empfang; Frame:[+|-];0...=brk
6
msb-f    111 01000($E8)-($08[FE])-($00[brk])
(auch 'Hallo' wurde 100% taktrichtig/signalfalsch gemessen)
Mögliche Ursachen:
a) Treiber/Empfänger 'verkehrt' eingestellt
b) Sender u.U. eine Platine auf der Max 2. einen Käfer verzinnt hat 
(quasi ein Rs232-Bug in dem Kontext) oder
c) etwas komplizierte Steckerverpolung (Tx an Vcc/ Gnd an Rx) was aber 
eigentlich nur mit viel Übung passieren dürfte.

Eigentlich gibt es bei solchen eindeutigen Messergebnissen keinen 
vernünftigen Grund wild von zusätzlicher Hardware zu schreiben wenn 
schon das Messergebnis des verwendeten elementaren Logikanalysators 
nicht verstanden wird.

NB.: wenn eh eine serielle Schnittstelle verwendet werden soll,dann 
lässt die sich auch sehr einfach ohne zusätzliche Verkabelungen/LED o.ä. 
durch Senden eines(!) 0x7f zur Taktmessung verwenden: kommen 2 Zeichen 
an, dann einfach auf 8MHz hochskillen ;-)
#5714450
Lesenswert?

Dirk B. schrieb:
> Eigentlich gibt es bei solchen eindeutigen Messergebnissen keinen
> vernünftigen Grund wild von zusätzlicher Hardware zu schreiben wenn
> schon das Messergebnis des verwendeten elementaren Logikanalysators
> nicht verstanden wird.

Es scheint leider Messinstrument vorhanden zu sein, mit dem der 
Signalverlauf aufgezeichnet werden könnte. Sonst wäre es ja einfach ;-)
Gast #5714519
Lesenswert?

Danke Dirk und Peter!

Eure Vermutung war richtig. Ich habe mir mal das FTDI_Tool 
runtergeladen. Im Eeprom des Chips sind tatsächlich RX und TX als 
invertiert gesetzt.
Wäre ich nie drauf gekommen, da ich das Kabel kürzlich für eine andere 
Andwendung neu gekauft hatte und dort die Kommunikation (Senden und 
Empfangen) problemlos funktionierte.

Laut Datenblatt
Seite 22 sind TX und RX werksseitig nicht invertiert, bei mir aber 
schon.

Seite 22

https://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_TTL-232R_CABLES.pdf
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren