Forum: Mikrocontroller und Digitale Elektronik Datenübertragung über USART0 und USART1


von Luffy M. (monkeydluffy)


Angehängte Dateien:

Lesenswert?

Moin,

ich habe zur Verfügung ein Mikrocontrollerboard 644P, der zwei USARTs 
besitzt. Es kommen Daten (Koordinaten x und y) von PC über die serielle 
Schnittstelle (RS232) an USART0. Dann muss ab dem USART1 die empfangenen 
Daten über die serielle Schnittstelle (RS485)  an zwei Motorsteuerungen 
zugeschickt werden. Darüber hinaus besitzen die beide Motorsteuerungen 
ein RS485-Anschluß als serielle Schnittstelle, um die Daten zu 
aufzunehmen.

Das erste Steuerprogramm(geschrieben in c++), das zur Übertragung von 
Daten ab dem PC zum Mikrocontrollerboard 644P über die RS232 dient, 
läuft einwandfrei.

Aber das zweite Steuerprogramm (geschrieben in C unter AVRstudio), das 
zur Übertragung von Daten ab dem Mikrocontrollerboard 644P über die 
USART0 und USART1 dient, läuft nicht. Die folgende Bedingungen 
if(uart_count==2 && control==0) und if(uart_count==2 && control==1) 
werden ewig ausgeführt und die andere Befehle des Main-Programms werden 
nicht durchgeführt. Außerdem sieht es so aus, wie meine beide 
Interruptroutine überhaupt nicht ausgeführt wurden.

Bitte, kann jemand mir helfen. Ich komme einfach nicht klar.

Meine Code liegen im Anhang.

Danke im Voraus.

mfg monkeydluffy

von Karl H. (kbuchegg)


Lesenswert?

> Das erste Steuerprogramm(geschrieben in c++), das zur Übertragung
> von Daten ab dem PC zum Mikrocontrollerboard 644P über die RS232
> dient, läuft einwandfrei.

Was heißt das?
Kommen die Daten am µC korrekt an. Hast du das kontrolliert?

(Ob dein PC-Programm läuft oder nicht, interessiert hier nicht wirklich. 
Da kommt was über die Serielle und der µC muss das korrekt empfangen. 
Für uns hier im Forum ist in erster Linie nur der Teil interessant)

So wie ich das sehe, machst du den Kardinalfehler schlechthin: Du willst 
alles gleichzeitig entwicklen. Eine vernünftige Entwicklungsstrategie 
sieht aber so aus: Sieh zu, dass du dich immer nur auf EINEN Aspekt 
konzentrierst, der möglichst von nichts anderem abhängt. D.h. um die 
UART0 (die vom PC) zu testen, konzentrier dich NUR auf diese UART und 
sieh zu, dass du die korrekt in Betrieb nimmst und zwar in einer 
testbaren Form! Testbare Form heißt an dieser Stelle NICHT die Zeichen 
an die UART1 weiter zu geben. Denn die UART1 ist noch nicht getestet und 
wenns nicht funktioniert, dann weißt du nicht ob es an der UART0 oder an 
der UART1 liegt. Insofern hast du daher beim Testen eine Abhängigkeit 
zwischen diesen beiden Teilsystemen, die du unter keinen Umständen haben 
willst. Ich nenn das gerne: Du eröffnest einen 2-Frontenkrieg. Und den 
haben schon ganz andere als du verloren.

Die Devise lautet "abspecken". Einzelsysteme schaffen, die auch einzeln 
mit möglichst wenig drumherum testbar sind.

