Forum: Mikrocontroller und Digitale Elektronik strings übergeben


von Timo P. (latissimo)


Lesenswert?

hallo!
ich habe vor, strings via uart zu versenden. Dazu habe ich eine fkt.
void uputs(char *s)
diese befüllt ein Array protocol, welches in der TX-ISR verwurstet wird.

der Aufruf: uputs("Test\r\n"); funktioniert super!
der Aufruf: uputs(buffer); funktioniert net es werden nur best. teile 
gesendet
buffer ist: sprintf(buffer,"asldkfj %4d \r\n",9999); wobei buffer[40]

1
void uputs( char *s )
2
{
3
  strcpy(protocol, s);
4
  while (*s)
5
  {
6
    ready = 0;
7
    IE2 |= UCA0TXIE;
8
    while(!ready);
9
  }
10
}
11
12
13
#pragma vector=USCIAB0TX_VECTOR
14
__interrupt void USCI0TX_ISR(void)
15
{  
16
    char temp;
17
    if(send_XPort) 
18
    {
19
      temp = protocol[i++];
20
      if(temp != '\0'); 
21
      UCA0TXBUF = temp;          // TX next character
22
    }
23
    if (temp == '\0')              // TX over?
24
    {
25
      i = 0;                      // Nach Stringende
26
      send_XPort = 0;
27
      ready = 1;          // beendet String-Sende-Fkt.
28
    }
29
}

von Zulu (Gast)


Lesenswert?

Ohne Worte!

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:
> hallo!
> ich habe vor, strings via uart zu versenden. Dazu habe ich eine fkt.
> void uputs(char *s)
> diese befüllt ein Array protocol, welches in der TX-ISR verwurstet wird.
>
> der Aufruf: uputs("Test\r\n"); funktioniert super!

Das glaub ich nicht.
Nicht mit der von dir geposteten uputs. Die landet unweigerlich in einer 
Endlosschleife.

von Timo P. (latissimo)


Lesenswert?

Danke Zulu für die herausragende Antwort!

von Zulu (Gast)


Lesenswert?

>Danke Zulu für die herausragende Antwort!
Danke auch Dir für diese humoristische Einlage. ;-)

von Karl H. (kbuchegg)


Lesenswert?

Wozu soll es gut sein, die einzelnen Character per Interrupt zu 
versenden, wenn deine uputs Funktion dann sowieso auf das Ende des 
Versendens wartet? (und nur mal angenommen, du hättest die 
Endlosschleife while (*s) bereinigt)

von Timo P. (latissimo)


Lesenswert?

weil ich s nicht inkrementiere?

von Timo P. (latissimo)


Lesenswert?

das versenden via interrupt geht. So ist das Timing ok.

Jetzt wollte ich nur für die handlebarkeit eine fkt haben, an die ich 
einen string übergebe, die sich dann kümmert. von mir aus auch unter 
zuhilfenahme einer interruptfunktion!

von Maik F. (sabuty) Benutzerseite


Lesenswert?

Timo P. schrieb:
> weil ich s nicht inkrementiere?

Das ist ja auch der Grund für die Endlosschleife :]

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:
> das versenden via interrupt geht. So ist das Timing ok.

Ja. Aber so wie du das geschrieben hast ist es sinnlos.
Ich kann auch von Wien nach Frankfurt über Helsinki fahren wenn ich 
will. Ich kann aber auch den einfachsten Weg nehmen.

> Jetzt wollte ich nur für die handlebarkeit eine fkt haben, an die ich
> einen string übergebe, die sich dann kümmert. von mir aus auch unter
> zuhilfenahme einer interruptfunktion!

Und warum muss die Funktion dann warten, bis der String rausgegeben 
wurde? Der Witz hinter dem Versenden eines Strings per Interrupt besteht 
ja gerade darin, dass der Aufrufer eben nicht darauf wartet, sondern 
weitermachen kann, während der String im Hintergrund rausgesendet wird.

von Timo P. (latissimo)


Lesenswert?

ok also ich könnte in meinem hauptprogramm:

- protocol[] füllen
- den interrupt aktivieren
- was anderes tun

und im interrupt:

- zeichen senden
- bei stringende den interrupt disablen.

von Karl H. (kbuchegg)


Lesenswert?

if(temp != '\0');
      UCA0TXBUF = temp;          // TX next character


Siehst du den kleinen ; am Zeilenende vom if?
Die gewünschte Funktionalität, nämlich dass ein Zeichen nur dann 
rausgeht, wenn es nicht '\0' ist, dürfte damit verloren gehen.

Auf der anderen Seite lässt die nicht vorhandene Einrückung vermuten, 
dass das sowieso nicht beabsichtigt war, wodurch allerdings die Abfrage 
sinnlos geworden ist. Wahrscheinlich wirft der Compiler sie raus.

von Peter (Gast)


Lesenswert?

das sieht mir hier auch nicht sehr sinnvoll aus

> if(temp != '\0');

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:
> ok also ich könnte in meinem hauptprogramm:
>
> - protocol[] füllen
> - den interrupt aktivieren
> - was anderes tun

Fast.
Die korrekte Version ist

- feststellen ob zufällig noch eine vorhergehende String-Versende
  Aktion im Gange ist und auf deren Abschluss warten

