Forum: Mikrocontroller und Digitale Elektronik USART Frage zu Bibliotheken


von Christoph W. (christoph_w496)


Lesenswert?

Hallo,

ich als erfahrener Programmierer und uC-Anfänger habe mir ein 
eHajoEtaval-Board und ein Atmega8-16PU besorgt, um über kleine 
Beispielprojekte in die Mikrocontroller-Welt einzusteigen. Die erste 
Aufgabe besteht für mich nun Daten vom uC auf den PC zu bekommen, um so 
printf-Debugging betreiben zu können und damit nicht ganz blind zu sein. 
Leider habe ich keinen Debugger (eventuell kann mir da jemand einen Tipp 
geben wie ich das kostenkünstig dann doch hinbekomme mit meinem Board) 
und da erschient mir UART als Möglichkeit zum Debuggen sinnvoll zu sein. 
Daraufhin habe ich mir einen USB-TTL-Adapter gekauft und 
losprogrammiert. Mithilfe der Doku war es auch nicht schwer eine 
funktionsfähige Verbindung hinzubekommen. Jedoch habe ich ein wenig 
gegooogelt weil ich gedacht habe, dass ich nicht der einzige sein kann 
der dieses Problem gelöst hat und so eine Bibliothek gesucht habe, die 
mir ein wenig unter die Arme greift. Jetzt habe ich 2 Libs ausprobiert 
(u.a. AVR-UART-lib) und diese nicht richtig zum laufen gebraucht. Die 
Zeichenketten, die auf meinen PC ankommen sind immer falsch. Kann mir 
jemand eventuell einen Tipp geben was ich falsch gemacht habe.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
// Defines:
6
#define LED1    (1<<PD5)
7
#define LED2    (1<<PD6)
8
9
extern "C"
10
{
11
  #include "AVR-UART-lib/usart.h"
12
}
13
14
bool bUseLib = false;
15
#define BAUD 9600UL
16
#include <util/setbaud.h>;
17
 
18
void uart_init(void)
19
{
20
  UBRRH = UBRRH_VALUE;
21
  UBRRL = UBRRL_VALUE;
22
  #if USE_2X
23
    UCSRA |= (1 << U2X);
24
  #else
25
    UCSRA &= ~(1 << U2X);
26
  #endif
27
28
  // Enable Receiver and Transmitter 
29
  UCSRB |= (1<<TXEN)|(1<<RXEN);
30
  // Set frame format: 8data, 2stop (USBS=1) bit, asychon (umsel=0)
31
  UCSRC = ((1<<URSEL)|(1<<USBS)|(1<<UCSZ0)|(1<<UCSZ1)) & ~(1<<UMSEL);
32
}
33
  
34
int main()
35
{  
36
  if(bUseLib)
37
  {
38
    //uart_set_FrameFormat(USART_8BIT_DATA|USART_1STOP_BIT|USART_NO_PARITY|USART_ASYNC_MODE); // default settings
39
    uart_init(BAUD_CALC(9600)); // 8n1 transmission is set as default
40
    //stdout = &uart0_io; // attach uart stream to stdout & stdin
41
    //stdin = &uart0_io; // uart0_in and uart0_out are only available if NO_USART_RX or NO_USART_TX is defined
42
  }
43
  else
44
  {
45
    uart_init();
46
  }
47
 
48
  // Globales Interruptflag einschalten:
49
  sei();
50
  
51
  // LED-Pins als Ausgang definieren
52
  DDRD |= LED1 | LED2;
53
    
54
  // LED1 einschalten
55
  PORTD |= LED1;
56
 
57
  while(1)
58
  {
59
    PORTD ^= LED1 | LED2;
60
    _delay_ms(1000);
61
    
62
    char* pstr = "Hallo\0";
63
    if(bUseLib)
64
    {
65
      uart0_putstr(pstr);
66
    }
67
    else
68
    {
69
      for(const char* pP = pstr; *pP != '\0'; ++pP)
70
      {
71
        while ( !( UCSRA & (1<<UDRE)) ) {}
72
        UDR = *pP;
73
      }
74
    }
75
  }
76
 
77
  return 0;
78
}