Nicht davon ausgehen, dass du keine Fehler machen wirst. Du MACHST 
Fehler (wie wir alle), d.h. du musst dir selbst deine 'Meilensteine' so 
setzen, dass du Fehler möglichst früh bemerkst. Wenn ich ein Auto 
entwickeln soll, dann ist ein erster Test mit dem kompletten Auto viel 
zu spät. Mein erster Test wird vielleicht sein, ob ich das Getriebe auf 
der Werkbank drehen kann, ob ich es schalten kann, ob das immer noch 
funktioniert, wenn ich es mit einer Bohrmaschine antreibe. Und erst dann 
wird das Getriebe als vorgetestete Komponente ins Auto eingebaut. Dann 
baut man den Kabelbaum mal losgelöst vom Auto in der Werkstatt auf und 
hängt da Ersatzteile drann um zu sehen, ob alles funktioniert.

So was
> Außerdem sieht es so aus, wie meine beide Interruptroutine überhaupt
> nicht ausgeführt wurden.
darf bei dem Programmstand, den du da präsentierst, überhaupt nicht mehr 
auftreten. Das hättest du längst vorher abtesten müssen, ob deine UART0 
korrekt Receive Interrupts auslöst oder nicht.

von Luffy M. (monkeydluffy)


Angehängte Dateien:

Lesenswert?

Hi,

Danke Karl für deine schnelle Antwort und ausführliche Ratschläge. Ich 
habe deine Tipps befolgt und habe versucht, ein Zeichen 'B' im UDRO zu 
schreiben. Dann habe ich versucht, dieses Zeichen nach UDR1 zu 
übertragen. Leider bekommt UDR0 und UDR1 kein Zeichen.

Bitte, kannst du mir segen, was ich falsch mache. ich bin einfach jetzt 
verwirrt.

Danke im voraus.

von spess53 (Gast)


Lesenswert?

Hi

>while(!(UCSR0A & (1<<RXC0)) );
....
> UDR0 = 'b';
>return UDR0;

Das kann nicht gehen. UDR0 sind praktisch zwei Register. Beim Scheiben 
nach UDR0 greifst du auf das 'UDR0' für TX zu. Beim Lesen auf das 'UDR0' 
von RX.

MfG Spess

von UDR0 (Gast)


Lesenswert?

>habe deine Tipps befolgt und habe versucht, ein Zeichen 'B' im UDRO zu

Hast Du nicht.
Ist die Zuweisung UDR0='b' überhaupt zulässig?

von Karl H. (kbuchegg)


Lesenswert?

Ich frage mich allen Ernstes, was so schwer daran ist, wenn dein erstes 
Testprogramm (und bitte: schreibs neu! nimm nicht den alten Code her und 
kommentiere wie ein Wahnsinniger aus - da verliert man ganz schnell den 
Überblick) erst mal so aussieht
1
#include <avr/io.h>
2
3
#define FOSC 8000000 // Clock Speed
4
#define BAUD 9600UL
5
6
// Berechnungen zur Baudrate:
7
8
#define UBRR_VAL ((FOSC+BAUD*8)/(BAUD*16)-1)   // clever runden
9
10
11
void USART_Init (unsigned int ubrr)
12
{
13
  UBRR0H = (unsigned char)(ubrr>>8);
14
  UBRR0L = (unsigned char) ubrr;
15
16
  UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (0<<RXCIE0)|(0<<TXCIE0);
17
  UCSR0C = (1<<USBS0) | (0<<UCSZ02)|(1<<UCSZ01)|(1<<UCSZ00);
18
} 
19
20
unsigned char USART0_Receive (void)
21
{
22
  while(!(UCSR0A & (1<<RXC0)) )
23
    ;
24
  return UDR0;
25
}
26
27
void USART0_Transmit (unsigned char data)
28
{
29
  while ( !(UCSR0A & (1<<UDRE0)) )
30
    ;
31
  UDR0 = data;
32
}
33
34
int main (void)
35
{
36
  USART_Init(UBRR_VAL) ;  // USART Initialization
37
38
  while(1)
39
  {
40
    USART0_Transmit( 'X' );
41
  }
42
}