- protocoll[] füllen, wobei es sinnvoll ist zu überprüfen, ob der
  zu sendende String da überhaupt hineinpassen wird.
  Ein strcpy mit einem unbekannten String in ein Zielarray ist
  eine Harakiri-Aktion

- den Interrupt aktivieren
  entweder in dem man das Interrupt Flag setzt, oder einfach das erste
  Zeichen an die USART übergibt. Letzteres ist gebräuchlicher, da man
  dann in der Sendefunktion kein Wissen über irgendwelche Sende-
  Interrupt Flags benötigt

- aus der Funktion returnen

>
> und im interrupt:
>
> - zeichen senden
> - bei stringende den interrupt disablen.

und auf jeden Fall, den index des nächsten zu sendenden Zeichens nicht i 
nennen. i kann alles Mögliche sein. Peinliche Verwechslungen sind 
vorprogrammiert, wenn man wichtige globale Variablen i, j, k nennt.

von Timo P. (latissimo)


Lesenswert?

warum sich das semikolon dahingeschlichen hat ist mir auch ein rätzel..

klärt aber immenoch nicht, warum die überhabe "sdflk" gegenüber der 
übergabe:
(arrayname) funktioniert

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:
> warum sich das semikolon dahingeschlichen hat ist mir auch ein rätzel..
>
> klärt aber immenoch nicht, warum die überhabe "sdflk" gegenüber der
> übergabe:
> (arrayname) funktioniert

Das lässt sich auch mit dem Mikro-Code Schnipsel nicht erklären

von Timo P. (latissimo)


Lesenswert?

ausschluss einer "Harakiri funktion" werde ich per sizeof sicherstellen 
oder halt genug an zeichen reservieren, bisher habe ich keine 
speicherprob.

i durch zb. next_char zu ersetzen ist ja auch kein prob.


würde trotzdem gerne wissen, warum die verschiedenen aufrufe zu 
verschiedenen resultaten führen......

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:

> würde trotzdem gerne wissen, warum die verschiedenen aufrufe zu
> verschiedenen resultaten führen......

Weil wahrscheinlich wieder mal irgendetwas Schlimmes passiert, was 
ausserhalb des geposteten Source-Codes passiert.
1
volatile char protocol[80];
2
volatile signed char next_char = -1;
3
4
unsigned char uputs( const char *s )
5
{
6
  if( strlen( s ) > sizeof( protocol ) - 1 )
7
    return FALSE;
8
9
  while( next_char != -1 )
10
    ;
11
12
  strcpy( protocol, s );
13
  next_char = 0;
14
  IE2 |= UCA0TXIE;
15
16
  return TRUE;
17
}
18
19
#pragma vector=USCIAB0TX_VECTOR
20
__interrupt void USCI0TX_ISR(void)
21
{  
22
  char temp = protocol[ next_char ];
23
24
  if( temp == '\0' )
25
  {
26
    next_char = -1;
27
    return;
28
  }
29
30
  UCA0TXBUF = temp;
31
  next_char++;
32
}

Ob die Sache mit den Interrupts bzw. den Interrupt Flags so stimmt kann 
ich mangels Datenblatt bzw. Kentniss des Prozessors nicht sagen. Ich 
habe das einfach vom TO so übernommen.

von Timo P. (latissimo)


Lesenswert?

ok die idee von der leichteren handlebarkeit ist wieder über den haufen 
geworfen und es läuft wieder über den interrupt, muss jetzt halt die 
interruptflags setzen/löschen.

wie würde ich eine empfangs ISR aufbauen, die mir ein array füllt? wenn 
ich einen string empfangnen will, der eine gewisse länge hat, dann endet 
er irgenwann. wie stelle ich das in der empfangsroutine fest? kann ich 
dann den string(den ich in ein arry schiebe) per \0 beenden? nur wie 
stell ich fest, dass der empfangene string zu ende ist?

wird ja wohl ne andere lösung geben, als ein timeout oder?

von Timo P. (latissimo)


Angehängte Dateien:

Lesenswert?

wen es interessiert, hier die geänderte c-datei (ist auch nicht lang)

da habe ich per timer ein flag gesetzt, was zwischen protocolaufbau und 
protocolversenden unterscheidet.

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:
> ok die idee von der leichteren handlebarkeit ist wieder über den haufen
> geworfen

du gibst zu leicht auf :-)

von Timo P. (latissimo)


Lesenswert?

Karl heinz Buchegger schrieb:
> du gibst zu leicht auf :-)

widersprechen will ich da net. Aber ich habe auch immer das verlangen, 
Zeit zu sparen.

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:

> dann den string(den ich in ein arry schiebe) per \0 beenden? nur wie
> stell ich fest, dass der empfangene string zu ende ist?

Indem du mit dem Sender vereinbarst, was als 'String-Ende' Zeichen zu 
werten ist.
Üblich ist zb das das Zeichen '\n' einen Eingabestring beendet. Darum 
muss man auch in den meisten Commandline Interpreteren auf Return 
drücken, damit die eingegebene Zeichensequenz der Bearbeitung zugeführt 
wird. ZUvor ist es einfach nur eine nicht abgeschlossene Abfolge von 
Zeichen, die noch editiert werden kann. Danach ist es ein String, der 
vom Commandline Interpreter als String bearbeitet wird (meistens ohne 
das '\n')

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:
> Karl heinz Buchegger schrieb:
>> du gibst zu leicht auf :-)
>
> widersprechen will ich da net. Aber ich habe auch immer das verlangen,
> Zeit zu sparen.

