Forum: Mikrocontroller und Digitale Elektronik UART legt Controller lahm


von Roland N. (eroli)


Lesenswert?

Hallo zusammen,

im Rahmen meines Projektes bin ich gerade auf ein neues Problem 
gestoßen. Mein MSP430 hört auf dem CAN-Bus mit, was alles so gesendet 
wird. Dabei achtet er auf ungefähr eine handvoll CAN-Botschaften 
identifiziert durch die entsprechende ID. Die IDs werden dabei von einer 
SD Karte gelesen und sind im aktuellen Fall Fünf an der Anzahl.

Der Controller soll nun den Bus abhören und Alarm schlagen, sobald eine 
ID innerhalb einer Sekunde nicht empfangen worden ist (fast alle 
Botschaften werden dabei alle 40ms gesendet).
Gerade wollte ich eine Ausgabe implementieren, welche einige Messwerte 
per UART über USB an den Computer sendet (Das Board wird als USB Serial 
Converter am PC erkannt).

Gesagt, getan und es funktioniert. Allerdings wird das Board dadurch 
scheinbar so stark belastet, dass meine Menüführung quasi gar nicht mehr 
möglich ist (Software-Debouncing in while-Schleife in der main).

Kann das sein? Ist das Senden via UART so anspruchsvoll? Oder sind es 
eher meine String-Operationen (1x strcpy, 8x strcat, 1x itoh, 1xitoa, 2x 
ftoa, Routinen aus numtostr-Paket hier aus dem Forum: 
Beitrag "C-Umwandlungsfunktionen für double/int/long nach String"), die zuviel Rechenzeit 
benötigen?
Eine Nachricht sieht zum Beispiel so aus:
"Fehlende CAN-Nachricht: ID: 0x123; Temp: 12.123; Hum: 12.123, Spannung: 
0\r\n"

Im Moment ist der CAN-Bus abgeklemmt und das Board soll auf 5 
Nachrichten reagieren. Demnach wird die obige Nachricht 5mal pro Sekunde 
(mit unterschiedlichen IDs) gesendet.

Was meint ihr? Woran wird es am wahrscheinlichsten liegen?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Roland M. (eroli)

>Gesagt, getan und es funktioniert. Allerdings wird das Board dadurch
>scheinbar so stark belastet, dass meine Menüführung quasi gar nicht mehr
>möglich ist (Software-Debouncing in while-Schleife in der main).

Aua! Das macht man mit einem TIMER! Siehe Entprellung

>Kann das sein? Ist das Senden via UART so anspruchsvoll? Oder sind es

Nein.

>Was meint ihr? Woran wird es am wahrscheinlichsten liegen?

An deiner unpassenden Programmierung.

von Jim M. (turboj)


Lesenswert?

Das kommt darauf an (tm). Ohne Blick auf den Sourcecode wird man keine 
vernünftige Aussage treffen können.

von Roland N. (eroli)


Lesenswert?

Sorry für den Doppelpost, aber ich habe gerade mal probiert alle 
Umwandlungen (itoh, itoa und ftoa) auszukommentieren und dann 
funktioniert es wunderbar. Auch mit itoh und itoa läuft es gut. 
Scheinbar braucht die ftoa-Funktion sehr viel Rechenzeit. Diese sieht 
bei mir so aus
1
void ftoa(char * buf, double f, char d, char pad, char padchar)
2
{
3
  char * p;
4
  const double powers[] = {1.0,10.0,100.0,1000.0,10000.0,100000.0};
5
6
  /* round */
7
  f = f>=0.0 ? (f*powers[d]+0.5)/powers[d] : (f*powers[d]-0.5)/powers[d];
8
9
  /* special case */
10
  if (f<0.0 && f > -1.0) {
11
    p = ltoa(buf,-1,pad,padchar);
12
    *(p-1) = '0';
13
  }
14
  else
15
    p = ltoa(buf,f,pad,padchar);
16
17
  *p++ = '.';
18
19
  if (f<0.0)
20
    f = -f;
21
  
22
  f -= (long) f;
23
  f *= powers[d];
24
  ltoa(p,(long)f,d,0);
25
}
26
27
char * ltoa(char * buf, long val, char pad, char padchar)
28
{
29
  char i;
30
  char neg = 0;
31
  char tmp_buf[21];
32
33
  if(val<0) {
34
    val = -val;
35
    neg = 1;
36
  }
37
38
  for(i=0; val>0; val/=10)
39
    tmp_buf[i++] = (val % 10) + '0';
40
41
  if(i==0)
42
    tmp_buf[i++] = '0';
43
44
  if(neg) {
45
    if(padchar) {
46
      tmp_buf[i++] = '-';
47
      while(i<pad)
48
        tmp_buf[i++] = ' ';
49
    }
50
    else {
51
      while(i<pad-1)
52
        tmp_buf[i++] = '0';
53
      tmp_buf[i++] = '-';
54
    }
55
  }
56
  else
57
    while(i<pad)
58
      tmp_buf[i++] = padchar ? ' ' : '0';
59
60
  while(i>0)
61
    *buf++ = tmp_buf[--i];
62
63
  *buf = 0;
64
65
  return buf;
66
}

Gibt es da vielleicht effizientere Wege?

@ Falk Brunner: Sicher ist das per Timer eleganter, aber das ist hier an 
dieser Stelle nicht das Problem. Dennoch werde ich das wohl auf einen 
neuen Timer umstellen. Danke für den Hinweis.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Roland M. schrieb:

> eher meine String-Operationen (1x strcpy, 8x strcat, 1x itoh, 1xitoa, 2x
> ftoa,

Da kommt allerdings dann schon einiges zusammen.

> "Fehlende CAN-Nachricht: ID: 0x123; Temp: 12.123; Hum: 12.123, Spannung:
> 0\r\n"

Muss das wirklich so geschwätzig sein?
Je nach Baudrate, dauert eine Übertragung dann schon seine Zeit. Und 
auch (speziell bei Floating Point) die Aufbereitung von Werten in eine 
ASCII Repräsentierung kriegt man nicht gratis.

Klar ist mir zb nicht, wozu du die ganzen strcpy und strcat brauchst.

Am Terminal kannst du sowieso nicht unterscheiden, ob das Programm 
zuerst ala
1
  strcpy( buffer, "Hallo " );
2
  strcat( buffer, "World!\n" );
3
4
  uart_string( buffer );
den Text zuerst in einen String zusammengebaut hat, oder ob du mittels
1
  uart_string( "Hallo " );
2
  uart_string( "World!\n" );
2 String-Übertragungen hattest. Der einzige Unterschied: du belastest 
deinen µC mit einem zusätzlichen Buffer, in dem erst mal alles 20 mal 
umkopiert werden muss, ehe es dann tatsächlich per UART auf die Reise 
geht.

: Bearbeitet durch User
von Roland N. (eroli)


Lesenswert?

Hallo Karl Heinz,

du hast natürlich Recht... Da habe ich gar nicht drüber nachgedacht. Ich 
habe es nun wie du vorgeschlagen hast abgeändert und die einzelnen 
Konvertierungsergebnisse direkt an den UART zum Senden übergeben. Es ist 
ein wenig besser, aber es braucht immer noch tierisch lange.

Ich denke das wesentliche Problem hierbei ist die ftoa-Geschichte...

Baudrate ist übrigens 38400. Zuerst war ich bei 9600 und dachte das 
Problem mit einer Erhöhung entschärfen zu können. Hat aber zu keiner 
merklichen Verbesserung beigetragen...

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Roland M. (eroli)

>Umwandlungen (itoh, itoa und ftoa) auszukommentieren und dann
>funktioniert es wunderbar. Auch mit itoh und itoa läuft es gut.

Das ist ja schon mal ein wichtiger Hinweis.

>Scheinbar braucht die ftoa-Funktion sehr viel Rechenzeit. Diese sieht
>bei mir so aus

Wozu postest du denn Quelltext? Das sind doch normalerweise Funktionen, 
die in deiner Compilerbilbiothek mit drinstecken. Wahrscheinlich auch 
deutlich besser optimiert. Möglicherweise musst du die (optimierte) 
Bibliothek zu deinem Code linken, damit die (langsamen) 
Standardfunktionen ersetzt werden. Beim avr gcc ist das jedenfalls so.

von Karl H. (kbuchegg)


Lesenswert?

Roland M. schrieb:

> Ich denke das wesentliche Problem hierbei ist die ftoa-Geschichte...

Flaoating Point ist für einen µC ohne FPU schon recht aufwändig. 
Brauchst du wirklich die Temperatur auf 2 Nachkommastellen. Und: wenn 
ja, brauchst du sie wirklich in der Form 89.50 oder reicht dir zum 
Debuggen nicht auch ein 8950 und du weißt ganz einfach, dass zwischen 
Zeher und Hunderter ein Dezimalpunkt rein muss.
Das könnte zb auch ein Programm mit viel weniger Aufwand erledigen. 
Funktionen werden meistens umfangreicher und aufwändiger, wenn sie so 
allgemein wie möglich sein müssen. Braucht man diese Allgemeingültigkeit 
nichtm, dann vereinfacht sich vieles.
Eine Ausgabe, die einen 16 Bit int immer in ein Feld der Größe 7 Zeichen 
(inkl. abschliessendes 0-Byte) reinschreibt und zwar immer mit führenden 
0-en, ist ein trivial und wird kaum länger als ein paar Zeilen. 
Verglichen mit deinem Monster für ltoa ist das schon recht heftig.

Nicht aus den Augen lassen, solltest du aber die Baudrate. Bei zb 9600 
Baud, kriegst du gerade mal ca. 1000 Zeichen pro Sekunde rüber. D.h. pro 
Zeichen dauert die Übertragung 1ms. Der Unterschied zwischen
"Fehlende CAN-Nachricht: ID: 0x123; Temp: 12.123; Hum: 12.123, Spannung: 
0\r\n"
und
"miss ID 123; T 12 H 12 V 0\r\"
siond alleine aus dem Grund schon mal 46ms bei 9600 Baud. Und das nur 
dadurch, dass dein Programm nicht so geschwätzig ist.

: Bearbeitet durch User
von Roland N. (eroli)


Lesenswert?

Hallo zusammen,

da ich wirklich nicht gedacht hätte, dass die Konvertierung einer 
float-Variablen in einen String so anspruchsvoll ist, habe ich mich dazu 
entschieden die Variable auf einen int zu casten und dann mittels itoa 
zu konvertieren.

Die vielen strcat-Funktionen habe ich quasi durch meine 
UART_Transmit-Funktion ersetzt, sodass auch der große Buffer wegfällt. 
Jetzt läuft es für mich akzeptabel schnell.

Vielen Dank für eure Erfahrungen ;-)

EDIT: Übrigens gibt es in der stdlib vom MSPGCC keine ftoa-Funktionen 
und dergleichen ;-) Daher hatte ich weiter oben das Quelltext-Monster 
gepostet ;-)

: Bearbeitet durch User
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.