Und das testest du erst mal.
Und zwar in dem du Hyperterminal (oder HTerm) am PC an die entsprechende 
COM Leitung ansetzt. Solange du im Hyperterminal keine X auftauchen 
siehst, brauchst du nämlich überhaupt nicht weiter machen - denn dann 
ist an deiner Konfiguration grundsätzlich was faul. Meistens ist es die 
FOSC Angabe, die nicht mit der Realität übereinstimmt. Es könnte aber 
auch ein falsch gekreuztes Kabel sein. Daher muss man das testen! Und 
getreu dem Motto 'So einfach wie möglich testen', testet man zunächst 
die Richtung vom µC zum PC. Denn wir wissen, dass die Serielle am PC 
funktioniert! Was wir nicht wissen ist, ob die UART0 im µC Bytes so 
absetzt, dass sie der Baudrate entsprechen, bzw. ob das Kabel richtig 
ist. Aber zumindest ist eine Unbekannte dahingehend weggefallen, dass 
wir 100% wissen: Der Empfänger (bzw. die Serielle Schnittstelle dort) 
ist auf jeden Fall korrekt - wenn irgendwo ein Fehler ist, dann sicher 
nicht dort.

Wenn das dann funktioniert, dann wird auch die umgekehrte Senderichtung 
auf Anhieb funktionieren. ABER: Auch das testen wir sofort wieder (es 
könnte ja auch sein, dass das Kabel einen Fehler hat). UNd zu diesem 
Behufe wird das Testprogramm abgewandelt:
1
int main (void)
2
{
3
  char c;
4
5
  USART_Init(UBRR_VAL) ;  // USART Initialization
6
7
  while(1)
8
  {
9
    c = USART0_Receive();
10
    USART0_Transmit( c );
11
  }
12
}

Alles was du im Hyperterminal tippst, muss vom µC zurückgeschickt werden 
und wird dann vom Hyperterminal angezeigt. Das das zurückschicken 
funktioniert, wissen wir bereits. Das wurde im vorhergehenden Test 
nachgewiesen, dass das so ist. D.h. dieser Test ist spezifisch auf das 
'Senden vom PC zum µC'. Kriegst du das Echo beim Tippen, dann machst du 
auch mal den Gegentest: Du legst einen Ziegelstein auf die PC-Tastatur 
(so dass der PC dauersendet) und steckst das Kabel aus: Das Echo muss 
sofort aufhören. Steckst du das Kabel wieder an, muss das Echo wieder da 
sein.

Erst dann kann man guten Gewissens sagen: Nach menschlichem Ermessen ist 
damit die UART0 erst mal soweit in Betrieb genommen worden, dass es sich 
um ein zumindest in den Grundzügen getestetes Subsystem handelt.


Hab keine Scheu davor dir Testprogramme zu machen, die nur zu dem Zweck 
da sind, dass etwas getestet wird! Den Code kannst du danach immer noch 
weiterverwenden. Hab auch keine Scheu davor, mal Code zu löschen 
(anstatt auszukommentieren). Ein Programmierer löscht in seinem 
Berufsleben sicherlich 10 mal mehr Code als dann letzendlich übrig 
bleibt.
Viel wichtiger ist es, dass dein Code ÜBERSICHTLICH ist. Mit verstreuten 
Codefetzen zwischen seitenweise auskommentiertem Code kann man aber 
nicht von Übersichtlichkeit sprechen.

von monkeydluffy (Gast)


Lesenswert?

Hallo,

danke schön nochmal für die ausführlichen Erklärungen. Ich weiße nicht, 
was denn los mit mir ist. Vielen dank für die Tipps.

mfg monkeydluffy

von Luffy M. (monkeydluffy)


Angehängte Dateien:

Lesenswert?

Moin,

 Nochmal danke schön Karl Heinz für deine Tipps

Ich habe die Beispielcode, die du mir gezeigt hat, verwendet und habe 
die USART0 in Betrieb genommen. Die beide Teste haben mit Erfolgreich 
geklappt.

Aber jetzt, stelle ich mich die Frage, wie ich der USART1 (RS485) in 
Betrieb nehmen kann. Wie sollen sich die beide USARTs die Daten 
austauchen?