:-)
Ist ganz einfach:
Mach es richtig, dann sparst du Zeit in der Entwicklung. Und eine 
saubere String-Sende Funktion sollte es einem eigentlich Wert sein, dass 
man da ein paar Stunden dafür opfert und auch ein paar Varianten 
durchprobiert, miteinander vergleicht und die Vor/Nachteile 
gegeneinander abwägt. Man kann damit nur lernen, welche Methoden 
funktionieren, welche nur fake sind, welche zwar auf den ersten Blick 
gut aussehen aber trotzdem Unsinn sind etc.
Beim nächsten mal ist nicht die String-Funktion sondern du musst ganze 
Datenbanken per UART übertragen. Da es dasselbe Grundprinzip ist, kannst 
du dann auf dein Wissen von der String-Funktion zurückgreifen :-)


PS: Die beste Lösung wäre ein Ringbuffer. Aber bring erst mal deinen 
normalen linearen Buffer zum laufen. Da kann man auch noch eine Menge 
dabei lernen.

von Zulu (Gast)


Lesenswert?

Woher K.H.B. nur diese Geduld nimmt?

@ Zulu

>Aber ich habe auch immer das verlangen, Zeit zu sparen.
Das ist eine Illusion.
Die Zeit die Du Dir beim lernen sparst,
brauchst Du dann um die Fehler zu finden, die Du mangels Wissen und 
Erfahrung einbaust.

Wenn sich K.H. die Zeit für eine Lektion in programmieren nimmt, dann 
solltest Du das nutzen.

von Zulu (Gast)


Lesenswert?

Quatsch:
Nicht @ Zulu
sondern @ Timo

von Timo P. (latissimo)


Lesenswert?

