www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Uart sendet falsches steuerzeichen


Autor: Wassmer Marco (Firma: keine) (weassi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

ich hab da ein problemchen, und zwar giebt mein uart erst mist aus, dann 
aber stimmts, also muss es am code liegen. Ich und mein c- mentor finden 
aber keinen, vielleicht kann mir ja einer von euch spezialisten helfen.
Ich probiere ein steuerzeichen zu senden, die Schnittstelle giebt aber 
nur [ACK][ACK], also [$06] [$06],aus.
als IDE benutze ich VMLAB, gut zum simulieren.
Das ganze soll einfach einen string an ein TP EA eDIP240 senden
clock und baudrate stimmt

relevanter code (nicht komplett):
 
#include <avr\io.h>
#include <stdlib.h>
#include <math.h>            // Most basic include files Add the necessary ones
#include <avr\signal.h>
#include <String.h>         // here
#include "uart1.h"

#ifndef F_CPU
#define F_CPU 4000000UL
#endif

/* 9600 baud */
#define BAUDRATE 9600UL //Definition als unsigned long, sonst gibt es Fehler in der Berechnung
#define CR "\r\n"

int main(void)
 {
   int adcval;
   int cordx ;
   int cordy;
   double winkel= 30;
   winkel= winkel* M_PI/180 ;
    uart_init();
    adcval = ReadChannel(0);
     cordx = make_cordx(adcval, winkel);
     cordy = make_cordy(adcval, winkel);
     punkt_machen(cordx, cordy);
;

    return 0;

}

void uart_init()
{
    uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*BAUDRATE) - 1);

    UBRRH = (uint8_t) (ubrr>>8);
    UBRRL = (uint8_t) (ubrr);

    // UART Receiver und Transmitter anschalten
    // Data mode 8N1, asynchron
    UCSRB = (1 << RXEN) | (1 << TXEN);
    UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);

    // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
    do
    {
        UDR;
    }
    while (UCSRA & (1 << RXC));
}


void uart_puts (const char *s)
{
    do
    {
        uart_putc (*s);
    }
    while (*s++);
}

char make_cordx(int wert, double angle)
{
  int xcord ;
  xcord = wert/16 ;
  angle = cos(angle);
  xcord = xcord*angle ;
  xcord += 119 ;

   return xcord;
  }

char make_cordy(int wert, double angle)
{
  int ycord;
  ycord = wert/16 ;
  angle = sin(angle);
  ycord = ycord*angle ;
  ycord += 63 ;

   return ycord;
  }

void punkt_machen(int x, int y)
{
   char text[3];
   uart_puts (0x11);
     uart_puts ("2");
     uart_puts ("#gp");
     itoa(x, text, 10) ;
     uart_puts (text);
     itoa(y, text, 10) ;
    uart_puts (text);
    return;
    }


Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uart_puts (0x11);

0x11 ist kein String! Veruchs mal mit uart_putc(0x11);

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger hat schon einen Fehler.

Hier ist der nächste
void uart_puts (const char *s)
{
    do
    {
        uart_putc (*s);
    }
    while (*s++);
}

anders rum
void uart_puts (const char *s)
{
    while( *s )
    {
        uart_putc (*s++);
    }
}