Bitte, schlagen sie mir einige Tipps vor.

Danke im Vorraus.

mfg monkeydluffy

von Karl H. (kbuchegg)


Lesenswert?

Luffy Monkey schrieb:

> Aber jetzt, stelle ich mich die Frage, wie ich der USART1 (RS485) in
> Betrieb nehmen kann.

Erst mal:
Genau wie die andere. Du brauchst irgendwas, mit dem du kontrollieren 
kannst, ob das was du sendest, korrekt ist.

> Wie sollen sich die beide USARTs die Daten
> austauchen?

Nix gelernt aus dem Vorgehen?
Du willst schon wieder den übernächsten Schritt zuerst machen. Wie da 
jetzt die Daten von der einen USART zur anderen kommen, ist zum jetzigen 
Zeitpunkt noch uninteressant. Dafür gibt es 2 (eigentlich 3)
Themenkreise, die viel interessanter sind.

1) USART1 in Betrieb nehmen. Erst mal genau so, wie die 0-er
2) USART0 auf Interrupt Betrieb umstellen.
   Wenn ein Zeichen empfangen wird, soll ein Interrupt ausgelöst werden.
   (und im Testprogramm dann sofort wieder zurückgeschickt werden)
3) USART1 auf Interrupt Betrieb umstellen.

Und erst jetzt sind die Einzelteile vorhanden, dass man sich überlegen
kann, wie man dann in der main() Hauptschleife eintreffende Zeichen von
der einen UART an die andere weitergibt.
Erst mal nur weitergeben, später dann ein Regelwerk da drüber legen,
welches regelt was wann und warum weitergeleitet wird.


Es ist immer das gleiche Spiel:
Erst mal macht man sich die Basiskomponenten klar und testet die. Und 
dann arbeitet man sich schrittweise an die gewünschte Funktionalität 
ran.

von Uwe (Gast)


Lesenswert?

Eigenes Protokol ausdenken bzw. was ist mit dem Protokol der 
Motorsteuerungen ?
Also wenn die Motorsteuerungen an dem gleichen RS485 Port dranhängen 
dann muß in deren Protokoll eine Adresse drin sein bzw. eine Achsnummer.
Du könntest das Protokoll einfach weiterbenutzen, aber dann stellt sich 
die frage warum du überhaupt einen µC drin hast.
Was hattest du denn eigentlich mit dem µC vor ?

von Luffy M. (monkeydluffy)


Lesenswert?

Ok, danke schön Karl Heinz.

Ich mache weiter.

mfg monkeydluffy

von Karl H. (kbuchegg)


Lesenswert?

Und als nächstes sollte man sich mal darüber Gedanken machen, was Uwe da 
gesagt hat: Nach welchem Protokoll soll die Übertragung vom PC zum µC 
laufen. So wie das aussieht machst du dir da selber das Leben schwer in 
dem du überhaupt kein Protokoll hast. Statt dessen hast du das gemacht, 
was am Dümmsten ist: Der PC sendet einfach und der µC soll irgendwie 
auseinanderklamüsern, was was ist.

von Luffy M. (monkeydluffy)


Angehängte Dateien:

Lesenswert?

Hi,

ich habe gerade mein USART1 getestet. Der Test war eine ziemliche gute 
Lektion für mich. Kurz gesagt, ich habe geschafft, der USART1 in Betrieb 
zu nehmen.

Jetzt werde ich versuchen, USART0 auf Interrupt Betrieb umzustellen.

Danke eure Hilfe.

mfg monkeydluffy

von Luffy M. (monkeydluffy)


Angehängte Dateien:

Lesenswert?

Moin,

ich habe der USART1 mit Interrupt umgestellt und bin ziemlich zufrieden. 
Aber ich komme nicht klar, wenn ich der USART0 mit Interrupt umstelle.

Bitte, kann jemand mir helfen.

danke im Voraus.

mfg monkeydluffy