also ich habe meinen geänderten Code in einem der vorherigen beiträge 
angehängt. Wie man dort sieht, nutze ich nur die ISR zum versenden.
Somit habe ich wieder Zeit gespart, weil ich zwischen den ISR`s was 
anderes machen könnte.

wenn ich zb. jetzt aus:

ISR enable
protocol(also zu versendendes array) füllen
nach stringende in isr ISR selbst disablen

einen Funktionsaufruf machen möchte, dann kann ich dies doch einfach 
tun.
Ich übergebe der fkt. als einzigen parameter einen string. diese kopiert 
den string dann in das versende array. und enabled die TX-ISR.

Dann hab ich doch meine funktion zb.

void uputs(char *s);
{
   IE2 |= UCA0TXIE;
   strcpy(protocol, s);
}

aufruf uputs(arrayname);

von Karl H. (kbuchegg)


Lesenswert?

Timo P. schrieb:

> Dann hab ich doch meine funktion zb.
>
> void uputs(char *s);
> {
>    IE2 |= UCA0TXIE;
>    strcpy(protocol, s);
> }

anders rum:
zuerst den Zwischenspeicher fertig herrichten, dann den Interrupt 
freigeben und somit die Chose starten.

Ich hab dir doch weiter oben schon eine Version hergerichtet (die ich 
allerdings naheliegender Weise nicht testen konnte). Nicht gesehen?

von Timo P. (latissimo)


Lesenswert?

schon klar hatte mich nur verschrieben
läuft ja bereits

jetzt kommt der empfang dran....

von Timo P. (latissimo)


Lesenswert?

hallo Karl heinz Buchegger!

ich habe noch mal versucht, die von dir oben gebotenen funktionen ans 
laufen zu bekommen... der aufruf uputs("wake\r\n");

liefert ein: 0wake

volatile char protocol[80];
volatile signed char next_char = -1;

unsigned char uputs( const char *s )
{
  if( strlen( s ) > sizeof( protocol ) - 1 )
    return FALSE;

  while( next_char != -1 )
    ;

  strcpy( protocol, s );
  next_char = 0;
  IE2 |= UCA0TXIE;

  return TRUE;
}

#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
  char temp = protocol[ next_char ];

  if( temp == '\0' )
  {
    next_char = -1;
    return;
  }

  UCA0TXBUF = temp;
  next_char++;
}

von Timo P. (latissimo)


Lesenswert?

ich weiß warum ich habe in der TX-ISR noch das flag für TX_ISR enable 
ausgemacht!

so ist das endlose senden vorbei und die 0 am anfang auch!

von Timo P (Gast)


Lesenswert?

Hallo! Empfangen tue ich Zeichen von hyperterm, diese kann ich auch an 
hyerterm zurücksenden. Wenn ich zB. in hyperterm temp eingebe, sieht 
command[] jetzt so aus: temp\0 richtig??


void uart_gets( char* Buffer, uint8_t MaxLen )
{
  uint8_t NextChar;
  uint8_t StringLen = 0;

  NextChar = uart_getc();         // Nextchar
  while( NextChar != '\n' && StringLen < MaxLen - 1 )
  {
    *Buffer++ = NextChar;
    StringLen++;
    NextChar = uart_getc();
  }
  *Buffer = '\0';
}


Aufruf:
char command[11];
uart_gets(command, 10);


if(strcmp(command, "temp")== 0)  // hier habe ich auch \0 o.\n probiert
{
  uputs("*****Werte\r\n");       // diese zeile wird nie ausgef. :(
}

von Timo P (Gast)


Lesenswert?

Selbst gedanken gemacht habe ich mir schon:

1) wenn ich in C "temp" schreibe ist das ein eindim. array mit inhalt: 
temp\0
   korrekt?
2) die uart_gets() fkt. liefert mir einen string mit \0
   korrekt?
3) command-array ist mit [11] groß genug f. Aufruf: uart_gets(command, 
10);
   korrekt?


4) andere Fehler?

von Karl H. (kbuchegg)


Lesenswert?

Timo P schrieb:
> Selbst gedanken gemacht habe ich mir schon:
>
> 1) wenn ich in C "temp" schreibe ist das ein eindim. array mit inhalt:
> temp\0
>    korrekt?

Sollte zumindest so sein.

> 2) die uart_gets() fkt. liefert mir einen string mit \0
>    korrekt?

ja

> 3) command-array ist mit [11] groß genug f. Aufruf: uart_gets(command,
> 10);
>    korrekt?

ja.
wobei an dieser Stelle gilt:
nicht kleckern, klotzen!

> 4) andere Fehler?

nichts erkennbares
aber lass dir doch einfach mal den String, den du empfangen hast
ausgeben
1
  uart_gets(command, 10);
2
  uputs( "\r\nEmpfangen: >" );
3
  uputs( command );
4
  uputs( "<\r\n" );

dann weißt du ganz genau, was deine Leseroutine gelesen hat. Wichtig: 
Vor und hinter dem command String ein Sonderzeichen ausgeben, damit du 
auch versteckt Zeichen siehst. Am Terminal muss stehen
1
Empfangen: >temp<
Jede Abweichung davon weißt auf ein Problem hin
zb wäre
1
Empfangen: >temp
2
<
eine Abweichung, die darauf hindeutet, dass der Return nicht richtig 
ausgefiltert wird und im empfangenen String durchkommt.

von Timo P (Gast)


Lesenswert?

ich habe schon die ausgabe gemacht

und zwar folgendermaßen:

uputs("command eingeben: ");
uart_gets(command, 10);
uputs("\r\n einzelne Zeichen seriell: ");
uputchar(command[0]);
uputchar(command[1]);
uputchar(command[2]);
uputchar(command[3]);
uputchar(command[4]);
uputchar(command[5]);
uputchar(command[6]);
uputchar(command[7]);
uputchar(command[8]);
uputs("\r\n");

so sehe ich temp

von Timo P (Gast)


Lesenswert?

die idee mit < und > ist gut, so kann ich zeilenvorschübe detektieren.

(im übrigen ist mir auch bewusst, dass ich in hyperterm gesendete 
strings mit zeilenvorschub senden kann indem ich nen haken setze)

von Peter (Gast)


Lesenswert?

das ist doch vielleicht die lösung. du beendest das einlesen bei \n wenn 
aber \r\n kommt dann steht hinter dem test noch ein \r

von Timo P (Gast)


Lesenswert?

uputs("command eingeben: ");
uart_gets(command, 10);
uputs("\r\n\r\n");
uputs( "\r\n\r\nEmpfangen: >" );
uputs( command );
uputs( "<\r\n" );

Die Ausgabe ist: (habe nur ein t eingegeben)

t<pfangen: >t

damit kann ich garnix anfangen....

von Steffen A. (stigmer)


Lesenswert?

Ich kann da nur das kostenlose Programm "hterm" empfehlen, bei google 
sofort zu finden. Da werden auch Steuerzeichen wie "\n" angezeigt etc..

HyperTerminal kann nix.

von Timo P (Gast)


Lesenswert?

STIMMT!!!

Fehler behoben!

also \r\n wird anscheinend gesendet vom hyperterm
anstatt \n und meine(deine) fkt. die den string empfängt, kappt die 
zeichen via \n


also ist es besser für mich, wenn ich zwei eval-boards miteinander 
kommunizieren lasse.....

dann kann ich via sendecontroller *"temp?\n"* schicken und mit der 
empfangsfkt.
in command schreiben, diesen dann via strcmp mit genau diesem 
*"temp?\n"* vergleichen...

von Peter (Gast)


Lesenswert?

mach doch einfach

while( NextChar != '\n' && NextChar != '\r ' && StringLen < MaxLen - 1 )

von Timo P (Gast)


Lesenswert?

hab ich schon gemacht ;)

läuft wunderbar. Jetzt kommen trotzdem controller dran. Habe ja die 
Möglichkeit zwei controller kommunizieren zu lassen, dann tu ich das 
auch und zeige mir nur die ergebnisse der kommunikation eines 
controllers via hyperterm


Besten Dank!

von Peter (Gast)


Lesenswert?

wenn sich controllers unterhalten müssen, dann verwendet man aber nicht 
unbedingt ein klartext protokoll. (könntest ja auch gleich xml nehmen)

von Timo P (Gast)


Lesenswert?

vllt kannst du mir ja mal allgemeine Tips geben:

ich habe vor, von einem Controller(Mainboard) commands zu senden an 
verschiedene Device Controller. z.B. "temp?"
der entspr. device Controller reagiert natürlich nur auf "temp?" und 
schickt die vorher gemessene Temperatur los. Werte können sein:

22,5 °C als 45 übertragen
23   °C als 46 übertragen

ist sowas sinnvoll? so brauche ich nicht per sprintf("%5.1f",...) 
umrechnen. Habe gehört das frisst viel Zeit... sagen wir mal ich hätte 6 
versch. Sensoren(sind dann auch 6 versch. Arten, 6 versch 
device-Controller)diese 6 werte will ich höchstens jede sekunde 
(wahrscheinlich alle 10 sek.) abfragen via mainboard.
also habe ich im worst case pro sekunde 6 kommands zu senden und 6 Werte 
zu empfangen.


wie übertrage ich werte, wie übertrage ich commands?
IDEE:

command: "temp?"
wert:    "45"  //für 22,5°C

von Peter (Gast)


Lesenswert?

einfach keine Strings übertragen.

als ersten eventuell eine ID (z.b. 1 für Temp ) und danach den wert.


send(1)

//8bit
uint8_t tmp = 45;
send( tmp );

//16bit
uint16_t tmp = 45;
send( (uint8_t)tmp >> 8 );
send( (uint8_t)tmp & 0xFF );

von Karl H. (kbuchegg)


Lesenswert?

Timo P schrieb:

> ich habe vor, von einem Controller(Mainboard) commands zu senden an
> verschiedene Device Controller. z.B. "temp?"
> der entspr. device Controller reagiert natürlich nur auf "temp?" und
> schickt die vorher gemessene Temperatur los. Werte können sein:
>
> 22,5 °C als 45 übertragen
> 23   °C als 46 übertragen
>
> ist sowas sinnvoll? so brauche ich nicht per sprintf("%5.1f",...)
> umrechnen. Habe gehört das frisst viel Zeit... sagen wir mal ich hätte 6
> versch. Sensoren(sind dann auch 6 versch. Arten, 6 versch
> device-Controller)diese 6 werte will ich höchstens jede sekunde
> (wahrscheinlich alle 10 sek.) abfragen via mainboard.
> also habe ich im worst case pro sekunde 6 kommands zu senden und 6 Werte
> zu empfangen.

Und in der Zwischenzeit löst dein µC noch mindestens 1000 teuflisch 
schwierige quadratische Gleichungen.

Die Sache ist die

ASCII Transfer
**************
ist natürlich langsamer als ein paar Binärcodes hin und her zu schicken. 
Hat allerdings den Vorteil, dass man sich mit jedem beliebigen 
Terminalprogramm an die Leitung klemmen kann und im Klartext mitlesen 
kann, was gesendet bzw. empfangen wird
Weiterer Vorteil: In der Entwicklungsphase können Sender und Empfänger 
getrennt voneinander entwickelt werden. Die Rolle der jeweiligen 
Gegenstelle übernimmt der Mensch, der vor dem Terminal sitzt.
Der Aufbau eines fehlergesicherten, selbst synchronisierenden Protokolls 
ist trivial.

Binärer Transfer
****************
läuft voll Speed über die Leitung. Ohne spezielle Entwicklungswerkzeuge 
ist eine getrennte Entwicklung von Sender und Empfänger nur schwer bzw. 
umständlich zu realisieren. Ein Terminalprogramm, welches die Bytewerte 
direkt anzeigt ist dabei unterste Grundausstattung. Aber selbst dann ist 
es mühsam.
Der Aufbau eines fehlergesicherten, selbst synchronisierenden Protokolls 
ist zwar möglich, je nach tatsächlichem Datenaufbau aber umständlich.



Dein Datenaufkommen schafft eine ASCII Verbindung mit links. Und das 
Kommando an den Sensor muss ja nicht unbedingt "GetActualTemperatur" 
lauten.

von Timo P (Gast)


Lesenswert?

sagen wir ich habe 6 devices, jedes erwartet ein command a 5 Zeichen
und sendet ein zeichen id und 4 Zeichen Zahlenwert

also 6 * (5z+1)  // für \n
und  6 * (5z+1)  // id, 4 databytes \n

sind 72 zeichen(bidirektional gerechnet)
und via 8N1@9600 kann ich doch 960 Zeichen übertragen...

da hab ich ja mehr als genug luft.....


werde also senden: "10045\n" für ID: 1 und value: 25°
oder meintest du das so, dass ich das in GETRENNTEN Strings sende?

von Peter (Gast)


Lesenswert?

du musst dich zwischen Text und Binary entscheiden.


"10045\n"  ist Text  (6 Zeichen)

0x01, 0x2D ist Binary. (2 Zeichen)

Binay ist für dein µC einfacher weil er es nicht erst in text und zurück 
umwandln muss. Aber für dich schwerer weil du schlecht mitlesen kannst.

von Steffen A. (stigmer)


Lesenswert?

Nen Kommando-Interpreter-Modul wäre doch was feines. Das sitzt zwischen 
Applikation und dem UART-Treiber und übersetzt Ein-/Ausgaben von ASCII 
nach BINARY oder anders herum. Intern wird ausschließlich binär 
kommuniziert (beliebig komplex) und in Richtung HyperTerm hat man die 
Wahl: Klartext oder Nullen/Einsen.. Per Kommando umschaltbar.

Erinnerte mich gerade an nen Teil meiner Diplomarbeit.. :P

von Timo P (Gast)


Lesenswert?

Für mich denke ich, kommt binary doch mit ins spiel!

Also 0x01, 0x2D sind ja nur zwei Zeichen, darum werd ich`s so 
übertragen...(warum auch immer dies binary genannt wird)

