Forum: Mikrocontroller und Digitale Elektronik string an den PC via Hyperterminal senden, nur zwei Zeichen!


von Matze (Gast)


Lesenswert?

Hallo zusammen,

könnt ihr mir bitte sagen warum nur die ersten beiden Zeichen meines 
"HalloWelt" strings gesendet werden?

ich bin noch Anfänger in SAchen Mikrokontrollertechnik.

Vielen Dank für Eure Hilfe,

Matthias.


anbei mein Code



#include <avr/io.h>
// #include <util/delay.h>    // wenn das aktiviert ist, dann sendet er 
gar nichts, wißt ihr warum? brauche ich doch  für delay funktionen, 
nicht wahr?

#ifndef F_CPU

#warning "F_CPU war noch nicht definiert, wird nun nachgeholt"


#define F_CPU 8000000UL

#endif



#define BAUD 4800UL      // Baudrate

// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = 
kein Fehler.


#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu 
hoch!
#endif





int main(void)
{



UCSRB |= (1<<TXEN);

UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // Asynchron 8N1

 UBRRH = UBRR_VAL >> 8;
 UBRRL = UBRR_VAL & 0xFF;



unsigned char tab[] = "HalloWelt";    //Tabelle als String
unsigned int i;




for (i=0;i<9; i++)
  {
  //while (!(UCSRA & (1<<UDRE)))  //warten bis senden möglich, wenn das 
aktiviert wird, sendet er gar nicht
  UDR=tab[i];                  //sendet nur "Ha" warum?
                                 //UDR=tab[5]; z.B. würde er senden, 
wenn   ich das direkt angebe, nur in der schleife nicht. :-(
  }




return 0;
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du schreibst:

  //while (!(UCSRA & (1<<UDRE)))  //warten bis senden möglich, wenn das
aktiviert wird, sendet er gar nicht

Und da steckt der Fehler. Die Zeile muss rein, aber richtig, d.h. mit 
einem Schleifenrumpf und zwar einem leeren. Ohne den wartet das while 
nicht auf die sendebereite UART, sondern ballert blind und stur Zeichen 
an die wahrscheinlich nach dem 2. Zeichen besetzte UART (Zeile 
UDR=tab[i];). Schau dir den bewährten Code im Tutorial an.

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

Matze schrieb:
> Hallo zusammen,

...
1
> for (i=0;i<9; i++)
2
>   {
3
>   //while (!(UCSRA & (1<<UDRE)))  //warten bis senden möglich, wenn das
4
> aktiviert wird, sendet er gar nicht
5
>   UDR=tab[i];                  //sendet nur "Ha" warum?
...

So schreibst Du ein neues Zeichen ins Schieberegister, bevor das alte 
gesendet wurde.

Wenn Du "while (!(UCSRA & (1<<UDRE))) UDR=tab[i]; " benutzt, wird, 
solange der Sender nicht frei ist ein Zeichen ins SR geschrieben. Daher 
wird der TX auch nie frei...

Ich spende mal ein *;*: "while (!(UCSRA & (1<<UDRE)));" und schon sieht 
alles besser aus. Für solche Sachen wird C geliebt ;-)

Falk

von Matze (Gast)


Lesenswert?

Hallo Stefan,

vielen Dank, dass Du mir geholfen hast! :-) Über Deine Hilfe bin ich 
sehr froh.  Jetzt kann ich weiter an diesem Problem arbeiten.

ich habe das schon solange probiert und es ging nie.




UCSRB |= (1<<TXEN);

UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // Asynchron 8N1

 UBRRH = UBRR_VAL >> 8;               //diese beiden
 UBRRL = UBRR_VAL & 0xFF;

Könntest Du mir vielleicht auch erklären wozu die letzten beiden Zeilen 
sind?
Nur diese habe ich nicht richtig verstanden.
die oberen ja
das hat irgendetwas mit der Frequenzteilerberechnung zu tun meine ich.

Viele Grüße, Matthias.

von Matze (Gast)


Lesenswert?

Hallo Falk,

vielen Dank, dass Du mir geholfen hast! :-) Über Deine Hilfe bin ich
sehr froh.  Jetzt kann ich weiter an diesem Problem arbeiten.

ich habe das schon solange probiert und es ging nie.

Es war nur ein einfaches ;   :-)


Hast du eine Erklärung warum ich dieses nicht definieren darf?

#include <util/delay.h>   ??

dann sendet er nämlich nur ein merkwürdiges Zeichen.



Ansonsten hätte ich hier noch eine Frage, wenn Du so nett wärst mir 
diese auch zu beantworten.





UCSRB |= (1<<TXEN);

UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // Asynchron 8N1

 UBRRH = UBRR_VAL >> 8;               //diese beiden unteren
 UBRRL = UBRR_VAL & 0xFF;

Könntest Du mir vielleicht auch erklären wozu die letzten beiden Zeilen
sind?
Nur diese habe ich nicht richtig verstanden.
die oberen ja
das hat irgendetwas mit der Frequenzteilerberechnung zu tun meine ich.

Viele Grüße, Matthias.

von ... (Gast)


Lesenswert?

Die stellen die Baudrate ein (Deine weiter oben definierten 4800Baud).
Die Formel, wie man aus Taktfrequenz und gewünschter Baudrate den 
passsenden Wert für das UBRR Register errechnet, steht im Datenblatt. 
Damit Du das nicht selber ausrechnen mußt, erledigen das ein paar Makros 
beim Compilieren für Dich (die unter "// Berechnungen").

von Matze (Gast)


Lesenswert?

Danke für Deine schnelle Hilfe!

Viele Grüße, Matthias.

von avr (Gast)


Lesenswert?

Matze schrieb:
> Hast du eine Erklärung warum ich dieses nicht definieren darf?

delay.h benötigt einen Wert für F_CPU oder setzt einen
"Default-Wert" (glaube 3,xx MHz).

Der F_CPU - Wert geht in deine Berechnung ein, deine DEF mit
8 MHz wird übersprungen. Daher ist die Baudrate falsch
gesetzt.

=> erst deine Frequenz definieren dann delay.h einbinden

avr

von Christian S. (kruemel)


Lesenswert?

Hallo,

möchte auch gerne Strings senden. Zeichen senden klappt nun mit Uart. 
Habe hier jetzt auch mal das C Programm nachgebaut und das mit einer for 
Schleife realisiert. Bei mir funktioniert es nicht.

Kommt nach meinem C Programmcode auch ein ; nach der while Schleife?
Würde ich das machen, würde doch nicht gewartet werden?

1
#define F_CPU 4000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
 
6
#define BAUD 9600UL      // Baudrate
7
 
8
// Berechnungen
9
10
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
11
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
12
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
13
 
14
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
15
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
16
#endif 
17
18
19
int main(void)
20
{
21
 
22
   UBRRH = UBRR_VAL >> 8;
23
   UBRRL = UBRR_VAL & 0xFF;
24
   
25
   UCSRB = (1<<RXEN)|(1<<TXEN);            //UART TX einschalten
26
   UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);     //Asynchron 8N1
27
28
unsigned char s[] = "HalloWelt"; 
29
unsigned int i;  
30
   
31
   
32
for (i=0;i<9; i++)
33
{
34
    while (!(UCSRA & (1<<UDRE)))
35
  {
36
  }
37
  UDR=s[i];             
38
}
39
40
    return 0;
41
}


Gruß
Christian

von Karl H. (kbuchegg)


Lesenswert?

Christian S. schrieb:

> möchte auch gerne Strings senden. Zeichen senden klappt nun mit Uart.

Du kannst also ein einzelnes Zeichen versenden?

> Habe hier jetzt auch mal das C Programm nachgebaut und das mit einer for
> Schleife realisiert. Bei mir funktioniert es nicht.

Definiere bitte "funktioniert nicht".
Was genau funktioniert nicht? Sieht du was? Einzelne Zeichen? Falsche 
Zeichen? Gar nichts?

>
> Kommt nach meinem C Programmcode auch ein ; nach der while Schleife?
> Würde ich das machen, würde doch nicht gewartet werden?

C-Buch!
Du brauchst eines! Ohne hat das wenig Sinn

while gehört zu den Compound Statemente, so wie auch if

Das bedeutet die Syntax lautet

  "while" "(" Ausdruck ")"
     Anweisung

Der erste Teil dürfte klar sein. Als ANweisung kann jede beliebige 
Anweisung stehen. Das kann sein eine leere Anweisung, die mit einem 
einzelnen ; geschrieben wird. Oder aber das können mehrere Anweisungen 
sein, die als solche wieder in einen Block mittels { } verpackt werden. 
Nun sagt allerdings niemand, dass ein Block zwingend aus mehreren 
Anweisungen bestehen muss. Das kann auch nur eine Anweisung sein, das 
kann aber auch gar keine Anweisung sein.
1
   while ( !(UCSRA & (1<<UDRE)) )     // <- hier ist der Ausdruck, der
2
                                      // die Schleife steuert
3
4
      ;                               // hier ist die davon abhängige Anweisung

ob du das dann so schreibst
1
   while ( !(UCSRA & (1<<UDRE)) )     // <- hier ist der Ausdruck, der
2
                                      // die Schleife steuert
3
4
   {                                  // der abhängige Teil ist jetzt ein
5
                                      // ein Codeblock, der hier halt zufällig
6
                                      // leer ist
7
   }