Der Code ist nicht sehr schwer. Ich schalte zusätzlich 2 Leds, um zu 
sehen, ob das Programm auch wirklich läuft. Wenn ich nun bUSeLib=true 
setze, dann kommt nichts richtiges mehr auf der anderen Seite an. 
Eigentlich kann das doch nicht so schwer sein, weil ich es mit dem 
Handbuch doch auch leicht hinbekommen habe. Habe ich eventuell eine 
fehlerhaft Lib verwendet? Wo holt ihr euch die Libs? Gibt es eine gute 
Anlaufstelle für verschiedene Probleme?

Danke im Voraus

von S. Landolt (Gast)


Lesenswert?

Als "erfahrener Programmierer" ist es mir unmöglich, aus den gemachten 
Angaben und dem Programmschnipsel etwas Brauchbares herauszulesen; mir 
fehlt alles Wesentliche. Also: versetzen Sie sich in unsere Lage und 
überlegen Sie, was alles an Angaben fehlen könnte.
  Übrigens:
> Mithilfe der Doku war es auch nicht schwer eine
> funktionsfähige Verbindung hinzubekommen.
Ist doch prima, so hatte ich auch mal angefangen, und mir dann meine 
Bibliotheken selbst geschrieben (in Assembler, nur am Rande).

von FS (Gast)


Lesenswert?

1
extern "C"
2
{
3
  #include "AVR-UART-lib/usart.h"
4
}

Was ist das denn für ein merkwürdiges Konstrukt?

Und warum wird der UART offenbar mit 2 Stoppbits initialisiert und 
weiter unten in den Kommentaren steht 8n1? Und zwei 
uart_init-Funktionen, einmal mit, einmal ohne Parameter?

von c-hater (Gast)


Lesenswert?

Christoph W. schrieb:

> ich als erfahrener Programmierer und uC-Anfänger habe mir ein
> eHajoEtaval-Board und ein Atmega8-16PU besorgt, um über kleine
> Beispielprojekte in die Mikrocontroller-Welt einzusteigen.
[...]
> und so eine Bibliothek gesucht habe, die
> mir ein wenig unter die Arme greift.

Falscher Ansatz. Wenn du wirklich µC beherrschen lernen willst, ist die 
Verwendung irgendwelcher Libs genau der falsche Weg.

Kann man ja schon sehr schön sehen: du hast keinen Plan, wie du das 
Debugging (der Lib bzw. deiner Verwendung selbiger) angehen willst. Und 
das, obwohl du immerhin schon LEDs zur Debugausgabe verfügbar hast...

Das spricht übrigens definitiv nicht für einen wirklich "erfahrenen" 
Programmierer, als den du dich darstellst... Alles, was du wohl bist, 
ist ein  Lib-Zusammenleimer, aber auch da nicht sonderlich erfahren, 
sonst hättest du schon Debugstrategien für dein Problem...

von Oliver S. (oliverso)


Lesenswert?

FS schrieb:
> Was ist das

Das ist C++, auch wenn man es dem Code sonst nicht ansieht.

Komische Zeichen aus der Usart kommen eigentlich immer durch eine 
falsche Baudrate. Falscher CPU-Takt, falsche Initialisierung, oder 
prinzipbedingt ungenauer Takt können Ursachen sein.

Oliver

von Stefan F. (Gast)


Lesenswert?

Der Atmega8 hat keine Debugging Schnittstelle.

Was die Library angeht, darfst du gerne mal meine versuchen: 
http://stefanfrings.de/avr_hello_world/index.html
Sie verwendet nur für den Empfang einen Puffer. Gesendet wird direkt 
blockierend.

Ich stimme allerdings c-hater zu, dass selber machen lehrreicher ist und 
letztendlich auch mit Sicherheit mehr Erfolg verspricht.

Hast du dich mit den Fuses zur Takt-konfiguration und F_CPU beschäftigt? 
Ist da alles richtig? Wenn du eine LED blinken lässt (abwechselnd 1s an 
und aus) stimmt dann das Timing? Verwendest du den Quarz? Ist die GND 
Leitung mit dem PC verbunden?

von Christoph W. (christoph_w496)