Muss mir halt mal gedanken machen, weil ein Byte für den Temperaturwert 
nicht ausreichen wird, also zwei byte übertragen und irgendwie 
zusammenstricken, am einfachsten nen 16bit int als low und highbyte 
übertragen.

Mal ne Frage, wenn ich nen signed int habe, denn ich in zwei einzelne 
bytes zerrupfe, auf der empfängerseite dann aus den beiden bytes wieder 
ein signed zusammenstricke, dann habe ich doch keine Informationen 
bezüglich der "signedness" verloren, richtig?

von Peter (Gast)


Lesenswert?

so lange du auf beiden seiten die gleichen Datentyp hast, es es ziemlich 
egal wie du es überträgst.
Die signed information ist nur für den Compiler entscheident, damit er 
weiss welche Instruktionen er an die CPU übergeben muss. Im Speicher 
lässt sich ein signed nicht von einem unsigned unterscheiden.

von Karl H. (kbuchegg)


Lesenswert?

Timo P schrieb:

> Mal ne Frage, wenn ich nen signed int habe, denn ich in zwei einzelne
> bytes zerrupfe, auf der empfängerseite dann aus den beiden bytes wieder
> ein signed zusammenstricke, dann habe ich doch keine Informationen
> bezüglich der "signedness" verloren, richtig?