oder so
1
   while ( !(UCSRA & (1<<UDRE)) )     // <- hier ist der Ausdruck, der
2
                                      // die Schleife steuert
3
                                      
4
   {                                  // hier beginnt der Codeblock, der
5
                                      // vom while abhängt
6
 
7
     ;                                // und aus einer leeren Anweisung besteht
8
9
   }                                  // und hier endet der Code Block

ist alles Jacke wie Hose. Entscheidend ist, das der vom while abhängige 
Teil, der sog. Schleifenrumpf einfach nur leer ist. Egal wie man das 
erreicht.

-> C-Buch!

von Christian S. (kruemel)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du kannst also ein einzelnes Zeichen versenden?

Ja ich kann einzelne Zeichen versenden. Das funktioniert.

Karl heinz Buchegger schrieb:
> Definiere bitte "funktioniert nicht".
> Was genau funktioniert nicht? Sieht du was? Einzelne Zeichen? Falsche
> Zeichen? Gar nichts?

Funktioniert nicht, heißt ich sehe am PC keine Zeichen, nichts.

Alles klar, es muss also eine leere Anweisung stehen, so wie auch beim 
Senden von nur einem Zeichen. Steht ja bei mir auch im Quelltext. Mein 
HalloWelt kommt aber trotzdem nicht an.

Viele Grüße
Christian

von Karl H. (kbuchegg)


Lesenswert?

Christian S. schrieb:
> Karl heinz Buchegger schrieb:
>> Du kannst also ein einzelnes Zeichen versenden?
>
> Ja ich kann einzelne Zeichen versenden. Das funktioniert.

Gut.
Wie sieht das in Codeform aus?

>
> Funktioniert nicht, heißt ich sehe am PC keine Zeichen, nichts.

Das ist ... unlogisch, Wengistens das erste 'H' müsstest du ja sehen, da 
ja dein Einzelzeichenversenden funktioniert.


Modularisier doch mal ein wenig (und die for-Schleife ist auch Mist)

1
#define F_CPU 4000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
 
6
#define BAUD 9600UL      // Baudrate
7
 
8
// Berechnungen
9
10
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
11
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
12
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
13
 
14
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
15
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
16
#endif 
17
18
////////////////////////////////////////////////////////////////
19
// UART initialisieren
20
//
21
void uart_init()
22
{
23
   UBRRH = UBRR_VAL >> 8;
24
   UBRRL = UBRR_VAL & 0xFF;
25
   
26
   UCSRB = (1<<RXEN)|(1<<TXEN);            //UART TX einschalten
27
   UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);     //Asynchron 8N1
28
}
29
30
////////////////////////////////////////////////////////////////
31
// ein einzelnes Zeichen ausgeben
32
//
33
void uart_putc( char c )
34
{
35
  while (!(UCSRA & (1<<UDRE)))
36
  {
37
  }
38
  UDR = c;       
39
}
40
41
////////////////////////////////////////////////////////////////
42
// Einen String ausgeben
43
//
44
void uart_puts( const char * s )
45
{
46
  while( *s )
47
    uart_putc( *s++ );
48
}
49
50
////////////////////////////////////////////////////////////////
51
int main(void)
52
{
53
  uart_init();
54
55
  uart_putc( 'X' );
56
57
  while( 1 )
58
  {
59
    uart_puts( "Hallo Welt\r\n" );
60
    _delay_ms( 100 );
61
  }
62
}


Steht alles so schön modularisiert im Tutorial.
Die 4Mhz stimmen?

von Christian S. (kruemel)


Lesenswert?

1
#define F_CPU 4000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
 
6
#define BAUD 9600UL      // Baudrate
7
 
8
// Berechnungen
9
10
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
11
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
12
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
13
 
14
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
15
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
16
#endif 
17
18
int main(void)
19
{
20
   UBRRH = UBRR_VAL >> 8;
21
   UBRRL = UBRR_VAL & 0xFF;
22
   
23
   
24
   UCSRB = (1<<RXEN)|(1<<TXEN);            //UART TX einschalten
25
   UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);     //Asynchron 8N1
26
   
27
   
28
while( 1 ) {
29
while (!(UCSRA & (1<<UDRE)))           /* warten bis Senden moeglich */
30
{
31
}
32
33
UDR = 'X';
34
_delay_ms(500);
35
36
} 
37
}

Das ist der Quellcode für ein Zeichen senden. Wie gesagt funktioniert.
Ich werde mir dann nochmal die put-Funktionen anschauen. Ich dachte das 
es über die for-Schleife auch gehen sollte.

Danke für die Hilfe.

Viele Grüße
Christian

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.