Lesenswert?

Hi,

Ui dann habe ich es hier ja mit richtigen Männer zu tun, die ihren Code 
selber schreiben und dann am besten in assembler. Leider muss ich auch 
feststellen, dass einige nicht nur vom programmieren her vor 30 Jahren 
stehengeblieben sind, sondern auch als Persönlichkeit, schade. Alle die 
mir Konstruktiv helfen wollen schon mal Dank im Voraus.

Ja das ist C++ (Bitte keine Grundsatzdisskusstion wieso ich C++ 
verwende). Und ja, wenn ich keine Debuschnittstelle habe, dann lege ich 
mir eben eine zurecht und für mich als Laie schien UART das richtige zu 
sein (wegen der HW-Kosten um es anzuschließen und weil es einfach 
umzusetzen ist) oder könnte ihr mir da Tipps geben? Und ja, bevor ich 
programmiere lege ich mir eine Debugstrategie zurecht und das ist genau 
diese. Ich finde es wichtig und richtig von der Pieke auf alles zu 
programmieren, um viel über das zu lernen was man da macht. Deswegen 
habe ich es auch zuerst selber implementiert, aber ich will bewußt eine 
Lib nehmen. Der Grund dafür ist, dass ich für mein Projekt eventuell auf 
einen anderen Atmel uC gehen möchte (geringer Kosten, kleiner, 
Stromsparender, ...) und für mich ist der Große eine Art Spielwiese wo 
ich vieles ausprobieren kann. Und die Libs bieten mir genau die 
Möglichkeit, ohne das ich später den Applikationscode ändern und ein 
neues Datasheet lesen muss.

Es kann nicht Grundlegend falsch sein was ich mit der Lib eingestellt 
habe. Meine Beobachtung ist, dass ich 5 Bytes verschicke und auch 5 
Bytes ankommen, aber leider die falschen. Wenn ich bewußt etwas falsch 
einstelle kommen immer mehr oder weniger Bytes an. Wie gesagt die 
Variante mit bUseLib==false (also ohne Lib) geht auch, also gehe ich 
davon aus, dass ich alles richtig verdrahtet habe.

Hier die Ausgabe mal richtig mal falsch.
1
01001000 01100001 01101100 01101100 01101111 // richtige Bits, bUseLib==false
2
10001000 11000001 11001100 11001100 11001111 // falsche Bits, bUseLib==true

Für mich sieht es so aus, dass bei den falschen Bits das 5te Bit einfach 
nach vorne wandern müsste und es würde alles richtig sein. Es kommt mir 
also nicht ganz falsch vor und davon würde ich ausgehen, wenn ich die 
Baudrate falsch einstelle.

Übrigens die Fuse-Bits habe ich nicht angefaßt und läuft damit mit 1Mhz 
takt. Ich habe extra die Leds benutzt um zu schauen ob der Takte (1hz) 
stimmt, den ich angegeben habe. F_CPU habe ich als Präprozessor-Variable 
angegeben, deswegen taucht das nicht auf.

Grüße

von c-hater (Gast)


Lesenswert?

Christoph W. schrieb:

> Ui dann habe ich es hier ja mit richtigen Männer zu tun, die ihren Code
> selber schreiben und dann am besten in assembler.

Ich kann das auch in C oder notfalls auch in C++ und auch noch in 
etlichen anderen Sprachen. Im Tiefschlaf und eventuell sogar mit 3.8‰ 
auf'm Turm.

Du allerdings offensichtlich nicht. Und deswegen solltest du vor allem 
eins lernen: deinen Fähigkeiten angemessenene Bescheidenheit.

> Und ja, wenn ich keine Debuschnittstelle habe, dann lege ich
> mir eben eine zurecht

Du hast die LEDs. Die SIND eine Debugschnittstelle. Bei der 
µC-Entwicklung sogar sehr oft die einzig mögliche!

Nutze sie also erstmal zum Debugging bezüglich der gewünschten 
UART-Funktionalität. Das würde jeder erfahrene Programmierer so machen. 
Nur Vollidioten suchen statt dessen nach der nächste UART-Lib, bis sie 
eine gefunden haben, die mehr oder weniger zufällig in genau dieser 
einen konket vorliegenden Konfiguration der Zielhardware funktioniert...