richtig.


Denk aber auch daran, deine Übertragung sollte im Idealfall so sein, 
dass sie sich synchronisiert. Damit ist gemeint:

Die beiden Geräte laufen schon seit geraumer Zeit, das verbindende Kabel 
ist abgefallen. Jetzt steckst du das Kabel wieder an und der Empfänger 
sieht

   0x87 0x02 0x02 0x56

Und er muss rausfinden können, dass hier

   0x87 0x02 0x02 0x56
              ^
              |
 die nächste Temperaturübertragung beginnt.

von Timo P (Gast)


Lesenswert?

kabel sind leiterplattenverbinder

es gibt ein mainboard, welches die devices (einstellbaren timings) 
bestromnt, diese machen alle ihre messungen, und dann fragt das 
Mainboard via command z.B "RH?\n" nach den Werten. Antwort könnte sein: 
"RH60\n"

oder command:
"temp?\n"

antwort:
"T45\n" oder 0x54 0x2D 0x0D // so habe ich doch aus 4 zeichen 3 gemacht 
:)

von Karl H. (kbuchegg)


Lesenswert?

Timo P schrieb:
> kabel sind leiterplattenverbinder

Ah, ok.

Da von Sensoren die Rede war, bin ich davon ausgegangen, dass diese 
räumlich abgesetzt sind und mit einem steckbaren Kabel mit einer 
Zentrale verbunden wird.

Wenn sowieso alles auf einer Platine ist, sollte das dann kein Problem 
sein.

von Timo P (Gast)


Lesenswert?

evtl. sind von den einzelnen platinen(devices) sensorkabel selbst 
weggeführt, aber die UART sind Platinenverbinder

1) * hierzu suche ich noch Wannenstecker und Wannenbuchsen als SMD in
   2,54mm 6Polig*

2) Bytereihenfolge ist mir überlassen, oder wird es oft nach einem
   bestimmten Prinzip gemacht? würde Big Endian nehmen.

3) wenn ich mal eine dez.13 übertragen will, kann ich dies nur tun,
   wenn ich ein anderes Stringendezeichen für den UART-Empfang wähle??
   Welches Würde sich anbieten? Ein Sonderzeichen wie '}' dann kann ich
   keine dez.172 übertragen


Danke für Antworten

von Timo P (Gast)


Lesenswert?

mir würde nur eine einzige Lösung für das Problem einfallen:

entweder
ich sende doch als string, dann hab ich mehr Zeichen, aber k. Prob mit 
stringendezeichen...

*oder:*
ich sende nicht als string, aber immer eine definierte Anzahl an Zeichen 
und lese via UART empfang auch nur diese Anz. an Zeichen aus, dann 
brauch ich k. Endezeichen

von Peter (Gast)


Lesenswert?

> ich sende nicht als string, aber immer eine definierte Anzahl an Zeichen
> und lese via UART empfang auch nur diese Anz. an Zeichen aus, dann
> brauch ich k. Endezeichen
Das hilft dir nicht weiter, wenn du einmal aus dem Tritt kommst dann 
stimmt alles nicht mehr.

Das einfachste ist wenn du ein zeichen nicht brauchst z.b. 255 das du 
das als Start interpretierst und danach dann deine anzahl einliest. Wenn 
jetzt innerhalb der Daten ein 255 auftaucht dann weist du das es ein 
erneuter Start ist. Du musst bloss dafür sorgen das in den eigentlichen 
daten dann kein 255 auftaucht.

von Timo P (Gast)


Lesenswert?

richtig, es wäre aber schön, wenn ich von 0 bis 255 alle werte innerhalb 
eines bytes übertragen könnte.

sonst brauch ich ja garnicht anfangen, ein 16int zu zerschnibbeln und 
als zwei zeichen zu übertragen.

werde einfach ausweichen und doch zum string greifen. Die Datenmenge, 
die ich zu handlen habe ist ja quasi lächerlich....

also nen "RH5644\n" zu senden jede sekunde...... das wird wohl gehen
dann muss ich halt nur noch die schnittstelle von ascii zu int 
programmieren