von Luffy M. (monkeydluffy)


Angehängte Dateien:

Lesenswert?

Moin,

ich habe der USART0 und USART1 auf Interrupt Betrieb umgestellt und bin 
ziemlich mit den Ergebnissen froh.

ich habe versucht, die Kommukation zwischen der USART0 und USART1 Im 
Interrupt Betrieb aufzubauen. Von mir aus, das scheint gut zu laufen und 
der Test hat auch geklappt.

Sei ihr mit meinen C-Coden einverstanden ? Oder soll ich noch was in 
meinem C-Code berücksichtigen ?

Danke im voraus.

mfg monkeydluffy.

von spess53 (Gast)


Lesenswert?

Hi

Du gibst die Interrpts RXCIE0, TXCIE0 und TXCIE1 frei. Hast aber nur die 
Interruptroutinen ISR(USART0_RX_vect) und ISR(USART1_TX_vect).

> ISR (USART1_TX_vect)
>{
> UDR1 = data0 ;
>}

Dieser Interrupt wird ausgelöst, wenn USART1 ein Byte übertragen hat. 
Damit produzierst du einen kontinuierlichen Datenstrom.

MfG Spess

von Luffy M. (monkeydluffy)


Lesenswert?

Hallo,

spess53 scchrieb:

> ISR (USART1_TX_vect)
>{
> UDR1 = data0 ;
>}

> Dieser Interrupt wird ausgelöst, wenn USART1 ein Byte übertragen hat.
> Damit produzierst du einen kontinuierlichen Datenstrom.

Wie kann ich die Erzeugung eines kontinuierlichen Datenstroms vermeiden 
?

Danke im Voraus.

mfg

von spess53 (Gast)


Lesenswert?

Hi

>Wie kann ich die Erzeugung eines kontinuierlichen Datenstroms vermeiden
>?

Indem du zum Senden keinen Interrupt benutzt.

MfG Spess

von Luffy M. (monkeydluffy)


Lesenswert?

Hi,

Spess53 schrieb:

> Indem du zum Senden keinen Interrupt benutzt.

Das heißt, alle Interruptroutine müssen deaktiviert werden. Oder nur die 
Interruptroutine ISR(USART1_TX_vect) muss deaktiviert werden.

mfg

von Karl H. (kbuchegg)


Lesenswert?

Luffy Monkey schrieb:
> Hi,
>
> Spess53 schrieb:
>
>> Indem du zum Senden keinen Interrupt benutzt.
>
> Das heißt, alle Interruptroutine müssen deaktiviert werden. Oder nur die
> Interruptroutine ISR(USART1_TX_vect) muss deaktiviert werden.

Wenn du nur den Sende-Interrupt deaktivierst, dann reicht das schon. Du 
willst ja nicht das Komplettsystem beeinträchtigen, nur weil da jetzt 
eine Übertragung komplett rausgegangen ist.

von Karl H. (kbuchegg)


Lesenswert?

Ooops

Das hier
1
/*-- Interruptroutine USART1 beim Senden --*/ 
2
3
 ISR (USART1_TX_vect)
4
{
5
 UDR1 = data0 ;
6
}

ist ja kompletter Quatsch.

Der Interrupt wird ausgelöst NACHDEM das Zeichen gesendet wurde.

Tu dir selbst einen Gefallen und hol dir zb vom Peter Fleury die UART 
Lib. Sonst hampelst du noch 2 Wochen an dieser Problematik herum.
Dort kannst du dir ansehen, wie man die Sache mit Interrupts vernünftig 
angeht und was man sonst noch so braucht - zb eine FIFO, die eingehende 
Zeichen zwischenspeichert solange das Programm anderweitig beschäftigt 
ist und sich nicht darum kümmern kann die Zeichen abzuholen.

von Luffy M. (monkeydluffy)


Lesenswert?

Hi,

Vielen für die Tipps, ich werde die UART Lib von Peter Fleury ansehen.

mfg monkeydluffy

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.