Nein, das machen nur (Ardu)Idioten so...

von Pandur S. (jetztnicht)


Lesenswert?

Moeglicherweise hast du keinen Quarz sondern den internen RC Oszillator 
verwendet. Der waere dann zu ungenau. und macht solche Fehler, von 
Bitverschieben.
Zweitens war der Mega8 die falsche Wahl. Der hat nichts, der kann 
nichts. Ich wuerde eher etwas in Richtung Mega 644 gehen. Auch im 44pin 
gehause, dafuer 2 Uarts und 64k Flasch

Ich verwende auch keine Libs, sondern hab etwas was fuer meine 
Anwendugne optimiert ist. Ich hab Master-Slave betrieb, bedeutet 
Senden-Empfangen nicht gleichzeitig. Und verwende einen linearen Buffer, 
keinen Ringbuffer.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Christoph W. schrieb:
> Für mich sieht es so aus, dass bei den falschen Bits das 5te Bit einfach
> nach vorne wandern müsste und es würde alles richtig sein. Es kommt mir
> also nicht ganz falsch vor und davon würde ich ausgehen, wenn ich die
> Baudrate falsch einstelle.

Vielleicht bist du ein erfahrener Programmierer, aber du bist ganz gewiß 
kein erfahrener Mikrocontroller-Anwender.
Also versuchen wir es mal mit ein wenig Denken:

1. Ansatzpunkt: Was passiert, wenn die Baudrate bei Sender und Empfänger 
absolut gleich ist? Klar: man kann senden, was man will und es kommt 
niemals aus dem Tritt.

2. Ansatzpunkt: Was passiert, wenn die Baudrate bei Sender und Empfänger 
eben NICHT gleich ist, sondern nur so etwa gleich? Dann läuft das Ganze 
für ein paar Bits durchaus synchron, aber irgendwann eben nicht mehr.

Der Ausweg: man stellt den Sender auf 2 Stopbits ein. Dann hat die 
Übertragung ein ganzes Bit, um sich am Beginn des nächsten Zeichens 
wieder auf dessen Startbit zu synchronisieren.

Nach meiner Erfahrung haben einige der üblichen USB-seriell-Adapter 
genau das Problem, was du beschrieben hast, wenn man am µC nur mit einem 
Stopbit sendet und die Baudrate (von beiden Teilen) nicht sehr exakt 
übereinstimmt.

Also stelle mal auf deinem µC zwei Stopbits ein und versuche es damit.

W.S.

von Pandur S. (jetztnicht)


Lesenswert?

USB verwendet intern 48MHz, entweder mit einem Keramikoszillator oder 
einem Quartz.

von Adam P. (adamap)


Lesenswert?

Christoph W. schrieb:
> Wenn ich nun bUSeLib=true
> setze, dann kommt nichts richtiges mehr auf der anderen Seite an.
> Eigentlich kann das doch nicht so schwer sein, weil ich es mit dem
> Handbuch doch auch leicht hinbekommen habe. Habe ich eventuell eine
> fehlerhaft Lib verwendet? Wo holt ihr euch die Libs?

Hey Christoph,

ich habe das grad mal aus Spaß getestet und ja, irgendwas passt da 
nicht.
Aber das gute daran ist doch, das was du selbst geschrieben hast, 
funktioniert!

Ich würde mir nicht die Mühe machen und den Grund für ein Fehlverhalten 
in einer Lib suchen, wenn man es eben selbst schreiben kann.

Dafür das du nur eine Debug-Ausgabe auf deinem ATmega8 haben möchtest, 
ist die AVR-UART-LIB viel zu überladen.

von Martin V. (oldmax)


Lesenswert?