oder gibt es schon ein gegenstück zu ..printf was int zu ascii machen 
kann?

von Peter (Gast)


Lesenswert?

wenn du eh genug Reserve auf der Übertragunsstrecke hast, könntest du 
auch na jeden Datensatz eine Pause machen. Dann weiss der Empfänger das 
nach jeder Pause ein neuer Datensatz einfängt. Dann musst du nur dafür 
sorgen das die eigentlichen Daten ohne pause gesendet werden - was aber 
recht einfach ist.

von Karl H. (kbuchegg)


Lesenswert?

Timo P schrieb:

> oder gibt es schon ein gegenstück zu ..printf was int zu ascii machen
> kann?


Wenn du sowieso printf im Einsatz hast, ist scanf nicht weit.

von Karl H. (kbuchegg)


Lesenswert?

Timo P schrieb:
> richtig, es wäre aber schön, wenn ich von 0 bis 255 alle werte innerhalb
> eines bytes übertragen könnte.

Beitrag "Synchronisation UART, Mega8 mit PC"

Hier findest du ein paar Ideen, wie man dieses Problem lösen kann.

von Timo P (Gast)


Lesenswert?

werd mich mal schlau lesen....

THX!

von Timo P (Gast)


Lesenswert?

ok ich könnte ja ein paket senden, was so aufgeb. ist:

0x00 0x01 0x02 DATABYTE 1 DATABYTE 2 0x02 0x01 0x00

quasi 0 1 2 als start
und   2 1 0 als ende

dann habe ich zwar die Möglichkeit alle erdenklichen Datenbytes zu 
übertragen, aber den Nachteil dass ich mehr Zeichen senden muss.

wenn ich die wahrscheinlichkeit zu hoch ansehe dass die datenbytes
auch 0 1 2 oder 2 1 0 aufeinanderfolgend enthalten, muss ich noch
mehr bytes für start und endsequenz nehmen.

was soll ich nun tun?

Gerne würde ich doch strings nutzen! Oder ist mir da grundsätzlich bzw. 
für meine lächerlichen Datenmengen von abzuraten?

von Peter (Gast)


Lesenswert?

Ich würde sagen du fängst erstmal mit Strings. Wenn du dann mal ein 
größere Projekt hast wo du eventeull auch auf die Resourcen achten 
musst. Kannst du dich auch mal an ein Binary Protokoll ranmachen.

von Timo P (Gast)


Lesenswert?

ok danke für die stellungnahme

von Frank E. (erdi-soft)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Timo P schrieb:

> quasi 0 1 2 als start
> und   2 1 0 als ende

Das sieht zwar alles nett aus.
Aber je komplizierter deine Start und Endesequenzen sind, umso mehr 
Aufwand muss man in die Erkennung stecken.

> dann habe ich zwar die Möglichkeit alle erdenklichen Datenbytes zu
> übertragen, aber den Nachteil dass ich mehr Zeichen senden muss.

Womit gerade bei kurzen Datenpaketen der Vorteil der geringeren 
Datenmenge schnell wieder aufgebraucht wird.

Dass in einem Datenbyte ein von dir benutzes Steuerbyte vorkommt, ist 
eine Ausnahmesituation. Ich würde das auch so behandeln: Grundsätzlich 
ein so einfaches Protokoll wie notwendig und nur dann, wenn diese 
Ausnahme auftritt, auf etwas komplizierters zurückgreifen.

> Gerne würde ich doch strings nutzen! Oder ist mir da grundsätzlich bzw.
> für meine lächerlichen Datenmengen von abzuraten?

Du hast Zeit genug, die Aufbereitung ist simpel, auch das 
auseinanderklamüsern der Daten ist kein großes Problem.

T?;

ist die Aufforderung an den Sonsor seine Temperatur zu senden. Oder 
meinetwegen auch einfach nur

T;

oder vielleicht auch

?T;

(das ? steht für: Ich hätte da mal eine Frage ...
 das T steht für: ... bezüglich der Temperatur
 das ; steht für: hiermit beende ich das Kommando)

-----

T23.5;

ist die Antwort des Sensors. Das T steht für Temperatur. Alles danach 
bis zum ; ist der Zahlenwert. Das kann man einfach programmtechnisch 
leicht erzeugen und auch leicht wieder auseinandernehmen um an den Wert 
als Zahl zu kommen (und vermeidet den ganzen Ärger mit \r \n oder nur \r 
oder nur \n)

Der springende Punkt ist:
Es gibt kein 'richtig' und kein 'falsch'. Es gibt auch kein 'besser' 
oder 'schlechter'.
'richtig' und 'gut' ist immer das, was du implementieren kannst und was 
einwandfrei funktioniert. Denk dir was aus. Aber mach nicht den Fehler 
einfach mal draufloszuprogrammieren ohne dir vorher ein Konzept überlegt 
zu haben, wie die Kommunikation grundsätzlich funktionieren soll.

zb könntest du dir überlegen:
* Eine Übertragung beginnt mit einem Kommandozeichen und dauert immer
  bis zu einem ;
  Alle Zeichen dazwischen, inklusive dem Kommandobyte bilden ein Paket

* Das erste Byte eines Pakets ist immer ein Kommando
  ?   Abfrage
  !   Wert wird übergeben

