Forum: Compiler & IDEs UART übergabe eines #defines


von qwer (Gast)


Lesenswert?

Im Header File
1
#define val   "PF10301*25\r\n"


Aufruf im Main
1
USART_TRANSMIT(val);



Funktion
1
void USART_TRANSMIT(char* adr)
2
{
3
  for(int i=0; i<sizeof(adr);i++)
4
  {
5
  
6
  while ( !( UCSR0A & (1<<UDRE0)) );
7
  
8
  UDR0 = adr[i];    
9
  }
10
11
}

Am PC gibt er mir aber leider nur die ersten beiden Characters aus.
Was is falsch?

: Verschoben durch User
von Walter T. (nicolas)


Lesenswert?

Was kommt denn bei "sizeof(adr)" raus?

von qwer (Gast)


Lesenswert?

Wohl zwei, aber warum?

von Walter T. (nicolas)


Lesenswert?

Vermutlich weil Dein AVR 16-bit-Adressen hat.

von qwer (Gast)


Lesenswert?

Wie komme ich dann an den waren size vom String?

von Bronco (Gast)


Lesenswert?

strlen()

von Karl H. (kbuchegg)


Lesenswert?

Nachzulesen in jedem noch so grindigem C-Buch, im Kapitel über 
Stringverarbeitung, bzw. schon vorher im Kapitel über Arrays:

Eine Funktion kann die Größe eines ihr übergebenen Arrays nicht 
feststellen!

Das betrifft alle Strings insofern, als eine Funktion die Länge des 
Strings nicht am Pointer festmachen kann, sondern auf andere Hilfen 
angewiesen ist. Genau aus diesem Grund gibt es in C die Konvention, das 
alle Strings mit einem \0 Character enden. Und es gibt spezielle 
String-Funktionen, die genau dieses wissen und ihre Operation darauf 
abstimmen.

zb. die Funktion strlen() welche, die tatsächliche Länge eines Strings 
fetsstellt.


Das war die ultra-ultra-ultra Kurzform. Dein C-Buch hat noch viele 
Seiten mehr über diesen Umstand und die Zusammenhänge zu berichten.
Was? Du hast kein C-Buch?  - Selber schuld. Kauf dir eines.

von qwer (Gast)


Lesenswert?

Jop, einfach blamabel.
Arbeite seit langen mal wieder mit C und hab wohl den ein oder anderen 
Befehl aus den basics vergessen.

Danke

von Karl H. (kbuchegg)


Lesenswert?

Und nein.
Ein #define wird nicht 'übergeben'

Ein #define macht eine Textersetzung. Ob du da schreibst
USART_TRANSMIT(val);

oder ob du schreibst
USART_TRANSMIT("PF10301*25\r\n");

ist Jacke wie Hose, weil der Präprozessor sowieso aus der ersten Form 
durch die angeordnete Textersetzung die 2.te Form macht, ehe dann der 
C-Compiler zum Zug kommt.

Auch hier wieder: nachzulesen in jedem noch so grindigem C-Buch.

von Karl H. (kbuchegg)


Lesenswert?

qwer schrieb:
> Jop, einfach blamabel.

Allerdings.
Denn die Frage nach der Stringlänge stellt sich gar nicht
1
void USART_TRANSMIT_CHAR( char c )
2
{
3
  while ( !( UCSR0A & (1<<UDRE0)) )
4
    ;
5
  UDR0 = c;    
6
}
7
8
void USART_TRANSMIT(char* adr)
9
{
10
  while( *adr != '\0' )
11
    USART_TRANSMIT_CHAR( *adr++ );
12
}

So schreibt man das. Kein Mensch benötigt dazu die tatsächliche 
Stringlänge in Zahlenform.
Und als Nebeneffekt fällt dann auch noch eine Funktion ab, die einzelne 
Character ausgeben kann.

von spontan (Gast)


Lesenswert?

Warum sendest Du nicht adr[i] solange adr[i] nicht 0x00 ist? Wäre doch 
auch chick.