Hi
Nun, hier wird anscheinend ein Mega8 mit der internen Takterzeugung von 
1 MHz
betrieben. Nicht so gut für serielle Datenübertragung. Es gibt hier auf 
der Website sehr gute Tutorials. In Assembler, vermutlich aber auch in 
C.
@Christoph
Du schreibst von dir, das du erfahrener Programmierer bist, warum? Uns 
beeindruckt das nicht. Im Gegenteil, denn dein Auftreten lässt dich n 
einem anderen Licht erscheinen. Ich habe viele Jahre Maschinen 
programmiert, mich mit Pascal, Basic und Assembler befaßt und auch 
einiges durchaus brauchbares produziert, bin aber weit davon entfernt, 
mich hier als erfahrenen Programmierer vorzustellen.
Das nur mal so nebenbei. Arbeiten mit Controllern setzt außer der 
Fähigkeit Programme zu schreiben ein wenig Kenntnisse der Controller und 
der Hardware voraus und Programmiersprache hin und her, auch in C nimmst 
du nicht einfach einen x-beliebigen Controller und haust da C drauf und 
es läuft völlig ohne ein paar Anpassungen. Wie bereits gesagt, mit dem 
1MHz internen Takt kann man zwar Mal probieren, aber nix stabiles 
erwarten.
An diejenigen, das ein Mega8 nicht zu debuggen sei, völlig falsch, das 
geht auch mit einer LED oder mit dem, was bei Makerconnect unter FAQ in 
meinem Buch beschrieben ist. Da dürft ihr gerne drin blättern, auch wenn 
es nicht ganz fehlerfrei ist. Aber schwere Fehler hab ich auch schon in 
Büchern gefunden, die weit über 50 € lagen.
In dem Sinne, bleibt gesund.
Gruß oldmax

von Adam P. (adamap)


Lesenswert?

Adam P. schrieb:
> Grund für ein Fehlverhalten

Noch eine kurze Anmerkung:
Die Lib funktioniert, jedoch nicht mit deinen 1MHz.
Mit einem 11.0592Mhz ext. Quarz läuft alles problemlos.

von Stefan F. (Gast)


Lesenswert?

Christoph W. schrieb:
> Leider muss ich auch
> feststellen, dass einige nicht nur vom programmieren her vor 30 Jahren
> stehengeblieben sind, sondern auch als Persönlichkeit, schade. Alle die
> mir Konstruktiv helfen wollen schon mal Dank im Voraus.

Sowohl c-hater als auch ich programmieren durchaus auch in modernen 
Programmiersprachen. Wenn du dir mal meine Homepage anschaust, siehst 
du, dass Assembler dort nur eine winzig kleine Ecke belegt. Und der 
c-hater hat mit einen tiefgründigen Kenntnissen hier schon einigen C++ 
programmierern detailliert erklärt, warum etwas nicht so funktionierte, 
wie es erwartet wurde.

Insofern kannst du dich solche frechen Sprüche bitte sparen.

Ein bisschen mehr Dankbarkeit für meinen schlanken funktionierenden 
Lösungsvorschlag in C wäre auch angebracht. Wenn du das gelesen hättest, 
wüsstest du auch über die Tauglichkeit des R/C Oszillators und der 1MHz 
Taktfrequenz bescheid.

Die wenigen Zeilen Code kannst du gerne in eine C++ Klasse verpacken, 
wenn du magst und darin mehr Sinn erkennst, als ich. Aber heule dann 
nicht, dass puts(), printf(), scanf(), etc. alle nicht funktionieren.

von Peter D. (peda)


Lesenswert?

Christoph W. schrieb:
> Habe ich eventuell eine
> fehlerhaft Lib verwendet?

Welche Lib, ich kann nicht hellsehen. Typisch postet man den Link auf 
die verwendeten Sourcen oder man packt das komplette Projekt in ein Zip.

von Christoph W. (christoph_w496)


Lesenswert?

Hi,

danke für den Tipp mit dem Mega644. Ich werde ihn mir anschauen.

Der Tipp das 1Mhz nicht gut sein soll bzw. generell irgendetwas mit dem 
internen Oszi nicht stimmt und das die Fehler verursacht ist genau 
richtig gewesen. Ich habe die Fuse-Bits so angepaßt das der interne Takt 
bei 8Mhz läuft und siehe da es geht nun auch mit der Lib.