* Das nächste Byte des Pakets bezeichnet, welcher Wert betroffen ist
  T   Temperatur
  D   Druck
  L   Luftfeuchte
  H   Uhrzeit Stunden
  M   Uhrzeit Minuten
  S   Uhrzeit Sekunden

* Alle restlichen Bytes sind der Wert, wobei Kommazahlen mit
  einem . geschrieben werden, sofern sie vorhanden sind.

* Abschliessendes Zeichen eines Pakets ist immer ein ;


Damit ist klar, wie

!T38.5;
oder
!L45;
oder
?H;

zu interpretieren ist und was zu machen ist, egal wer diese Sequenz an 
wen schickt.

PS:
Ach ja. Vergiss am besten gleich wieder die Idee, die Kommunikation so 
natürlichsprachlich wie möglich anzulegen. "Computer, strukturelle 
Integrität um 20% erhöhen" funktioniert nur bei Star Trek.

von Timo P. (latissimo)


Lesenswert?

nochmals danke für die zahlreiche Beteiligung.

ps: keine Angst, ich mag star trek eh nicht...
    Raumschiff Orion sagt mir da eher zu mit Bügeleisen, Brausetablette
    im Wasserglas, Badewannenstrudel usw... ;)

von Steffen A. (stigmer)


Lesenswert?

Ich würde vorschlagen, du baust die nen definierten Header, falls du 
doch binär bleiben möchtst, z.B. so:

1. Byte | 2. Byte | 3. Byte | ..... | n-tes Byte
  Start    Länge    Status    Data     Checksum

Dein UART empfängt stets per Interrupt Zeichen für Zeichen und puffert 
diese. Sobald das vereinbarte Start-Zeichen erkannt wird, setzt der µC 
eine Nachricht zusammen und baut diesen Puffer wieder ab. Im 2. Byte 
findet er die Nachrichten-Länge, dadruch weiß er, wann er aufhören muss 
die Nachricht zusammen zu setzten. Ob das funktioniert hat, merkste dann 
an der Prüfsumme im letzten Byte. Im Fehlerfall kannst du einen Fehler 
zurück geben und im Status Byte codieren. Die Gegenstelle kann dann 
entscheiden was zu tun ist (z.B. die Nachricht wiederholen).

Vielleicht etwas dick für deinen Anwendungsfall, aber ne saubere Sache.

von Peter (Gast)


Lesenswert?

@Steffen A.
So einfach ist es leider nicht, das Problem ist wenn das Start-Byte in 
den Daten vorkommt. Dann Synchroniert der Empfänger nicht mehr auf den 
Sender.

von P. S. (Gast)


Lesenswert?

Peter schrieb:

> @Steffen A.
> So einfach ist es leider nicht, das Problem ist wenn das Start-Byte in
> den Daten vorkommt. Dann Synchroniert der Empfänger nicht mehr auf den
> Sender.

Das muss man halt escapen, wurde das noch nicht erwaehnt? Dann kann man 
auch waehrend man die Daten liest auf das Startbyte hoeren - dann weiss 
man schon vor der Checksumme, das was schief gegangen ist.

von Steffen A. (stigmer)


Lesenswert?

Peter Stegemann schrieb:
> Peter schrieb:
>
>> @Steffen A.
>> So einfach ist es leider nicht, das Problem ist wenn das Start-Byte in
>> den Daten vorkommt. Dann Synchroniert der Empfänger nicht mehr auf den
>> Sender.
>
> Das muss man halt escapen, wurde das noch nicht erwaehnt? Dann kann man
> auch waehrend man die Daten liest auf das Startbyte hoeren - dann weiss
> man schon vor der Checksumme, das was schief gegangen ist.

Wenn das Start-Byte beim Zusammenbau der Nachricht vorkommt, sollte das 
die Software nicht schocken. Sollte aber das Richtige versäumt werden 
und dann das 2. "Start-Byte" fälschlicherweise als Startbyte erkannt 
werden, kommt die Checksumme nicht mehr hin... Fehlermeldung senden und 
die letzte Nachricht wiederholen lassen, bzw. ne fortlaufende ID mit im 
Header aufnehmen. Dann kann man gezielt sagen "Nachricht No. XY nochmal, 
bitte."

Bin nicht sicher, was mit dem "Unwort" escapen gemeint ist? Erbitte 
Erklärung deines Vorschlages. :)

von P. S. (Gast)


Lesenswert?

Steffen A. schrieb:

> Bin nicht sicher, was mit dem "Unwort" escapen gemeint ist? Erbitte
> Erklärung deines Vorschlages. :)

Finde ich etwas irritierend, dass du eine lange Antwort schreibst und 
dann erst nach dem Wort fragst, was du nicht verstanden hast. Kein 
Wunder passt deine Antwort irgendwie nicht zu dem, was ich geschrieben 
habe.

http://de.wikipedia.org/wiki/Escape-Sequenz
http://de.wikipedia.org/wiki/Maskierungszeichen

von Steffen A. (stigmer)


Lesenswert?

Die Antwort bezog sich auf das Zitat in deinem Zitat, ich habe erklärt 
wie dessen Bedenken ausgeräumt werden können. War wohl nicht ganz 
offensichtlich, zugegeben.

Was escape-Zeichen sind, ist mir übrigens bekannt. Beim Zusammenhang 
hatte ich gehofft, du würdest das fix in 1-2 Sätzen zusammen schreiben.

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.