Forum: Mikrocontroller und Digitale Elektronik Uart sendet falsches steuerzeichen


von Wassmer M. (Firma: keine) (weassi)


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):
1
 
2
#include <avr\io.h>
3
#include <stdlib.h>
4
#include <math.h>            // Most basic include files Add the necessary ones
5
#include <avr\signal.h>
6
#include <String.h>         // here
7
#include "uart1.h"
8
9
#ifndef F_CPU
10
#define F_CPU 4000000UL
11
#endif
12
13
/* 9600 baud */
14
#define BAUDRATE 9600UL //Definition als unsigned long, sonst gibt es Fehler in der Berechnung
15
#define CR "\r\n"
16
17
int main(void)
18
 {
19
   int adcval;
20
   int cordx ;
21
   int cordy;
22
   double winkel= 30;
23
   winkel= winkel* M_PI/180 ;
24
    uart_init();
25
    adcval = ReadChannel(0);
26
     cordx = make_cordx(adcval, winkel);
27
     cordy = make_cordy(adcval, winkel);
28
     punkt_machen(cordx, cordy);
29
;
30
31
    return 0;
32
33
}
34
35
void uart_init()
36
{
37
    uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16*BAUDRATE) - 1);
38
39
    UBRRH = (uint8_t) (ubrr>>8);
40
    UBRRL = (uint8_t) (ubrr);
41
42
    // UART Receiver und Transmitter anschalten
43
    // Data mode 8N1, asynchron
44
    UCSRB = (1 << RXEN) | (1 << TXEN);
45
    UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
46
47
    // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
48
    do
49
    {
50
        UDR;
51
    }
52
    while (UCSRA & (1 << RXC));
53
}
54
55
56
void uart_puts (const char *s)
57
{
58
    do
59
    {
60
        uart_putc (*s);
61
    }
62
    while (*s++);
63
}
64
65
char make_cordx(int wert, double angle)
66
{
67
  int xcord ;
68
  xcord = wert/16 ;
69
  angle = cos(angle);
70
  xcord = xcord*angle ;
71
  xcord += 119 ;
72
73
   return xcord;
74
  }
75
76
char make_cordy(int wert, double angle)
77
{
78
  int ycord;
79
  ycord = wert/16 ;
80
  angle = sin(angle);
81
  ycord = ycord*angle ;
82
  ycord += 63 ;
83
84
   return ycord;
85
  }
86
87
void punkt_machen(int x, int y)
88
{
89
   char text[3];
90
   uart_puts (0x11);
91
     uart_puts ("2");
92
     uart_puts ("#gp");
93
     itoa(x, text, 10) ;
94
     uart_puts (text);
95
     itoa(y, text, 10) ;
96
    uart_puts (text);
97
    return;
98
    }

von holger (Gast)


Lesenswert?

uart_puts (0x11);

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

von Karl H. (kbuchegg)


Lesenswert?

holger hat schon einen Fehler.

Hier ist der nächste
1
void uart_puts (const char *s)
2
{
3
    do
4
    {
5
        uart_putc (*s);
6
    }
7
    while (*s++);
8
}

anders rum
1
void uart_puts (const char *s)
2
{
3
    while( *s )
4
    {
5
        uart_putc (*s++);
6
    }
7
}

und das nächste Problem
1
void punkt_machen(int x, int y)
2
{
3
   char text[3];
4
   uart_puts (0x11);
5
     uart_puts ("2");
6
     uart_puts ("#gp");
7
     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.

von Wassmer M. (Firma: keine) (weassi)


Lesenswert?

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

zu diesm part:
1
 void uart_puts (const char *s)
2
{
3
    do
4
    {
5
        uart_putc (*s);
6
    }
7
    while (*s++);
8
}

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:
1
void punkt_machen(int x, int y)
2
{
3
   char text[3];
4
   uart_puts (0x11); // neu: uart_putc(0x11)
5
     uart_puts ("2");
6
     uart_puts ("#gp");
7
     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.

von holger (Gast)


Lesenswert?

>text[3] also effektiv drei zeichen lang.

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

von holger (Gast)


Lesenswert?

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

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

von Stefan E. (sternst)


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.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Wassmer Marco schrieb:
>
1
 void uart_puts (const char *s)
2
> {
3
>     do
4
>     {
5
>         uart_putc (*s);
6
>     }
7
>     while (*s++);
8
> }

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.

von Karl H. (kbuchegg)


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)

von Ber (Gast)


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

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.