von Udo S. (urschmitt)


Lesenswert?

spontan schrieb:
> Warum sendest Du nicht adr[i] solange adr[i] nicht 0x00 ist?

Weil man dann völlig unnötigerweise zusätzlich eine Variable i bräuchte
-> Mehr Ramverbrauch
-> Code komplexer weil zusätzliche Variable
-> Der Code (zumindest unoptimiert) langsamer ist, weil immer die 
Adresse aus dem Pointer und der Variable i berechnet werden muss

von Hanno (Gast)


Lesenswert?

Hallo,

ich habe ein ähnliches Problem. Mit dem Unterschied, dass ich gerne 
mehrere Byte empfangen würde.

Hätte es so probiert:
1
unsigned char USART1_RECEIVE()
2
{
3
  UDR1 = 0xFF;
4
  int i=0;
5
  
6
  while( *UDR1 != '\0' )
7
    
8
    {
9
      while ( !(UCSR1A & (1<<RXC1)) )
10
      {;}
11
      BUFFER[i]=UDR1;
12
      i++;
13
    }
14
  
15
  return BUFFER;
16
  
17
}

Leider kommt folgende Fehlermeldung und ich weiß nicht mehr weiter

Error  1  invalid type argument of unary '*' (have 'int')
Warning  2  return makes integer from pointer without a cast [enabled by 
default]

Grüße

von Hanno (Gast)


Lesenswert?

1
unsigned char BUFFER[128]

von Peter II (Gast)


Lesenswert?

Hanno schrieb:
> Leider kommt folgende Fehlermeldung und ich weiß nicht mehr weiter

wo ist denn BUFFER deklariert?

auserdem darst du UDR1 nicht 2mal auslesen. (ja auch ein vergleich ist 
ein auslesen!)

von Hanno (Gast)


Lesenswert?

Dann so?
1
unsigned char USART1_RECEIVE()
2
{
3
  BUFFER = 0xFF;
4
5
  while( *BUFFER != '\0' )
6
  BUFFER=UDR1;    
7
    {
8
      while ( !(UCSR1A & (1<<RXC1)) )
9
      {;}
10
      BUFFER++;
11
    }
12
13
  return BUFFER;
14
  
15
}

von Peter II (Gast)


Lesenswert?

Hanno schrieb:
> Dann so?
> unsigned char USART1_RECEIVE()

nein, die ließt ohne zu warten das erste zeichen ein.

warum nicht so?


[c]
do {
  while ( !(UCSR1A & (1<<RXC1)) );

  BUFFER=UDR1;
  if ( BUFFER == 0 ) {
     break;
  }
  BUFFER++;
} while( auf maximal länge prüfen! )

  return BUFFER;

von Peter II (Gast)


Lesenswert?

Nachtrag:

1
char* pos = BUFFER;
2
do {
3
  while ( !(UCSR1A & (1<<RXC1)) );
4
5
  pos = UDR1;
6
  if ( BUFFER == 0 ) {
7
     break;
8
  }
9
  pos++;
10
} while( auf maximal länge prüfen! )
11
12
  return BUFFER;

aber sauber ist das noch lange nicht, denn es macht wenig sinn eine 
globale variable als return zu übergeben. Besser ist es der funktion 
selber buffer als Paramter zu übergeben und auch die maximale länge.

von Karl H. (kbuchegg)


Lesenswert?

Hanno schrieb:
> Dann so?

schon ein bischen besser