Auch auf die Gefahr hin mich weiter als Lib-Schupser zu outen, werde ich 
an der Lib erst einmal festhalten. Damit bleibt es mir erspart mich 
genau mit den Feinheiten von Atmel8-UART zu beschäftigen mit dem FIFO 
und speziellen Registern. Ich möchte das wirklich nur benutzen, um nicht 
blind bei der Programmierung zu sein. Für mich wird das was ich noch vor 
habe genügend herausfordernd und ich widme mich lieber diesen Details.

Ich verstehe nicht wieso ihr auf diesem "erfahrenen Programmierer" 
rumreitet. Wieso stört euch so ein Aussage? Doch nur wenn ihr euch 
irgendwie mit mir vergleicht. Wieso solltet ihr das? Ich habe es einfach 
hingeschreiben um damit auszudrücken, dass ihr mit mir als Programmierer 
reden könnt (ich also die Begrifft recht gut verstehe) und ihr mir 
Code-Beispiele geben könnt. Und mit dem µC-Anfänger will ich genau das 
Geneteil ausdrücken. Auch das µC-Anfänger ist relativ, wie das mit dem 
erfahrenen Programmierer. Darüber regt sich aber keiner auf. Im 
Gegensatz zu meiner Oma würde ich mich aber schon als erfahrener 
Programmierer bezeichnen, aber auch als erfahrener µC-Programmierer :-)

Nochmals danke für euch Hilfe. Spannend mit euch zu reden.
Grüße

von Peter D. (peda)


Lesenswert?

Christoph W. schrieb:
> es geht nun auch mit der Lib.

Was ist an der Lib so geheim, daß Du sie nicht verlinken oder posten 
kannst?

von S. Landolt (Gast)


Lesenswert?

> Tipp mit dem Mega644. Ich werde ihn mir anschauen

Dann möchte ich Joggel E. ein wenig korrigieren (ich wurde nicht umsonst 
an anderer Stelle als Pedant bezeichnet): es fehlt ein "P", also 
ATmega644P, der ATmega644 hat nur einen USART. Übrigens könnte man dann 
gleich auf den ATmega1284P umsteigen, mit seinen 16 KiB RAM und Timer3. 
Oder, warum nicht, falls es räumlich kleiner sein soll, der AVR128DA28.
  Nur der ATmega8, der ist "vor 30 Jahren stehengeblieben" - na ja, 
nicht ganz.

von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

> Der Tipp das 1Mhz nicht gut sein soll ... ist genau richtig gewesen.

So ganz klar ist mir das nicht: gleich zu Beginn hieß es
> Mithilfe der Doku war es auch nicht schwer eine
> funktionsfähige Verbindung hinzubekommen.
Da muss also ganz bewusst, nach Studium des Datenblattes, das UCSRA.U2X 
eingeschaltet worden sein, sonst hätten 9600 Bd bei 1 MHz nie&nimmer 
funktioniert, bei einem Fehler von 7 %. Wenn also in der Dokumentation 
dieser Library nicht explizit auf die Eigenheiten des Schalters USE_2X 
hingewiesen wurde, so hätten Sie doch spätestens an dieser Ihrer 
Programmstelle
1
#if USE_2X
2
    UCSRA |= (1 << U2X);
3
  #else
4
    UCSRA &= ~(1 << U2X);
5
  #endif
stutzig werden müssen.

von Christoph W. (christoph_w496)


Lesenswert?

Hi,

ich habe 2 verschiedene Libs ausprobiert:
1) https://github.com/andygock/avr-uart
2) https://github.com/jnk0le/AVR-UART-lib

Die 2te Lib geht nun mit dem eingestellten Takt von 8Mhz und 0,5Mbps.

Ich habe es gerade noch einmal nachgestellt und du hast vollkommen 
recht. Der Codeteil
1
  #if USE_2X
2
    UCSRA |= (1 << U2X);
3
  #else
4
    UCSRA &= ~(1 << U2X);
5
  #endif
stammt aus util/setbaud.h von der mitgelieferten avr-lib, die dabei ist. 
Intern wird über eine Formel überprüft wie der eingestellte Takt und die 
Baudrate im Verhältnis stehen und im Fall von 1Mhz und 9600bps wurde 
USE_2X=1 gesetzt.

Schönen Abend euch

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.