und das nächste Problem
void punkt_machen(int x, int y)
{
   char text[3];
   uart_puts (0x11);
     uart_puts ("2");
     uart_puts ("#gp");
     itoa(x, text, 10) ;

das nenn ich mutig, davon auszugehen, dass die Textrepräsentierung von 
sowohl x als auch y einen maximalen String mit 2 Zeichen ergibt. Vor 
allen Dingen da hier

  xcord += 119 ;

die berechnete x Koordinate für positive xcord schon mal kräftig 
angehoben wird.

Du solltest deinen C-Mentor wechseln, wenn er solche Sachen nicht sieht.

Autor: Wassmer Marco (Firma: keine) (weassi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen danke für die korekturen, display und uc verstehen sich jetzt, 
mehr oder weniger.

zu diesm part:
 void uart_puts (const char *s)
{
    do
    {
        uart_putc (*s);
    }
    while (*s++);
}

ich verstehe den fehler nicht ganz, das ist doch eine do-schleife, die 
das gleich macht wie ne while-schleife ausser das sie min. einmal 
durchläuft, insofern sinnvoll da eigntlich wenn die funktion aufgerufen 
wird i.d.R. auch etwas gesendet werden will.

zu dem part:
void punkt_machen(int x, int y)
{
   char text[3];
   uart_puts (0x11); // neu: uart_putc(0x11)
     uart_puts ("2");
     uart_puts ("#gp");
     itoa(x, text, 10) ;

mmh.. ein berechtigter einwand...
aber irgendwo hab ich glelesen das C ja keine strings kennt, sondern nur 
char-arrays, sprich die variabel text[3] ist nicht null terminiert, also 
effektiv drei zeichen lang.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>text[3] also effektiv drei zeichen lang.

Nö, zwei Zeichen mit /0 am Ende.
Für drei Zeichen brauchst du text[4].

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nö, zwei Zeichen mit /0 am Ende.

\0 natürlich :( Oder einfach ne Null.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wassmer Marco schrieb:

> ich verstehe den fehler nicht ganz, das ist doch eine do-schleife, die
> das gleich macht wie ne while-schleife ausser das sie min. einmal
> durchläuft, insofern sinnvoll da eigntlich wenn die funktion aufgerufen
> wird i.d.R. auch etwas gesendet werden will.

"i.d.R." ist aber nicht das gleiche wie "garantiert immer". Was ist, 
wenn die Funktion doch mal mit einem leeren String aufgerufen wird? 
Möchtest du, dass dann eine Null gesendet wird?

> mmh.. ein berechtigter einwand...
> aber irgendwo hab ich glelesen das C ja keine strings kennt, sondern nur
> char-arrays, sprich die variabel text[3] ist nicht null terminiert, also
> effektiv drei zeichen lang.

Die Variable text ist natürlich nicht "von Natur aus" null-terminiert. 
Aber itoa erzeugt eine Null-Terminierung (ansonsten würde ja auch das 
folgende "uart_puts (text)" gar nicht funktionieren), also muss in text 
auch Platz für diese Terminierung sein.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wassmer Marco schrieb:
>
 void uart_puts (const char *s)
> {
>     do
>     {
>         uart_putc (*s);
>     }
>     while (*s++);
> }

Eine C-Zeichenkette (Beispiel "test") ist immer nullterminiert, 
benötigt also immer 5 Bytes.

Wenn s also ein Zeiger auf dieses "test" ist, passiert folgendes:

1. uart_putc (*s)
   *s dereferenziert den Zeiger und ergibt das Byte 't'. Dieses wird 
ausgegeben.
2. while (*s++);
   Die Schleife wird ab "do" wiederholt, wenn das Zeichen an *s (also 
das 't') nicht 0 ist. Nach diesem Vergleich und vor dem Sprung nach "do" 
wird s noch um eine Speicherposition erhöt.
3. uart_putc (*s)
   Jetzt wird das 'e' gesendet.
4. ....
5. while (*s++);
   Es wird auf 't' (das letzte in "test") geprüft. Es ist wieder nicht 
null, also weiter bei "do".
6. uart_putc (*s);
   Jetzt kommt das Problem. s zeigt jetzt auf das Byte nach "test", und 
zwar auf die Nullterminierung. Diese Null wird gesendet.
7. while (*s++);
   Jetzt trifft die Bedingung "Zeichen an Zeigerposition s nicht null" 
nicht mehr zu, die Schleife ist beendet.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger schrieb:
>>text[3] also effektiv drei zeichen lang.
>
> Nö, zwei Zeichen mit /0 am Ende.
> Für drei Zeichen brauchst du text[4].

@Marco
Wobei es an solchen Stellen praktisch IMMER kontraproduktiv ist, zu 
knausrig zu sein. Irgendwann wird deine Zahl nämlich größer und sei es 
nur weil beim testen nicht alles auf Anhieb funktioniert.

Wenn du das Array in dieser Funktion größer machst, dann kostet dir das 
praktisch nichts, kann dich aber zumindest am Anfang vor seltsamen 
Problemen bewahren. Ein int kann per Definition auf deinem µC von -32768 
bis 32767 gehen. Das macht maximal 6 Zeichen, dazu noch die obligate 
'\0'-Terminierung macht 7 Positionen. Darauf würde ich das auslegen 
(oder der Einfachheit halber gleich mal 10 nehmen)

Autor: Ber (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Darauf würde ich das auslegen (oder der Einfachheit halber gleich mal 10 >nehmen)

FULL ACK!!

"Speichersparen" kann man dann wenn man fertig ist, vorher (wie Karl 
heinz schon geschrieben hat) machts speziell für Anfänger nicht viel 
Sinn.

mfg
Ber

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.