> unsigned char USART1_RECEIVE()
> {
>   BUFFER = 0xFF;

warum willst du da BUFFER etwas zuweisen? Und vor allen Dingen: warum 
0xFF;
Du hast doch noch gar kein Zeichen, welches du im Buffer speichern 
könntest.

Ausserdem ist BUFFER ein Array. D.h. es besteht (bei dir) aus 128 
einzelnen Variablen, die alle denselben Namen tragen, nämlich Buffer, 
und nur durch den Arrayindex unterschieden werden.

Welche dieser 128 'Variablen' ist denn gemeint, wenn du einfach nur 
BUFFER schreibst?

>   while( *BUFFER != '\0' )

Das ist zwar im C-Sinne nicht ganz falsch, aber ich bin recht sicher, 
dass es nicht das ist was du haben willst. (Soll heissen: syntaktisch 
ist das korrekt. Aber laut Duden ist "Das U-Boot frisiert das Mondlicht" 
auch korrektes Deutsch. Selbst wenn der Satz keinen Sinn ergibt)

Wieder: BUFFER, das sind 128 Variablen!

Ausserdem: wie kannst du denn prüfen, ob BUFFER (egal welches) den Wert 
\0 hat? Einer der 128 BUFFER Variablen wurde ja noch gar nichts 
zugewiesen!

>   BUFFER=UDR1;

BUFFER ist ein Array!

>     {
>       while ( !(UCSR1A & (1<<RXC1)) )
>       {;}

Öhm.
Diese Schleife hier wartet darauf, dass ein Zeichen an der UART 
hereinkommt. D.h. du hast hier die Reihenfolge genau verkehrt rum

Du musst ZUERST darauf warten, dass du ein Zeichen bekommst, und erst 
DANN kannst du dir dieses Zeichen aus UDR1 abholen.

>       BUFFER++;

BUffer ist ein Array. Das kannst du nicht inkrementieren!

von Karl H. (kbuchegg)


Lesenswert?

@Peter II


Bitte beachten:
Laut Hanno
1
unsigned char BUFFER[128]


erspar ihm noch Pointer-Syntax. Er hat mit grundlegenden Konzepten und 
Array-Indizierung noch genug zu kämpfen.

von Peter II (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> erspar ihm noch Pointer-Syntax. Er hat mit grundlegenden Konzepten und
> Array-Indizierung noch genug zu kämpfen.

die hat er doch selber vorgeschlagen.

von Hanno (Gast)


Lesenswert?

1
unsigned char USART1_RECEIVE()
2
{
3
  int i=0;
4
  while ( !(UCSR1A & (1<<RXC1)) )      /* Warte auf Daten am RX */
5
    {
6
      while( *UDR1 != '\0' )      /* Prüfe ob Ende des Strings erreicht */
7
      {;}
8
      if(i>128){break;}        /*Pufferüberlauf vorbeugen*/
9
      BUFFER[i]=UDR1;          /*Daten im Puffer ablegen*/
10
      i++;              
11
    }
12
13
  //return BUFFER;  Muss ich ja nicht returnen, weil ich so drauf zugreifen kann oder?
14
}
15
  
16
}

So müssts dann passen oder?

von Hanno (Gast)


Lesenswert?

Mir fällt gerade ein, ich wollte ja mehrere Bytes einlesen können.

So wie grad geschrieben geht das ja nicht.

Ich lese jetzt ein, solange der Buffer nicht voll ist und solange kein 
'\0' empfangen wurde. Hoffe ich jedenfalls.
1
/* Es werden solange Bytes eingelesen, bis '\0' empfangen wurde*/
2
3
4
unsigned char USART1_RECEIVE()
5
{
6
  int i=0;
7
  BUFFER[0]=1;
8
  while( BUFFER[i] != '\0' && i<128)        /* Prüfe ob Ende des Strings erreicht */  /*Pufferüberlauf vorbeugen*/
9
  {
10
      while ( !(UCSR1A & (1<<RXC1)) )      /* Warte auf Daten am RX */
11
      {;}
12
      BUFFER[i]=UDR1;              /*Daten im Puffer ablegen*/
13
      i++;
14
  }
15
}

von Peter II (Gast)


Lesenswert?

Hanno schrieb:
> So wie grad geschrieben geht das ja nicht.

aber so auch nicht. Was soll die Zuweisung mit 1? Das machst du doch nur 
wegen dem while.

Verwende doch mal eine do .. while schleife. Damit geht es besser.

und ein return solltest du auch reinscheiben.

von Hanno (Gast)


Lesenswert?

aber jetzt
1
/* Es werden solange Bytes eingelesen, bis '\0' empfangen wurde*/
2
3
4
unsigned char USART1_RECEIVE()
5
{
6
  int i=0;                  /*Laufvariable initialisieren*/
7
  do 
8
  {      
9
    while ( !(UCSR1A & (1<<RXC1)) )      /* Warte auf Daten am RX */
10
    {;}
11
    BUFFER[i]=UDR1;              /*Daten im Puffer ablegen*/
12
    i++;                  /*Laufvariable inkrementieren*/
13
  }  while (BUFFER[i] != '\0' && i<128);    /* Prüfe ob Ende des Strings erreicht */  /*Pufferüberlauf vorbeugen*/
14
  
15
  return *BUFFER;    
16
}

von Peter II (Gast)


Lesenswert?

Hanno schrieb:
> aber jetzt

leider nicht.

> i++;
> }  while (BUFFER[i] != '\0' && i<128);

wenn du i++ machst, dann vergleichst du die falsche stelle im buffer.

> return *BUFFER;
was macht es für einen sinn EIN zeichen aus den Buffer zurückzugeben?

von Hanno (Gast)


Lesenswert?

Peter II schrieb:
> was macht es für einen sinn EIN zeichen aus den Buffer zurückzugeben?

Wie gebe ich den ganzen Vektor zurück?

von Peter II (Gast)


Lesenswert?

Hanno schrieb:
> Wie gebe ich den ganzen Vektor zurück?

warum verwendest du überhaupt ein unsigned char und kein char?
1
unsigned char* USART1_RECEIVE()
2
{
3
   return BUFFER;
4
}

Warum willst du überhaupt eine globale Variabel zurückgeben, diese 
kannst du eh von überall aus nutzen?

von Hanno (Gast)


Lesenswert?

Peter II schrieb:
> und ein return solltest du auch reinscheiben.

Also nur return ohne Buffer o.ä.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Karl Heinz Buchegger schrieb:
>> erspar ihm noch Pointer-Syntax. Er hat mit grundlegenden Konzepten und
>> Array-Indizierung noch genug zu kämpfen.
>
> die hat er doch selber vorgeschlagen.

Ich glaube nicht, dass er weiß was er tut. Schau dir an, was er da so 
redebrechtet.

von Karl H. (kbuchegg)


Lesenswert?

Hanno schrieb:
> Peter II schrieb:
>> und ein return solltest du auch reinscheiben.
>
> Also nur return ohne Buffer o.ä.

Den man dann in diesem Fall einfach weglassen kann.
Der Returntyp für main reduziert sich dann ebenfalls auf void.

von Karl H. (kbuchegg)


Lesenswert?

1
char USART1_get_char()
2
{
3
  while ( !(UCSR1A & (1<<RXC1)) )
4
  {;}
5
6
  return UDR1;
7
}
8
9
void USART1_get_string()
10
{
11
  uint8_t i=0;
12
  char c;
13
14
  do 
15
  {      
16
    c = USART1_get_char();
17
    BUFFER[i] = c;
18
    i++;
19
  }  while ( c != '\0' && i < sizeof(BUFFER));
20
21
  BUFFER[i-1] = '\0'; // sicherheitshalber, falls des Empfangene zu lang ist
22
}


(Deine Kommentare hab ich rausgeworfen, weil es sich um sinnlose 
Kommentare handelt. Ein Kommentar, der nur den C-Code in deutscher 
Schreibweise wiedergibt, ist sinnlos. Die Funktionen sind so kurz und so 
leicht zu durchschauen - da ist der Code sein eigener Kommentar)
Der Code erzählt mir das WIE, ein Kommentar erzählt mir das WARUM.

PS: Bist du sicher, dass der Sender einen String mit einem \0 zeichen 
abschliesst und das dann auch so über die UART schickt? Es ist zwar 
grundsätzlich möglich, aber reichlich ungewöhnlich.

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.