Forum: Mikrocontroller und Digitale Elektronik Problem: 16 Bit Variable über UART zu empfangen


von Reinhard O. (kristian_1955)


Lesenswert?

Hallo liebes Microcontroller Forum,

ich nutze einen ATMEGA88A-PU. UART, 8Data Bit; 1 Stop Bit; BAUD: 9600
Ich programmiere den Controller mit C im Atmel Studio.

Dem Controller schicke ich über LabView 2 Byte. Zuerst das MSB dann das 
LSB. Die beiden Bytes füge ich auf dem Controller in eine 16 Bit 
Variable zusammen. Das klappt soweit ganz gut.
Wenn ich nun aber in einer Dauerschleife permanent das MSB und das LSB 
an den Microcontroller schicke, springt der Wert der 16 Bit Variable auf 
dem Controller kurz auf einen anderen Wert und dann wieder zurück auf 
den Wert den ich permanent schicke.

Konkrekt bedeuetet das:

Wenn ich dauerhaft 1000 (dezimal) sende, springt die Variable kurzzeitig 
auf 59624. Das bedeutet, dass das  MSB = 232 ist und das LSB auch = 232 
obwohl ja MSB ungleich LSB sein sollte. Etwas ähnliches passiert wenn 
ich 100 (dezimal) sende.
Dann empfänge ich mittendrin kurzzeitig 25700. Das entspricht MSB = 
100(dezimal) und LSB = 100 (dezimal). Es ist also ein deutliches Muster 
zu erkennen. Leider habe ich keine Idee wie ich das beseitigen kann. Bin 
sehr unerfahren in Sachen Mikrocontroller Programmierung. Im Folgendem 
beschreibe ich wie ich den Empfang programmiert habe. Sicherlich keine 
elegante Lösung. Vielleicht liegt hier schon das Problem.

Der Empfang auf dem Mikrocontroller läuft folgendermaßen ab:

Ich empfange Daten per Interrupt. Jedes mal wenn ein Byte empfangen 
wird, also der Empfangsinterrupt ausgelöst wird, erhöhe ich eine 
Zählvariable um den Wert 1.

Empfängt der Mikrocontroller nun den Befehl, dass er in die 16 Bit 
Variable schreiben (Befehl: 85) soll, wird der Zähler = 0 gesetzt.
Das nächste Byte, das dann empfangen wird setzt den Zähler = 1. Das 
erkennt meine if-Abfrage und speichert diesen Wert dann als MSB ab. Beim 
nächsten Byte, das empfangen wurde ist der Zähler = 2. Auch das erkennt 
eine if-Abfrage und speichert das Byte in einer Variablen namens LSB. 
Das MSB und das LSB verknüpfe ich dann ODER und erhalte so den 16 Bit 
Wert. Anschließend setze ich den Zähler = 10, sodass die beiden if 
Bedingungen erst wieder erfüllt sind, sobald ich den Befehl schicke um 
in diese Variable zu schreiben.

Viele Grüße & besten Dank

von Jay K. (deeplyembedded)


Lesenswert?

Generell sagen ein paar Zeilen Code mehr als tausend Worte.

Es klingt aber ganz danach als würde mit deiner Zählung irgendetwas 
nicht stimmen, so dass das LSB versehentlich als MSB interpretiert wird.

von Klaus (Gast)


Lesenswert?

Jay K. schrieb:
> Es klingt aber ganz danach als würde mit deiner Zählung irgendetwas
> nicht stimmen, so dass das LSB versehentlich als MSB interpretiert wird.

Deswegen schicken clevere die Zahl in ASCII mit einem newline als 
Trennzeichen.

MfG Klaus

von Sebastian E. (sbe_15)


Lesenswert?

Vermutlich benötigst du eine Synchronisation zwischen Sender und 
Empfänder für den Fall das irgendwann mal ein Byte verschütt geht.

Das geht z.B. über eine Sendepause, wenn LabView in eine gröberen 
Zeitraster sendet als der UART zum Senden beider Bytes benötigt:

<Befehl><MSB><LSB>...Pause...<Befehl><MSB><LSB>...Pause...

Hier könntest du auf dem µC einen Timer mitlaufen lassen, der den 
Abstand zwischen zwei empfangenen Bytes misst.

Oder du verpackst das in ein Protokoll, z.B. (binär)


0b00BB BBBB
0b01BB MMMM
0b10MM MMLL
0b11LL LLLL

B = Bits des Befehls
M = Bits des MSB
L = Bits des LSB

Die '0' und '1' ober wären dann Byte-Zähler, aus denen sich die 
Reihenfolge rekonstruieren lässt, bzw. verlorene Bytes erkannt werden 
können. Den Luxus muss man sich dann mit ein wenig Bitschieberei 
erkaufen.

von H.Joachim S. (crazyhorse)


Lesenswert?

Jo, Programm bitte.

D.h. eigentlich funktioniert es, aber manchmal nicht?

von Jay K. (deeplyembedded)


Lesenswert?

Klaus schrieb:
> Jay K. schrieb:
>> Es klingt aber ganz danach als würde mit deiner Zählung irgendetwas
>> nicht stimmen, so dass das LSB versehentlich als MSB interpretiert wird.
>
> Deswegen schicken clevere die Zahl in ASCII mit einem newline als
> Trennzeichen.
>
> MfG Klaus


Was zur Folge hat, dass du für eine uint16 in worst-case (0xffff) 5 
ASCII Zeichen und damit 5 Bytes übertragen musst...und wenn eins 
verloren geht, wird es trotzdem nicht erkannt?

Sinnvoller ist da ein Protokoll, wie von Sebastian vorgeschlagen.
Ein ganz einfaches wäre ein Acknowledge vom Empfänger nach jedem Byte


<Befehl1></ACK><MSB1></ACK><LSB1></ACK><Befehl2></ACK><MSB2></ACK><LSB2> 
</ACK>

von Stefan K. (stefan64)


Lesenswert?

Hans D. schrieb:
> Wenn ich nun aber in einer Dauerschleife permanent das MSB und das LSB
> an den Microcontroller schicke, springt der Wert

Ev liegt Dein Problem gar nicht im Microcontroller, sondern im Sender, 
d.h. Du hast einen Buffer-Overflow.

Der Vorteil eines ASCII-Protokolls liegt für mich in der einfachen 
Debug-Möglichkeit, jedes Terminalprogramm reicht zum Testen.

Gruß, Stefan

von M. K. (sylaina)


Lesenswert?

Hans D. schrieb:
> Empfängt der Mikrocontroller nun den Befehl, dass er in die 16 Bit
> Variable schreiben (Befehl: 85) soll, wird der Zähler = 0 gesetzt.
> Das nächste Byte, das dann empfangen wird setzt den Zähler = 1. Das
> erkennt meine if-Abfrage und speichert diesen Wert dann als MSB ab. Beim
> nächsten Byte, das empfangen wurde ist der Zähler = 2. Auch das erkennt
> eine if-Abfrage und speichert das Byte in einer Variablen namens LSB.
> Das MSB und das LSB verknüpfe ich dann ODER und erhalte so den 16 Bit
> Wert. Anschließend setze ich den Zähler = 10, sodass die beiden if
> Bedingungen erst wieder erfüllt sind, sobald ich den Befehl schicke um
> in diese Variable zu schreiben.

Darf dein Programm zwischen dem Empfangen vom MSB und LSB auf die Werte 
zugreifen? Für mich klingt das nämlich danach, dass der uC ab und an 
schneller als der UART ist und dann auf deine 16 bit Variable schon 
zugreift obwohl die noch gar nicht fertig gebaut ist.
Du musst hier also einen atomaren Zugriff auf die 16 bit Variable 
zusammenstellen damit man nicht während des Neubaus schon mal auf die 
Variable zugreift.

von Klaus (Gast)


Lesenswert?

Jay K. schrieb:
> Was zur Folge hat, dass du für eine uint16 in worst-case (0xffff) 5
> ASCII Zeichen und damit 5 Bytes übertragen musst

Was für eine Verschwendung!

Stefan K. schrieb:
> Der Vorteil eines ASCII-Protokolls liegt für mich in der einfachen
> Debug-Möglichkeit, jedes Terminalprogramm reicht zum Testen.

Warum sind wohl die meißten Protokolle im Internet ASCII? Clever, halt.

MfG Klaus

von Walter S. (avatar)


Lesenswert?

Hans D. schrieb:
> Im Folgendem
> beschreibe ich wie ich den Empfang programmiert habe.

das hilft nix, der Programmtext dagegen um so mehr

von Jim M. (turboj)


Lesenswert?

M. K. schrieb:
> Für mich klingt das nämlich danach, dass der uC ab und an
> schneller als der UART ist und dann auf deine 16 bit Variable schon
> zugreift obwohl die noch gar nicht fertig gebaut ist.

Oder er ist langsamer und der nächste Wert des MSB liegt an bevor der 
alte abgeholt wurde.

Quelltext als Anhang, bitte.

von Thomas E. (thomase)


Lesenswert?

Jim M. schrieb:
> Oder er ist langsamer und der nächste Wert des MSB liegt an bevor der
> alte abgeholt wurde.

Die Übertragung eines Bytes dauert 1ms. So langsame Controller gibt es 
gar nicht.

von Wolfgang (Gast)


Lesenswert?

Hans D. schrieb:
> Dem Controller schicke ich über LabView 2 Byte. Zuerst das MSB dann das
> LSB. Die beiden Bytes füge ich auf dem Controller in eine 16 Bit
> Variable zusammen. Das klappt soweit ganz gut.

Woher soll der Empfänger wissen, welche das erste und welches das zweite 
Byte ist. Jeweils ein Start- und ein Stopbit reichen nicht, um die Bytes 
beim Empfänger zu unterscheiden. Du könntest drei Byte übertragen. Das 
würde für 21 Bit Daten zzgl. 1 Bit Synchronisationsinformation pro 
gesendetem Byte reichen.

von Reinhard O. (kristian_1955)


Angehängte Dateien:

Lesenswert?

Hallo an alle,

ich bin sehr erfreut, dass mir so viele Leute helfen wollen.:)
Schonmal ein Dankeschön dafür.

Den Quellcode findet ihr im Anhang.

Viele Grüße

von Jay K. (deeplyembedded)


Lesenswert?

Du verwendest UARTInterruptZaehler sowohl im Interrupt als auch in der 
Hauptroutine und deine if() Abfragen sind sicherlich nicht atomar -> Es 
kann passieren dass du gerade einen deiner if() Blöcke abarbeitest, dann 
kommt ein Interrupt mit neuen Daten und "Command" wird überschrieben.

Du könntest das ganze synchronisieren indem du nicht ständig die 
Hauptroutine laufen lässt, sondern in der ISR eine Art Semaphore setzt, 
das in der Hauptroutine gepollt und ausgewertet wird.
In der ISR selbst setzt du nur das Semaphore und pufferst evtl noch 
"Command" weg, so dass die Hauptroutine mit einer Kopie von "Command" 
arbeitet

von Reinhard O. (kristian_1955)


Lesenswert?

Mir ist grade klar geworden, dass es sinnvoll wäre nochmal zu 
beschreiben wie der Sender arbeitet:

Er sendet:
<Befehl 85><warten auf Quittierung vom Mikrocontroller uC sendet 1 
(dezimal)><sendet MSB><warten auf Quittierung vom Mikrocontroller uC 
sendet 1 (dezimal)><sendet LSB><Wartet auf 2 Byte(uC antwortet mit MSB 
und LSB)>

Anschließend beginnt der Zyklus von Vorne, also wieder:
<Befehl 85><warten auf Quittierung vom Mikrocontroller uC sendet 1 
(dezimal)><sendet MSB><warten auf Quittierung vom Mikrocontroller uC 
sendet 1 (dezimal)><sendet LSB><Wartet auf 2 Byte(uC antwortet mit MSB 
und LSB)>

....

Das Ganze in einer Dauerschleife. Dabei treten dann die oben 
beschriebenen Probleme auf.

von M. K. (sylaina)


Lesenswert?

Hans D. schrieb:
> Das Ganze in einer Dauerschleife. Dabei treten dann die oben
> beschriebenen Probleme auf.

Ja aber wie verhinderst du, dass der Mikrocontroller lesend auf die 16 
bit Variable während grade eine neue 16 bit Variable an den 
Mikrocontroller übertragen wird? Bei einen atomaren Zugriff wird 
verhindert, dass während eines Lesezugriffs schreibend auf die Variable 
zugegriffen wird und umgekehrt.

von Reinhard O. (kristian_1955)


Lesenswert?

Auf die 16 Bit Variable "Aufstromeit" greift der uC nur zu, wenn ich ihm 
den Befehl 5 (dezimal) sende.

Verhindert das nicht, dass ich die Variable lese während ich Sie 
schreibe?

von Jay K. (deeplyembedded)


Lesenswert?

Hans D. schrieb:
> Auf die 16 Bit Variable "Aufstromeit" greift der uC nur zu, wenn ich ihm
> den Befehl 5 (dezimal) sende.

Hm? Du greifst auch beim Zusammenbauen darauf zu. Und genau da kann was 
schief gehen, wenn du einen Interrupt bekommst und dann in "Command" das 
LSB geschrieben wird, obwohl du in deiner MSB if-Schleife bist

von Thomas E. (thomase)


Lesenswert?

Hans D. schrieb:
> Mir ist grade klar geworden, dass es sinnvoll wäre nochmal zu
> beschreiben wie der Sender arbeitet:

Dir sollte klar werden, daß es totaler Mist ist, was du machst.

Wenn ein Datensatz, der aus mehreren Bytes besteht, übertragen werden 
soll, brauchst du ein Protokoll. Das sieht minimal so aus:

Präambel
Daten
Postambel

Wenn die Länge der Daten immer gleich ist, kann man auf die Postambel 
auch verzichten. Fehlererkennung bzw. -korrektur lassen wir mal aussen 
vor.

Der Sinn der Präambel ist, dem Empfänger eindeutig zu signalisieren, daß 
jetzt ein Satz von Daten folgt. Der der Postambel ist es, ihm 
mitzuteilen, daß die Übertragung jetzt zuende ist.

Die Daten, die dazwischen übertragen werden, dürfen weder für eine 
Präambel noch für eine Postambel gehalten werden. Alles, was dafür nötig 
ist, wurde schon vor Jahrzehnten erfunden und nennt sich ASCII. Also 
benutze das auch. Keiner hat hier Lust, deinen Murks zum Laufen zu 
bringen.

von Reinhard O. (kristian_1955)


Lesenswert?

Thomas E. schrieb:
> Wenn ein Datensatz, der aus mehreren Bytes besteht, übertragen werden
> soll, brauchst du ein Protokoll. Das sieht minimal so aus:
>
> Präambel
> Daten
> Postambel

Übernimmt in dem Fall nicht der Befehl die Funktion der Präambel?
Wie man das mit ASCII macht, verstehe ich nicht. Finde nirgendwo eine 
Anleitung dafür..

von Arduinoquäler (Gast)


Lesenswert?

Danke an Thomas Eckmann dass du einmal ein klares Wort gegen
dieses Herumge-Eiere in diesem Thread geschrieben hast.

von myasuro (Gast)


Lesenswert?

Hi,
bei 2 Byte langt doch auch der 9Bit Modus der UART, MSB hat 9. bit 
gesetzt, LSB nicht. (wo das zusätzliche bit ist würde ich halt erst 
gucken wie die Darstellung im Atmega ist. Minimal, keine Absicherung, 
aber schon mal kein Vertauschen von MSB mit LSB.
MfG
myasuro

von Reinhard O. (kristian_1955)


Lesenswert?

Okay....wenn das alles Murks ist, würde ich versuchen ein richtiges 
Übertragungsprotokoll, das  mit ASCII Zeichen arbeitet, zu 
programmieren.
Habe sowas leider noch nie gemacht. Könnt ihr mir mit Links weiterhelfen 
wo beschrieben steht wie man sowas macht?

Vielen Dank

von ms (Gast)


Lesenswert?

Hallo Hans,

Hans D. schrieb:
> Könnt ihr mir mit Links weiterhelfen
> wo beschrieben steht wie man sowas macht?

https://ccrma.stanford.edu/courses/250a-fall-2005/docs/avrlib/

dort nach STX/ETX Packet Protocol suchen.

ms

von Eric B. (beric)


Lesenswert?

Thomas E. schrieb:
> Präambel
> Daten
> Postambel
>
> Wenn die Länge der Daten immer gleich ist, kann man auf die Postambel
> auch verzichten.

Oder wenn im Präambel die Länge der Daten mitkodiert ist, oder wenn in 
den Daten selber das Ende mitkodiert ist (wie zB bei MIDI).

Hans D. schrieb:
> Okay....wenn das alles Murks ist, würde ich versuchen ein
> richtiges Übertragungsprotokoll,

Das hast du eigentlich schon, nur ein wenig zu umständlich. Poste 
erstmal deine vollständige Code. Als C-Datei.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Hans D. schrieb:
> Okay....wenn das alles Murks ist, würde ich versuchen ein richtiges
> Übertragungsprotokoll, das  mit ASCII Zeichen arbeitet, zu
> programmieren.

 Nein, lass es sein. Das sind die Tipps von Leuten, die keine
 Ahnung haben, weil die so etwas noch nie implementiert haben.

 Mach es mit: <SOF><LSB><MSB><EOF>
 Das sind (und bleiben) immer 4 Byt.
 Bei ASCII sind es zwischen 1 und 5 Bytes ( + CR/LF) und das Ganze
 muss dann auch noch umgerechnet werden.

 <SOF> ist bei mir 0xAA, <EOF> ist 0xA9 und da gab es noch nie
 irgendwelche Probleme damit.

 Auf <SOF> warten.
 Weitere 3 Bytes einlesen.
 Letztes Byte == <EOF> ?

: Bearbeitet durch User
von Reinhard O. (kristian_1955)


Lesenswert?

1
#define F_CPU 18432000
2
#include <stdio.h>
3
#include <string.h>
4
#include <stdlib.h>
5
#include <stdio.h>
6
7
8
#include <avr/wdt.h>
9
#include <util/delay.h>
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
13
volatile uint8_t AufstromzeitHB = 0;
14
volatile uint8_t AufstromzeitLB = 0;
15
volatile uint16_t Aufstromzeit = 0;
16
int y = 0;
17
int x = 0;
18
uint8_t buesy = 0;
19
uint8_t adc_write_config[56];
20
uint8_t adc_read_com[49];
21
uint8_t register_status[49];
22
uint8_t Zahlen[12];
23
volatile uint8_t t = 0;
24
volatile int z =0;
25
uint8_t Byte1, Byte2, Byte3;
26
uint8_t datain_spi;
27
uint8_t START= 0b00000000;
28
volatile uint8_t Command = 0;
29
volatile uint8_t EmpfangeAufstromzeit = 1;
30
uint8_t AnzahlBytes = 0;
31
uint8_t UARTInterruptZaehler =10;
32
33
void long_delay(uint16_t ms) {
34
  for (; ms>0; ms--) _delay_ms(1);
35
}
36
37
38
void USART_Init(uint16_t UBRR)
39
{
40
  UBRR0H = (uint8_t)(UBRR >> 8);            //Schiebe 16-Bit um 8 Stellen nach rechts (1111111111111111 --> 0000000011111111)
41
  UBRR0L = (uint8_t)UBRR;                //Lese die ersten 8 Bit der Variable UBRR ein und schneide den Rest ab.
42
  UCSR0A = ~(1<<U2X0);
43
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);          //Frame: 1 stop Bit, 8 data bits
44
  UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);      //Aktiviere Sender(TXD) und Empfänger(RXD) sowie Receive Complete Interrupt.
45
}
46
void USART_Flush(void)
47
{
48
  uint8_t dummy;
49
  while (UCSR0A & (1<<RXC0)) dummy = UDR0;
50
}
51
void SPI_MasterInit(void)
52
{
53
  //SPCR |= (0<<DORD);  
54
  SPCR |= (1<<MSTR);    //Controller = Master
55
  //SPCR  &= ~(1<<CPOL);  //CLK positive phase
56
  SPCR |= (0<<CPHA);    //Sampling data @ falling edge
57
  SPCR |= (0<<SPR1) | (0<<SPR0);
58
  DDRB |= (1<<PB3);
59
      //Set MOSI output
60
  DDRB &= ~(1<<PB4);    //Set MISO input
61
  DDRB |= (1<<PB5);    //Set SCK output
62
  DDRB |= (1<<PB2);    //Set SS output
63
  
64
  SPCR |= (1<<SPE)|(0<<SPIE)|(0<<CPOL);// | (1<<SPIE);    //SPI enable
65
}
66
void IOports(void)
67
{
68
  DDRB &= ~(1<<DDB1); // Set /DRDY as Input 
69
  DDRD |= (1<<DDD2); // 
70
  PORTD |= (1<<PD2); // 
71
  DDRC |= (1<<DDC2) | (1<<DDC0); 
72
  PORTC |= (0<<PC2) | (1<<PC0);
73
}
74
void USART_Senden(uint8_t Daten)
75
{
76
  while (!(UCSR0A & (1<<UDRE0)));            // Warte auf leeren Sendebuffer, Sendebuffer leer, wenn UDREO = 1.
77
  UDR0 = Daten;                    //Schreibe, die der Funktion übergebenen 8-Bit, in den Sendebuffer.
78
}
79
void SPI_Senden(uint8_t Daten)
80
{
81
  //PORTB &= ~(1<<PB2);        //SS = low (Slave= enabled)
82
  
83
  SPDR = Daten;          //Übertragung starten
84
  while (!(SPSR & (1<<SPIF)));  //Warte auf Ende der Übertragung
85
  //return SPDR;
86
  
87
}
88
89
uint8_t SPI_Empfangen(void)
90
{
91
  while (!(SPSR & (1<<SPIF)));
92
  return SPDR;
93
}
94
95
96
97
void reset_SPI_ADS(void)
98
{
99
  DDRD |= (1<<DDD2);
100
  PORTD ^= (1<<PD2);
101
  _delay_us(100);
102
  PORTD ^= (1<<PD2);
103
}
104
void stop_conversion(void)
105
{
106
  PORTC &= ~(1<<PC2);
107
}
108
void start_conversion(void)
109
{
110
  PORTC |=(1<<PC2);
111
}
112
113
void reset_ADS1258(void)
114
{
115
  PORTC &= ~(1<<PC0);
116
  _delay_us(100);
117
  PORTC |= (1<<PC0);
118
  _delay_ms(17);
119
}
120
void ADCInit(void)
121
{  //stop_conversion();
122
  PORTD &= ~(1<<PD2);      // /CS of ADC auf GND
123
  for(int i=0; i<=3; i++)
124
  {
125
    SPI_Senden(adc_write_config[i]);
126
  }
127
  PORTD |= (1<<PD2);
128
  
129
}
130
uint8_t USART_Empfangen(void)                  
131
{
132
  while(!(UCSR0A &(1<<RXC0)))              //Während ungelesene Daten im Buffer sind, lies den Inhalt des Registers aus
133
  ;
134
  return UDR0;
135
}
136
137
138
139
int main(void)
140
{  adc_write_config[0]=0b01100000;    //CONFIG0
141
  adc_write_config[1]=0b00000010;    //Inhalt CONFIG0
142
  adc_write_config[2]=0b01100001;    //select config1
143
  adc_write_config[3]=0b01110000;    //write config1 max delay, low data rate
144
  
145
  /////alle PT100////////////////////////////////////////////
146
  adc_write_config[4]=0b01100100;    //select MUXG0
147
  adc_write_config[5]=0b11110000;    //write MUXG0 Lese nur PT100 aus
148
  adc_write_config[6]=0b01100101;    //select MUXSG1
149
  adc_write_config[7]=0b00000000;    //write MUXSG1
150
  ///////////////////////////////////////////////////////////
151
  
152
  ////////Lese nur DUT1//////////////////////////////////////
153
  adc_write_config[8]=0b01100100;      //select MUXG0
154
  adc_write_config[9]=0b00000000;
155
  adc_write_config[10]=0b01100101;    //select MUXSG1
156
  adc_write_config[11]=0b00000000;    //write MUXSG1
157
  adc_write_config[12]=0b01100011;    //select MUXDIF
158
  adc_write_config[13]=0b01000000;    //write MUXDIF
159
  ///////////////////////////////////////////////////////////
160
  
161
  //////Lese nur DUT2///////////////////////////////////////
162
  adc_write_config[14]=0b01100100;    //select MUXG0
163
  adc_write_config[15]=0b00000000;
164
  adc_write_config[16]=0b01100101;    //select MUXSG1
165
  adc_write_config[17]=0b00000000;    //write MUXSG1
166
  adc_write_config[18]=0b01100011;    //select MUXDIF
167
  adc_write_config[19]=0b10000000;    //write MUXDIF
168
  //////////////////////////////////////////////////////////
169
  
170
  //////Lese nur DUT3///////////////////////////////////////
171
  adc_write_config[20]=0b01100100;    //select MUXG0
172
  adc_write_config[21]=0b00000000;
173
  adc_write_config[22]=0b01100101;    //select MUXSG1
174
  adc_write_config[23]=0b00000000;    //write MUXSG1
175
  adc_write_config[24]=0b01100011;    //select MUXDIF
176
  adc_write_config[25]=0b00000001;    //write MUXDIF
177
  //////////////////////////////////////////////////////////
178
  
179
  ////Lese nur DUT4/////////////////////////////////////////
180
  adc_write_config[26]=0b01100100;    //select MUXG0
181
  adc_write_config[27]=0b00000000;
182
  adc_write_config[28]=0b01100101;    //select MUXSG1
183
  adc_write_config[29]=0b00000000;    //write MUXSG1
184
  adc_write_config[30]=0b01100011;    //select MUXDIF
185
  adc_write_config[31]=0b00000010;    //write MUXDIF
186
  //////////////////////////////////////////////////////////
187
  
188
  /////PT100 DUT1///////////////////////////////////////////
189
  adc_write_config[32]=0b01100100;    //select MUXG0
190
  adc_write_config[33]=0b00010000;
191
  adc_write_config[34]=0b01100101;    //select MUXSG1
192
  adc_write_config[35]=0b00000000;    //write MUXSG1
193
  adc_write_config[36]=0b01100011;    //select MUXDIF
194
  adc_write_config[37]=0b00000000;    //write MUXDIF
195
  //////////////////////////////////////////////////////////
196
  
197
  /////PT100 DUT2///////////////////////////////////////////
198
  adc_write_config[38]=0b01100100;    //select MUXG0
199
  adc_write_config[39]=0b00100000;
200
  adc_write_config[40]=0b01100101;    //select MUXSG1
201
  adc_write_config[41]=0b00000000;    //write MUXSG1
202
  adc_write_config[42]=0b01100011;    //select MUXDIF
203
  adc_write_config[43]=0b00000000;    //write MUXDIF
204
  //////////////////////////////////////////////////////////
205
  
206
  /////PT100 DUT3///////////////////////////////////////////
207
  adc_write_config[44]=0b01100100;    //select MUXG0
208
  adc_write_config[45]=0b01000000;
209
  adc_write_config[46]=0b01100101;    //select MUXSG1
210
  adc_write_config[47]=0b00000000;    //write MUXSG1
211
  adc_write_config[48]=0b01100011;    //select MUXDIF
212
  adc_write_config[49]=0b00000000;    //write MUXDIF
213
  //////////////////////////////////////////////////////////
214
  
215
  /////PT100 DUT4///////////////////////////////////////////
216
  adc_write_config[50]=0b01100100;    //select MUXG0
217
  adc_write_config[51]=0b10000000;
218
  adc_write_config[52]=0b01100101;    //select MUXSG1
219
  adc_write_config[53]=0b00000000;    //write MUXSG1
220
  adc_write_config[54]=0b01100011;    //select MUXDIF
221
  adc_write_config[55]=0b00000000;    //write MUXDIF
222
  //////////////////////////////////////////////////////////
223
  
224
  
225
  adc_read_com[0]=0b00110000; //Channel Data Read Command
226
  adc_read_com[1]=0b00000000;
227
  adc_read_com[2]=0b00000000;
228
  adc_read_com[3]=0b00000000;
229
  adc_read_com[4]=0b00000000;  //LSB CH1
230
  
231
  
232
  
233
  Zahlen[0]=0b00000000;
234
  Zahlen[1]=0b00000000;
235
  Zahlen[2]=0b00000011;
236
  Zahlen[3]=0b00000100;
237
  Zahlen[4]=0b00000101;
238
  Zahlen[5]=0b00000110;
239
  Zahlen[6]=0b00000111;
240
  Zahlen[7]=0b00001000;
241
  Zahlen[8]=0b00001001;
242
  Zahlen[9]=0b00001010;
243
  Zahlen[10]=0b00001011;
244
  Zahlen[11]=0b00001100;
245
  
246
  
247
  //sei();                      //Interrupts aktivieren (SREG; I =1);
248
  USART_Init(119);          //39      //U2Xn = 0 (normal speed in Asynchronus Mode) // f=18.432Mhz // Baudrate = 2400 //39=28800 Baudrate
249
  sei();
250
  SPI_MasterInit();
251
  IOports();
252
  DDRC |= (1<<DDC5);                //LED Ausgang
253
  _delay_ms(100);                  
254
  ADCInit();
255
  //DDRC |= (1<<PC5);  /LED
256
  
257
  
258
  
259
  
260
261
while(1)
262
    {  ///////////////////////////////////////////////////////////////////////////////////////////
263
    if (Command == 0b00000001 && EmpfangeAufstromzeit == 1)
264
   {  cli();
265
     buesy = 1;
266
     PORTD &= ~(1<<PD2);      // ChipSelect low
267
    for (int i = 8;i<=13;i++)  
268
    {
269
      SPI_Senden(adc_write_config[i]);
270
    }
271
    
272
    PORTD |= (1<<PD2);      // ChipSelect high
273
    PORTC |=(1<<PC2);      // START pin of ADS high level
274
    PORTC &=~(1<<PC2);      // START pin low again
275
    
276
    AnzahlBytes = 5;
277
    Command = 0;
278
    buesy = 0;
279
    sei();
280
    USART_Senden(1);
281
  }
282
  /////////////////////////////////////////////////////////////////////////////////////////////////
283
  if (Command == 0b00000010 && EmpfangeAufstromzeit == 1)
284
  {  cli();
285
    buesy = 1;
286
    PORTD &= ~(1<<PD2);      // ChipSelect low
287
    for (int i = 14;i<=19;i++)  
288
    {
289
      SPI_Senden(adc_write_config[i]);
290
    }
291
    
292
    PORTD |= (1<<PD2);      // ChipSelect high
293
    PORTC |=(1<<PC2);      // START pin of ADS high level
294
    PORTC &=~(1<<PC2);      // START pin low again
295
    
296
    AnzahlBytes = 5;
297
    Command = 0;
298
    buesy = 0;
299
    sei();
300
    USART_Senden(1);
301
  }
302
/////////////////////////////////////////////////////////////////////////////////////////////////////
303
if (Command == 0b00000011 && EmpfangeAufstromzeit == 1)
304
{  cli();
305
  buesy = 1;
306
  PORTD &= ~(1<<PD2);      // ChipSelect low
307
  for (int i = 20;i<=25;i++)
308
  {
309
    SPI_Senden(adc_write_config[i]);
310
  }
311
  
312
  PORTD |= (1<<PD2);      // ChipSelect high
313
  PORTC |=(1<<PC2);      // START pin of ADS high level
314
  PORTC &=~(1<<PC2);      // START pin low again
315
  
316
  AnzahlBytes = 5;
317
  Command = 0;
318
  buesy = 0;
319
  sei();
320
  USART_Senden(1);
321
}
322
/////////////////////////////////////////////////////////////////////////////////////////////////////
323
if (Command == 0b00000100 && EmpfangeAufstromzeit == 1)
324
{  cli();
325
  buesy = 1;
326
  PORTD &= ~(1<<PD2);      // ChipSelect low
327
  for (int i = 26;i<=31;i++)
328
  {
329
    SPI_Senden(adc_write_config[i]);
330
  }
331
  
332
  PORTD |= (1<<PD2);      // ChipSelect high
333
  PORTC |=(1<<PC2);      // START pin of ADS high level
334
  PORTC &=~(1<<PC2);      // START pin low again
335
  
336
  AnzahlBytes = 5;
337
  Command = 0;
338
  buesy = 0;
339
  sei();
340
  USART_Senden(1);
341
}
342
/////////////////////////////////////////////////////////////////////////////////////////////////////
343
if (Command == 0b10000000 && EmpfangeAufstromzeit == 1)
344
{  cli();
345
  buesy = 1;
346
  PORTD &= ~(1<<PD2);       // ChipSelect low
347
  for (int i = 32;i<=37;i++)
348
  {
349
    SPI_Senden(adc_write_config[i]);
350
  }
351
  
352
  PORTD |= (1<<PD2);      // ChipSelect high
353
  PORTC |=(1<<PC2);      // START pin of ADS high level
354
  PORTC &=~(1<<PC2);      // START pin low again
355
  
356
  AnzahlBytes = 5;
357
  Command = 0;
358
  buesy = 0;
359
  sei();
360
  USART_Senden(1);
361
}
362
/////////////////////////////////////////////////////////////////////////////////////////////////////    
363
if (Command == 0b01000000 && EmpfangeAufstromzeit == 1)
364
{  cli();
365
  buesy = 1;
366
  PORTD &= ~(1<<PD2);      // ChipSelect low
367
  for (int i = 38;i<=43;i++)
368
  {
369
    SPI_Senden(adc_write_config[i]);
370
  }
371
  
372
  PORTD |= (1<<PD2);      // ChipSelect high
373
  PORTC |=(1<<PC2);      // START pin of ADS high level
374
  PORTC &=~(1<<PC2);      // START pin low again
375
  
376
  AnzahlBytes = 5;
377
  Command = 0;
378
  buesy = 0;
379
  sei();
380
  USART_Senden(1);
381
}  
382
////////////////////////////////////////////////////////////////////////////////////////////////////
383
/////////////////////////////////////////////////////////////////////////////////////////////////////
384
if (Command == 0b11000000 && EmpfangeAufstromzeit == 1)
385
{  cli();
386
  buesy = 1;
387
  PORTD &= ~(1<<PD2);      // ChipSelect low
388
  for (int i = 44;i<=49;i++)
389
  {
390
    SPI_Senden(adc_write_config[i]);
391
  }
392
  
393
  PORTD |= (1<<PD2);      // ChipSelect high
394
  PORTC |=(1<<PC2);      // START pin of ADS high level
395
  PORTC &=~(1<<PC2);      // START pin low again
396
  
397
  AnzahlBytes = 5;
398
  Command = 0;
399
  buesy = 0;
400
  sei();
401
  USART_Senden(1);
402
}
403
////////////////////////////////////////////////////////////////////////////////////////////////////
404
/////////////////////////////////////////////////////////////////////////////////////////////////////
405
if (Command == 0b00100000 && EmpfangeAufstromzeit == 1)
406
{  cli();
407
  buesy = 1;
408
  PORTD &= ~(1<<PD2);      // ChipSelect low
409
  for (int i = 50;i<=55;i++)
410
  {
411
    SPI_Senden(adc_write_config[i]);
412
  }
413
  
414
  PORTD |= (1<<PD2);      // ChipSelect high
415
  PORTC |=(1<<PC2);      // START pin of ADS high level
416
  PORTC &=~(1<<PC2);      // START pin low again
417
  
418
  AnzahlBytes = 5;
419
  Command = 0;
420
  buesy = 0;
421
  sei();
422
  USART_Senden(1);
423
}
424
////////////////////////////////////////////////////////////////////////////////////////////////////
425
////////////////////////////////////////////////////////////////////////////////////////////////////
426
if (Command == 0b01010101 && EmpfangeAufstromzeit == 1)
427
{  
428
  EmpfangeAufstromzeit =0;
429
  UARTInterruptZaehler = 0;
430
  
431
  USART_Senden(1);
432
  Command = 0;
433
  x=0;
434
  y=0;
435
}
436
437
if (UARTInterruptZaehler == 1)
438
{
439
  
440
  AufstromzeitHB = Command;
441
  
442
  Aufstromzeit = (AufstromzeitHB << 8);
443
  while(y<1)
444
  {
445
  USART_Senden(1);
446
  y = y+1;
447
  }
448
  
449
  
450
}
451
if (UARTInterruptZaehler == 2)
452
{  
453
  AufstromzeitLB =  Command;
454
  Aufstromzeit = Aufstromzeit | AufstromzeitLB;
455
  //Aufstromzeit = ( AufstromzeitHB << 8 ) | AufstromzeitLB;
456
  
457
  while(x<1)
458
  {  
459
    USART_Senden(AufstromzeitHB);
460
    USART_Senden(AufstromzeitLB);
461
    x=x+1;
462
  }
463
}
464
if (UARTInterruptZaehler == 3)
465
{
466
  EmpfangeAufstromzeit = 1;
467
}
468
469
///////////////////////////////////////////////////////////////////////////////////////////////////  
470
471
///////////////////////////////////////////////////////////////////////////////////////////
472
if (Command == 0b00000101 && EmpfangeAufstromzeit == 1)
473
{  cli();
474
  buesy=1;
475
  PORTC |=(1<<PC5);
476
  long_delay(Aufstromzeit);
477
  PORTC &= ~(1<<PC5);
478
  
479
  Command = 170;
480
  sei();
481
  buesy = 0;
482
}  
483
    
484
if (AnzahlBytes == 5 && Command == 0b10101010 && EmpfangeAufstromzeit == 1)
485
  {  cli();
486
    Command=0;
487
    buesy=1;
488
    t=0;
489
    while(t==0)
490
    {
491
    PORTC |=(1<<PC2);      // START pin of ADS high level
492
    PORTC &=~(1<<PC2);      // START pin low again
493
    PORTD &= ~(1<<PD2);      //CS low
494
    
495
    for (int i=0; i<=4; i++)
496
    {
497
      SPI_Senden(adc_read_com[i]);
498
      register_status[i] = SPI_Empfangen();
499
      
500
    }
501
    
502
    
503
    
504
    for (int i=1;i<=4;i++)
505
    {  
506
      USART_Senden(register_status[i]);
507
    }
508
    t=t+1;
509
    }
510
    //Command=0;
511
    buesy=0;
512
    sei();
513
    }
514
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
515
    if (Command == 6 && EmpfangeAufstromzeit == 1 )
516
    {  Command = 0;
517
      z=0;
518
      cli();
519
      buesy=1;
520
      while (z==0)
521
      {
522
      USART_Senden(AufstromzeitHB);
523
      USART_Senden(AufstromzeitLB);
524
      z=z+1;
525
      }
526
      buesy = 0;
527
      sei();
528
    }
529
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
530
  }
531
  
532
  
533
}
534
535
ISR(USART_RX_vect)
536
  {
537
    UARTInterruptZaehler = UARTInterruptZaehler +1;
538
    if (UARTInterruptZaehler==11)
539
    {
540
      UARTInterruptZaehler = 10;
541
    }
542
    
543
    if (buesy == 0)
544
{
545
  Command = USART_Empfangen();
546
}
547
548
  }

von Thomas E. (thomase)


Lesenswert?

Hans D. schrieb:
> Übernimmt in dem Fall nicht der Befehl die Funktion der Präambel?
> Wie man das mit ASCII macht, verstehe ich nicht. Finde nirgendwo eine
> Anleitung dafür..

Jein.
Was sendest du? Die Zahl 85?

Die Zahl 85 gehört zum Textsatz des ASCII. Diese Codes werden auch nur 
dafür benutzt. Guck in deine ASCII-Tabelle, dann siehst du, wie das 
aufgebaut ist. Solltest du keine haben, nimm diese hier:

http://www.ascii-code.com/

Es gibt Steuercodes und Textcodes. Steuercodes sind die von 0 bis 31.
So, und jetzt ist Schluß mit dezimal. Da mußt du durch.

Steuercodes gehen von 0 - 0x1F.
Darstellbare Zeichen von 0x20 - 0x7F
Erweiterte darstellbare Zeichen von 0x80 - 0xFF

Für die Präambel benutzt man Zeichen aus dem Steuercode, für die Daten 
aus dem Textcode. Warum macht man das so? Damit Steuercodes nicht mit 
Daten verwechselt werden können. Das ist das A und O der Übertragung.

Die Übertragung beginnt also mit einem Steuerzeichen. Escape, 0x1B, wird 
dafür gerne genommen. Mit ein paar Ausnahmen, kann man aber auch jedes 
andere dafür nehmen. Bleiben wir mal bei Esc.

Darauf folgen die Daten. Wir übertragen den Wert 27. Nun hat die 
Dezimalzahl 27 die unangenehme Eigenschaft aus den gleichen Bits zu 
bestehen, wie unser Escape. Deswegen können wir das nicht so übertragen. 
Die Zahl in Hex umzuwandeln, 0x1B, nützt uns natürlich auch nichts.

Deswegen wird die Zahl in Text umgewandelt. Und zwar Nibble für Nibble. 
Spätestens jetzt ist definitiv Schluß mit Dezimalzahlen. Das Byte mit 
dem Inhalt 27 = 0x1B wird in zwei Zeichen umgewandelt:
Aus dem Highnibble  1 wird '1' und aus dem Lownibble B wird 'B'.

Hä?

1 ist die Zahl mit dem Wert 1. Also 1 Meter, 1 Apfel oder was weiß ich.
'1' ist in C die Schreibweise für das Zeichen 1, welches, wenn es 
gedruckt wird, vereinbarungsgemäß der Zahl 1 entspricht. B und 'B' 
entsprechend.

Jetzt guckst du in die Tabelle und siehst '1' hat den Code 0x31 und 'B' 
den Code 0x42. Diese beiden Codes werden jetzt statt der Zahl 27 
übertragen. Darauf folgt in gleicher Weise die Hexzahl B.

Die Umwandlung ist ganz einfach: Man addiert einfach zu dem Nibble die 
Zahl 0x30. Wenn diese Zahl dann größer als 0x39 ist, müssen nochmal 7 
hinzuaddiert werden. Um die Hexumwandlung brauchst du dich nicht zu 
kümmern. Die Zahl steht sowieso so im Register. Dezimal ist nur für uns 
wenn wir es lesen wollen.

Der gesamte Datensatz sieht jetzt also so aus:

0x1B   = Escape
0x31   = '1'
0x42   = 'B'
...
...
0x0A   = '\n'(Line Feed)

Der Empfänger macht zunächst nichts anderes als auf das Escape zu 
warten.
Hat er dieses empfangen, setzt er den Empfangszähler, -counter, 
-pointer, nenne es, wie du willst, auf 0 und schreibt die Bytes , die 
darauf folgen in einen Puffer. Der Puffer muß so groß, daß alles, was an 
Daten kommt, da reinpasst. Wenn er das 0x0A empfangen hat, setzt er ein 
Flag, das im Hauptprogramm abgefragt wird und dieses bearbeitet die 
Daten. Das mit dem Flag setzten, ist eine einfache Möglichkeit von 
vielen, das zu handhaben.

Soweit erstmal klar?

von Thomas E. (thomase)


Lesenswert?

Marc V. schrieb:
> Nein, lass es sein. Das sind die Tipps von Leuten, die keine
>  Ahnung haben, weil die so etwas noch nie implementiert haben.

Sprücheklopfer.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas E. schrieb:
> Sprücheklopfer.

 Nein, nur jemand der so etwas tatsächlich geschrieben und zum laufen
 gebracht hat.

 Warum sollte er 2 Bytes umrechnen, 6 Zeichen senden und empfangen,
 diese dann wieder zurückrechnen, wenn es mit nur 4 Bytes genausogut,
 sogar besser geht, weil kürzer und ohne Umrechnen ?

 P.S.
 Und, um dich zu zitieren:
Thomas E. schrieb:
> Denn die gebetsmühlenartig
> vorgetragene So-kurz-wie-möglich-Regel ist zwar nicht kompletter Unsinn,
> sollte aber einem, bezogen auf das gesamte Programm, "So kurz wie nötig"
> weichen.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Marc V. schrieb:
> Nein, nur jemand der so etwas tatsächlich geschrieben und zum laufen
>  gebracht hat.

Wow. Respekt!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas E. schrieb:
> Wow. Respekt!

 Keine Ursache.
 War noch im Vorschulalter.

von Arduinoquäler (Gast)


Lesenswert?

Mein Gott, entscheidend ist doch dass ein Protokoll verwendet
wird, ihr streitet jetzt darum welches es denn sein soll ....

Bin gespann wer Recht hat/bekommt ;-)

von Reinhard O. (kristian_1955)


Lesenswert?

Thomas E. schrieb:
> Der Empfänger macht zunächst nichts anderes als auf das Escape zu
> warten.
> Hat er dieses empfangen, setzt er den Empfangszähler, -counter,
> -pointer, nenne es, wie du willst, auf 0 und schreibt die Bytes , die
> darauf folgen in einen Puffer. Der Puffer muß so groß, daß alles, was an
> Daten kommt, da reinpasst. Wenn er das 0x0A empfangen hat, setzt er ein
> Flag, das im Hauptprogramm abgefragt wird und dieses bearbeitet die
> Daten. Das mit dem Flag setzten, ist eine einfache Möglichkeit von
> vielen, das zu handhaben.

Geht das in die richtige Richtung?
1
  int main(void)
2
    {
3
      while(UARTInterruptZaehler<=4)
4
    {
5
      if (UARTInterruptZaehler = 1)
6
      {
7
        Empfangsbuffer[0]=Command;
8
      }
9
      if (UARTInterruptZaehler = 2)
10
      {
11
        Empfangsbuffer[1]=Command;
12
      }
13
      if (UARTInterruptZaehler = 3)
14
      {
15
        Empfangsbuffer[2] =Command      
16
      }
17
    }
18
  }
19
20
  
21
22
23
ISR(USART_RX_vect)
24
  {  UARTInterruptZaehler=UARTInterruptZaehler + 1;
25
    Command = USART_Empfangen();
26
    if (Command == 0x1B)
27
    {
28
      UARTInterruptZaehler = 0;
29
    }
30
    if (Command == 0x0A)
31
    {
32
      dataready=1;
33
    }
34
  }

von ms (Gast)


Lesenswert?

Hallo Hans,

das einfachste und mit nur zwei Byte geht so.

uC im MPCM mode betreiben.
LabView sendet das erste Byte mit MARK Parity.
uC empfängt das Byte und schaltet das MPCM ab.
LabView sendet das zweite Byte mit SPACE Parity.
uC empfängt das Byte und schaltet das MPCM wieder an.

Das Mark Parity ist der eindeutige Start.

ms

von Arduinoquäler (Gast)


Lesenswert?

ms schrieb:
> Das Mark Parity ist der eindeutige Start.

Wird Zeit dass wir hier endlich die uint9_t / int9_t und
uint18_t / int18_t Datentypen salonfähig machen, wa?

von Georg (Gast)


Lesenswert?

Marc V. schrieb:
> Mach es mit: <SOF><LSB><MSB><EOF>
>  Das sind (und bleiben) immer 4 Byt.
>
>  <SOF> ist bei mir 0xAA, <EOF> ist 0xA9 und da gab es noch nie
>  irgendwelche Probleme damit.

Und was passiert, wenn die binären Nutzdaten zufällig 0xAA oder 0xA9 
sind??

Offensichtlich hast du selbst nicht die geringste Ahnung von einem 
zuverlässig funktionierenden Protokoll. Aber angeben wie der Gröpaz.

Georg

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Georg schrieb:
> Und was passiert, wenn die binären Nutzdaten zufällig 0xAA oder 0xA9
> sind??

 Nichts, werden richtig gedeutet, da vor den Daten schon ein 0xAA
 empfangen wurde und nach den Daten ein 0xA9 gekommen ist.

 Dein Protokoll zur Kommunikation mit dem Gehirn funktioniert wohl
 nicht, oder Gehirn nicht vorhanden ?


> Offensichtlich hast du selbst nicht die geringste Ahnung von einem
> zuverlässig funktionierenden Protokoll. Aber angeben wie der Gröpaz.

 Nein, aber das scheint bei dir der Fall zu sein. Auf jeden Fall hast
 du mit Sicherheit keine Ahnung.

von ms (Gast)


Lesenswert?

Arduinoquäler schrieb:
> Wird Zeit dass wir hier endlich die uint9_t / int9_t und
> uint18_t / int18_t Datentypen salonfähig machen, wa?

man muss sich nur zu helfen wissen.

ms

von Thomas E. (thomase)


Lesenswert?

Hans D. schrieb:
> ISR(USART_RX_vect)
>   {  UARTInterruptZaehler=UARTInterruptZaehler + 1;
>     Command = USART_Empfangen();
>     if (Command == 0x1B)
>     {
>       UARTInterruptZaehler = 0;
>     }
>     if (Command == 0x0A)
>     {
>       dataready=1;
>     }
>   }

Im Prinzip.

Aber für den Zähler interessiert sich eigentlich niemand.
1
volatile unsigned char Rbuf[4];
2
volatile unsigned char Ready = 0;
3
4
ISR(USART_RX_vect)
5
{
6
  static unsigned char ind = 0;
7
  unsigned char udr = UDR;
8
9
  switch(udr)
10
  {
11
    case 0x1B: ind = 0; break;
12
    case 0x0A: Ready = 1; break;
13
    default:
14
      RBuf[ind++] = udr;
15
      ind %= 4;
16
  }
17
}

: Bearbeitet durch User
von Georg (Gast)


Lesenswert?

Marc V. schrieb:
> Nichts, werden richtig gedeutet, da vor den Daten schon ein 0xAA
>  empfangen wurde und nach den Daten ein 0xA9 gekommen ist.

Dazu ist jeder sachliche Kommentar reine Zeitverschwendung. Dummheit 
siegt, wenn sie nur laut genug vorgetragen wird.

Georg

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc V. schrieb:
> Nichts, werden richtig gedeutet, da vor den Daten schon ein 0xAA
>  empfangen wurde und nach den Daten ein 0xA9 gekommen ist.

Das setzt aber voraus, dass beim Empfang bisher kein Byte verschluckt 
wurde. Damit führst Du dann aber auch den sicheren Empfang eines Frames 
ad absurdum und Du könntest damit auf Start- und Ende-Zeichen komplett 
verzichten, weils denselben Effekt hat - nämlich keinen.

Wenn die Start- und Ende-Zeichen auch in den Daten vorkommen, muss man 
sie entweder "escapen" durch ein Vorschaltzeichen, oder man muss 
sicherstellen, dass die beiden Zeichen in den eigentlichen Daten nicht 
vorkommen. Sonst kann man im Falle einer Fehlübertragung (z.B. 
verschlucktes Byte beim Empfangen) nicht mehr sicher am Anfang eines 
neuen Frames aufsetzen, um sich wieder zu synchronisieren. Wenn Du 
versuchst, auf das nächste 0xAA aufzusetzen, könnte es sein, dass Du 
mitten in den Daten aufsetzt. Und das ist ein Fehler. Ganz schlimm ist 
es, wenn dann im Datenstrom tatsächlich noch ein 0xA9 steckt. Wo ist 
Dein Frame dann zuende?

Ich kann Dir auch gern ein Beispiel konstruieren, wo es sicher 
fehschlägt. Aber ich nehme an, Du verstehst es auch so: Eine Sicherung 
einer Datenübertragung darf nicht eine korrekte Übertragung 
voraussetzen, denn sonst ist sie unnütz. Aber genau das machst Du.

: Bearbeitet durch Moderator
von Reinhard O. (kristian_1955)


Lesenswert?

Thomas E. schrieb:
> ber für den Zähler interessiert sich eigentlich niemand.
>
> volatile unsigned char Rbuf[4];
> volatile unsigned char Ready = 0;
>
> ISR(USART_RX_vect)
> {
>   static unsigned char ind = 0;
>   unsigned char udr = UDR;
>
>   switch(udr)
>   {
>     case 0x1B: ind = 0; break;
>     case 0x0A: Ready = 1; break;
>     default:
>       RBuf[ind++] = udr;
>       ind %= 4;
>   }
> }

Gut...deinen Code verstehe ich so:
Jedesmal, wenn ein Byte empfangen wird, wird die Variable "ind" = 0 
gesetzt und der Inhalte des Empfangsregisters in die Variable udr 
geschrieben. Die Variable ind wird dann bei jedem Interrupt um 1 erhöht. 
Irgendwann wird dann 0x1B empfangen und ind = 0 gesetzt. Das Byte das 
danach empfangen wird, wird dann in RBuf[1] gespeichert, das danach in 
RBuf[2], dann RBuf[3] und zum Schluss RBuf[4].
Wird 0x0A empfangen, wird Ready gleich 1 gesetzt.

Ready = 1 müsste dann in der while(1)-Schleife erkannt werden und der 
Empfangsbuffer ausgelesen werden?

von Thomas E. (thomase)


Lesenswert?

Hans D. schrieb:
> Jedesmal, wenn ein Byte empfangen wird, wird die Variable "ind" = 0
> gesetzt

Nein, nicht jedesmal. Das ist eine statische Variable. Die verhält sich 
wie eine globale Variable, nur daß man sie außerhalb der ISR nicht 
sieht.
Den Rest hast du richtig verstanden.

Du solltest die Lücken in deinen C-Kenntnissen schließen.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Ich kann Dir auch gern ein Beispiel konstruieren, wo es sicher
> fehschlägt. Aber ich nehme an, Du verstehst es auch so: Eine Sicherung
> einer Datenübertragung darf nicht eine korrekte Übertragung
> voraussetzen, denn sonst ist sie unnütz. Aber genau das machst Du.

 Das mag ich. Alle auf einen, dass die anderen Beispiele gar keine
 Fehlerprüfung haben, macht ja nichts. Erinnert mich an ein bestimmtes
 Tier aus Afrika, fängt mit H und endet mit e. Kann mich nicht mehr
 genau auf den Namen erinnern, aber egal, vielleicht kommt einer von
 Euch auf den Namen...

 Okay.
 Pseudocode auf die schnelle, so aus dem Kopf:
1
 const c_SOF = 0xAA
2
 const c_EOF = 0xA9
3
 const sofOK = 0
4
 const eofOK = 1
5
 
6
 RxPtr =0
7
 RxFlag = 0
8
9
main()
10
    while(RxFlag.eofOK <> 1)
11
12
13
 ISR:
14
  RxByt = UDDR
15
  if RxFlag.eofOK == 1 then return
16
  
17
  if RxFlag.sofOK == 0
18
   if RxByt == c_SOF then
19
     RxPtr = 0
20
     RxFlag = (1<<sofOK)
21
   endif
22
23
  else
24
   RxPtr++
25
   if RxPtr >= 3 then
26
     If RxByt <> c_EOF then
27
       RxFlag = 0            // Habe auch irgendwo eine Routine welche die
28
       RxPtr = 0             // schon empfangenen Bytes auf SOF prüft
29
     else
30
       RxFlag |= (1<<c_EOF)
31
     endif
32
    endif
33
  endif
34
  RxBuff[RxPtr] = RxByt
 Hier kann zwar ein ganzes Frame verlorengehen, aber aus dem Takt
 kann diese Rotine niemals kommen .
 Und mit der oben erwähnten Routine nichteinmal das.

 Und jetzt bitte ich um dein konstruiertes Beispiel.

von Reinhard O. (kristian_1955)


Lesenswert?

Thomas E. schrieb:
> Nein, nicht jedesmal. Das ist eine statische Variable. Die verhält sich
> wie eine globale Variable, nur daß man sie außerhalb der ISR nicht
> sieht.
> Den Rest hast du richtig verstanden.
>
> Du solltest die Lücken in deinen C-Kenntnissen schließen.

Mit den Lücken stimme ich dir zu. Bei den Dingen, die ich bisher so 
programmiert habe, bin ich mit meinen "Kenntnissen" zum Ziel gekommen.
Hier ist wohl eine Grenze erreicht.

Die empfangenen Daten würde ich dann so wieder decodieren?
1
while(1)
2
    { if (Ready = 1)
3
    {  Zeichen1 = Rbuf[1];
4
    Zeichen1 = Zeichen1 + 0x30;
5
    if(Zeichen1 > 0x39)
6
    {
7
      Zeichen1 = Zeichen1 + 7;
8
    }
9
    Zeichen2 = Rbuf[2];
10
    Zeichen2 = Zeichen2 + 0x30;
11
    if(Zeichen2 > 0x39)
12
    {
13
      Zeichen2 = Zeichen2 + 7;
14
    }
15
    Zeichen3 = Rbuf[3];
16
    Zeichen3 = Zeichen3 + 0x30;
17
    if(Zeichen3 > 0x39)
18
    {
19
      Zeichen3 = Zeichen3 + 7;
20
    }
21
    Zeichen4 = Rbuf[4];
22
    Zeichen4 = Zeichen4 + 0x30;
23
    if(Zeichen4 > 0x39)
24
    {
25
      Zeichen4 = Zeichen4 + 7;
26
    }
27
    
28
    Befehl = (Zeichen1<<24)|(Zeichen2<<16)|(Zeichen3<<8)|(Zeichen4);
29
    }

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Marc V. schrieb:
> else
>        RxFlag |= (1<<c_EOF)

 sollte
1
        RxFlag |= (1<<eofOK)
 heissen.

von vn nn (Gast)


Lesenswert?

Klaus schrieb:
> Warum sind wohl die meißten Protokolle im Internet ASCII?

Diese Behauptung halte ich gelinde gesagt für Blödsinn.

von Thomas E. (thomase)


Lesenswert?

Hans D. schrieb:
> Zeichen1 = Zeichen1 + 0x30;
>     if(Zeichen1 > 0x39)

Nein. So macht das im Prinzip der Sender.
Du empfängst für die Zahl 1 das Zeichen '1'. Also 0x31. Daraus mußt du
0x01 machen.

unsigned char AsciiToByte(char nH, char nL)
{
 if(nH & 0x40) nH += 9;
 if(nL & 0x40) nL += 9;
 return (nH << 4) + (nL & 0x0F);
}


Hans D. schrieb:
> Befehl = (Zeichen1<<24)|(Zeichen2<<16)|(Zeichen3<<8)|(Zeichen4);

Damit hast du ein lückenhaftes Long gebastelt.
1
  unsigned int Value = AsciiToByte(RBuf[3], RBuf[2]) << 8;
2
  Value += AsciiToByte(RBuf[1], RBuf[0]);


Die Byte-Reihenfolge ist jetzt:
RBuf[0] = Lowbyte Lownibble
RBuf[1] = Lowbyte Highnibble
RBuf[2] = Highbyte Lownibble
RBuf[3] = Highbyte Highnibble


Diese Reihenfolge ist grundsätzlich beliebig. Du solltest aber in jedem
deiner Programme dieselbe Reihenfolge verwenden. Sonst steigst du
spätestens beim übernächsten Programm nicht mehr durch.

Denn diese sehr einfache Empfangsroutine...
1
volatile unsigned char Rbuf[4];
2
volatile unsigned char Ready = 0;
3
4
ISR(USART_RX_vect)
5
{
6
  static unsigned char ind = 0;
7
  unsigned char udr = UDR;
8
9
  switch(udr)
10
  {
11
    case 0x1B: ind = 0; break;
12
    case 0x0A: Ready = 1; break;
13
    default:
14
      RBuf[ind++] = udr;
15
      ind %= 4;
16
  }
17
}

... lässt sich auch sehr einfach universell einsetzen:

1
#define MAX_DATA 13
2
volatile unsigned char Rbuf[MAX_DATA];
3
volatile unsigned char Ready = 0;
4
5
ISR(USART_RX_vect)
6
{
7
  static unsigned char ind = 0;
8
  unsigned char udr = UDR;
9
10
  switch(udr)
11
  {
12
    case 0x1B: ind = 0; break;
13
    case 0x0A: Ready = 1; break;
14
    default:
15
      RBuf[ind++] = udr;
16
      ind %= MAX_DATA;
17
  }
18
}


Damit kannst du Daten bis 13 Bytes Länge empfangen. Sind die Daten 
kürzer, wird nach z.B. 4 Bytes durch Ready das Ende signalisiert.

vn nn schrieb:
> Diese Behauptung halte ich gelinde gesagt für Blödsinn.

Dem kann man nicht widersprechen. ASCII ist ein Code und kein Protokoll. 
Dieser Code macht aber Protokolle sehr einfach.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas E. schrieb:
> Dieser Code macht aber Protokolle sehr einfach.

 Aha.
 Wenn die Computer lesen könnten.

 Ansonsten nimmt man CRC und hat ein Byte overhead anstatt doppelter
 Lange.

von vn nn (Gast)


Lesenswert?

Thomas E. schrieb:
> vn nn schrieb:
>> Diese Behauptung halte ich gelinde gesagt für Blödsinn.
>
> Dem kann man nicht widersprechen. ASCII ist ein Code und kein Protokoll.
> Dieser Code macht aber Protokolle sehr einfach.

Mein Kommentar bezog sich eher auf die Behauptung, dass die meisten 
Protokolle im Internet auf ASCII aufbauen würden, dass er es auch noch 
falsch ausgedrückt hat, hab ich überlesen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc V. schrieb:
> Hier kann zwar ein ganzes Frame verlorengehen, aber aus dem Takt
>  kann diese Rotine niemals kommen .

Hier das versprochene Beispiel:
1
Sender:
2
3
Sendet: <1234> <A9AA> <AAA9> <AAA9> <AAA9>
4
5
Frames:
6
7
Frame  Daten
8
============
9
1:     AA 12 34 A9
10
2:     AA A9 AA xx  : xx = A9, welches beim Empfang verschluckt wird.
11
3:     AA AA A9 A9
12
4:     AA AA A9 A9
13
5:     AA AA A9 A9
14
6:     ....
15
16
Empfänger sieht dann:
17
18
Frame   1  1  1  1        2  2  2  3        3   3  3  4      4   4  4  5    5   5    ...
19
Data    AA 12 34 A9       AA A9 AA AA       AA  A9 A9 AA     AA  A9 A9 AA   AA  A9   ...
20
RxPtr   0  1  2  3  ACK   0  1  2  NACK     0   1  2  NACK   0   1  2  NACK 0   1    ...

ACK: Frame als gültig erkannt
NACK: Frame wird verworfen

Lediglich 1 Byte wird verschluckt, nämlich das, welches ich oben mit xx 
gekennzeichnet habe. Danach ist Deine Empfängerroutine aus dem Takt und 
kann keinen einzigen der nachfolgenden Frames mehr erkennen.

: Bearbeitet durch Moderator
von S. R. (svenska)


Lesenswert?

vn nn schrieb:
>> Warum sind wohl die meißten Protokolle im Internet ASCII?
>
> Diese Behauptung halte ich gelinde gesagt für Blödsinn.

Die wichtigsten Dienste im Internet sind meiner Meinung nach Web (HTTP), 
Mail (IMAP, SMTP, POP3), Chat (XMPP = Jabber = Facebook-Chat = 
Google-Chat, IRC) und Telefonie (SIP). Das sind, wie die meisten offenen 
Standards, alles ASCII-Protokolle.

Verbreitete Binärprotokolle sind z.B. Skype, H.323 und RTP.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Lediglich 1 Byte wird verschluckt, nämlich das, welches ich oben mit xx
> gekennzeichnet habe. Danach ist Deine Empfängerroutine aus dem Takt und
> kann keinen einzigen der nachfolgenden Frames mehr erkennen.

 Ja.
 Nur ist das weitere senden von Daten zwecklos, da immer wieder die
 selben Daten kommen.
 Natürlich kann das bei ASCII nicht vorkommen, oder ?

 Auf deinem Prinzip basierend, kann ich dasselbe für jedes
 Protokoll konstruieren.

 Wie schon gesagt, man nimmt binär und CRC, wenn Zeichen dauernd
 "verschluckt" werden (wo passiert das ?).

 Oder man baut die Verbindung richtig auf, den mit richtiger Verbindung
 gibt es auch kein "Verschlucken" von Zeichen.

von Klaus (Gast)


Lesenswert?

S. R. schrieb:
> Verbreitete Binärprotokolle sind z.B. Skype, H.323 und RTP.

Wobei H323 auch noch gegen SIP verloren hat.

MfG Klaus

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

S. R. schrieb:
> Die wichtigsten Dienste im Internet sind meiner Meinung nach Web (HTTP),
> Mail (IMAP, SMTP, POP3), Chat (XMPP = Jabber = Facebook-Chat =
> Google-Chat, IRC) und Telefonie (SIP). Das sind, wie die meisten offenen
> Standards, alles ASCII-Protokolle.

 Tja, nur werden diese ASCII nicht RAW übertragen, sondern eingebettet.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc V. schrieb:
> Nur ist das weitere senden von Daten zwecklos, da immer wieder die
> selben Daten kommen.

Ich kann auch Beispiele mit variierenden Daten aufführen, wo Du mehr als 
einen Frame pro Übertragungsfehler wegwerfen musst. Das heisst, die 
Frameerkennungsrate sinkt auch so beträchtlich im Vergleich zu einem 
Protokoll, welches als Framebegrenzungen spezielle Sonderzeichen 
verwendet, die in den Daten selbst nicht vorkommen.

> Natürlich kann das bei ASCII nicht vorkommen, oder ?

Nein, da gibt es ein oder zwei Ende-Zeichen, in der Regel. NL oder CRNL. 
Diese kommen in den Daten nicht vor.

Beispiel:

1234 <NL>
A9AA <NL>
AAA9 <NL>
AAA9 <NL>
AAA9 <NL>

Bei einem Bytefehler geht max. ein Frame verloren.

Noch besser wäre das:

<STX> 1234 <ETX>
<STX> A9AA <ETX>
<STX> AAA9 <ETX>
<STX> AAA9 <ETX>
<STX> AAA9 <ETX>

Aber das ist etwas unleserlicher in einem Datenmitschnitt.

> Auf deinem Prinzip basierend, kann ich dasselbe für jedes
>  Protokoll konstruieren.

Konstruiere es bitte für ASCII <NL> oder <STX>...<ETX>

: Bearbeitet durch Moderator
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Zeig es mir :-)

 Nicht nötig, du weisst auch, dass so etwas ohne Probleme geht.
 Aber ich kann mir sinnvollere Sachen vorstellen, als mit Gewalt
 unrealistische Beispiele zu konstruieren.

 Wie man das Ganze Bulletproof macht, ist schon seit Jahrzehnten
 bekannt, hier ging es um ein Beispiel (von mir) wo Zeichen
 verschluckt werden und ein Beispiel (von anderen) wo Zeichen
 nicht verschluckt werden.

 Die Frage für den Deutschen:
  - Wie viele Leute sind in dem Bus ?
  - 1,2,3, ... 49.
  - Genau !!!
 Und die Frage für den Juden:
  - Und jetzt sagen Sie uns die Namen und Vornamen von diesen Leuten.

von ms (Gast)


Lesenswert?

Hallo,

es gibt leute die hier was lernen wollen. Ob man jetzt ASCII oder Binär 
verwendet kommt auf die Situation drauf an. Ich bin auch kein freund von 
ASCII aber hier in diesem fall scheint es passend zu sein.

@Moderator
ein Moderator sollte das Ziel (Fragestellung) nicht aus den Augen 
verlieren.
Er lenkt das gespräch gezielt auf eine Lösung hin und nicht zu einer 
Diskussion. Punkt.

ms

von Reinhard O. (kristian_1955)


Lesenswert?

Soweit habe ich es jetzt verstanden:

Es soll zum Beispiel 5000(dezimal) übertragen werden.
1. Schritt: 5000 --> 0x1388
2.Jede einzelne Ziffer als Zeichen betrachten und in der ASCII Tabelle 
die entsprechende Hexadezimalzahl raussuchen.
3. Folgenden Frame an den uC senden um 5000 zu übertragen:
0x1B
0x38
0x38
0x33
0x31
0x0A

Dank der Hilfe von Thomas Eckmann (vielen Dank, das hätte ich allein auf 
keinen Fall geschafft), bin ich jetzt soweit, dass ich mit HTerm Frames 
mit dem gegebenen Aufbau an den uC senden kann und diese wieder 
decodiert werden.

Wie gehts jetzt am besten weiter?
Wie übertrage ich das jetzt am besten auf mein altes Programm sodass ich 
möglichst wenig ändern muss.
Jetzt müsste ich doch 85(dez.) zunächst so codiert an den uC senden und 
im Anschluss daran meinen 16 Bit Wert, den ich in eine bestimmte 
Variable schreiben möchte oder?

Vielen Dank an alle und ein schönes Wochenende:)

: Bearbeitet durch User
von Joe F. (easylife)


Lesenswert?

MIDI war gar kein so schlechtes Beispiel.
Man könnte das oberste Bit als Sync-Bit nehmen, und pro byte einfach nur 
7 Datenbit übertragen.
Dann käme man mit 3 Byte pro Übertragung aus.
Sinngemäß:
1
void    uart_tx_byte(uint8_t x);
2
uint8_t uart_rx_byte();
3
4
void send_16_bit(uint16_t data)
5
{
6
  uart_tx_byte(0x80 | (data >> 9));
7
  uart_tx_byte(0x7F & (data >> 2));
8
  uart_tx_byte(0x7F & (data << 5));
9
}
10
11
uint16_t receive_16_bit()
12
{
13
  uint16_t data;
14
  uint8_t  b=0;
15
  
16
  while (! (b & 0x80))
17
    b = uart_rx_byte();
18
    
19
  data =  (uint16_t)(b) << 9;
20
  
21
  b = uart_rx_byte();
22
  data |= (uint16_t)(b) << 2;
23
  
24
  b = uart_rx_byte();
25
  data |= (uint16_t)(b) >> 5;
26
  
27
  return data;
28
}

von Forist (Gast)


Lesenswert?

Hans D. schrieb:
> #define F_CPU 18432000
> ...

Was verstehst du unter C-Datei?

Ist die Forumsfunktion zum Senden von Dateianhängen schon wieder kaputt?

von Thomas E. (thomase)


Lesenswert?

Hans D. schrieb:
> Wie gehts jetzt am besten weiter?

Du dekodierst deine Daten im Hauptprogramm. Das Befehlsbyte liegt vor 
den Daten. Dieses kommt in eine Variable(unsigned char) und die 
eigentlichen Daten in eine andere Variable(unsigned int). Und dann 
wertest du das aus:

1
if(Befehlsbyte == 85)
2
{
3
//  tu was
4
}

oder
1
switch(Befehlsbyte)
2
{
3
 case 0:
4
  //tu dies 
5
  break;
6
 case 1:
7
  //tu das
8
  break;
9
 case 85:
10
  //tu jenes
11
  break;
12
}

Alles im Hauptprogramm oder in Funktionen, die aus dem Hauptprogramm 
aufgerufen werden.

von S. R. (svenska)


Lesenswert?

Marc V. schrieb:
>> Die wichtigsten Dienste im Internet sind meiner Meinung nach Web (HTTP),
>> Mail (IMAP, SMTP, POP3), Chat (XMPP = Jabber = Facebook-Chat =
>> Google-Chat, IRC) und Telefonie (SIP). Das sind, wie die meisten offenen
>> Standards, alles ASCII-Protokolle.
>
>  Tja, nur werden diese ASCII nicht RAW übertragen, sondern eingebettet.

Weil das Internet Protocol ein Binärprotokoll ist, ist ein 
ASCII-Protokoll im Internet logisch unmöglich? Unfug schreibst du ja 
öfter, aber ich wüsste manchmal gerne, warum.

Hans D. schrieb:
> Es soll zum Beispiel 5000(dezimal) übertragen werden.

Ja. Das geht am einfachsten, indem du die Dezimalzahl ziffernweise als 
Text überträgst und z.B. mit einem Endezeichen abschließt.

Dein Frame besteht also aus den Bytes { '5', '0', '0', '0', '\n' } oder, 
in hexadezimaler Darstellung { 0x35, 0x30, 0x30, 0x30, 0x0A }. (Beide 
Darstellungen sind exakt gleich.)

> 1. Schritt: 5000 --> 0x1388

Du willst eine Dezimalzahl übertragen.
Warum wandelst du sie dann in Hex um? Ist doch nur Arbeit!

> 2.Jede einzelne Ziffer als Zeichen betrachten und in der ASCII Tabelle
> die entsprechende Hexadezimalzahl raussuchen.

Wenn du eine Zahl in eine Zeichenkette umgewandelt hast, dann ist jedes 
Zeichen darin (abzüglich dem Nullbyte am Ende) eine Ziffer. Jede Ziffer 
liegt bereits nach Tabelle passend codiert vor.

> 3. Folgenden Frame an den uC senden um 5000 zu übertragen:
> 0x1B -- ESC
> 0x38 -- '8'
> 0x38 -- '8'
> 0x33 -- '3'
> 0x31 -- '1'
> 0x0A -- '\n'

Erstens überträgst du damit die Hexadezimaldarstellung, ohne sie zu 
markieren (üblicherweise markiert man sowas mit einem "0x"-Präfix).

Zweitens überträgst du die Zahl rückwärts und machst es damit dem 
empfandenden System schwerer, sie zu dekodieren.

Thomas hat vollkommen Recht und Marc schreibt mal wieder halbgaren 
Unfug.

Wenn deine Kommunikation immer aus "Befehl Parameter Parameter" besteht, 
dann kannst du dein Protokoll auch so definieren:
- ASCII-Zahl ( Leerzeichen ASCII-Zahl )wiederholen Zeilenende

Also "85 17 32 535\n" bedeutet dann "Befehl 85 mit den Parametern 17, 32 
und 535". Dein Empfangscode schreibt also so lange Bytes in einen 
Puffer, bis ein "\n" kommt und übergibt die gesamte Zeile auf einmal an 
eine Auswertefunktion. Die zerlegt die Zeile dann in die Stücke.

von M. K. (sylaina)


Lesenswert?

S. R. schrieb:
> Ja. Das geht am einfachsten, indem du die Dezimalzahl ziffernweise als
> Text überträgst und z.B. mit einem Endezeichen abschließt.

Nope, am einfachsten geht das indem man die zwei Bytes überträgt und das 
ist dann auch noch schneller.
Sender macht:

LowByte = 5000 & 0xff;
HighByte = (5000 >> 8) & 0xff;

Empfänger macht:

LowByte = EmpfangsByte;
HighByte = EmpfangsByte << 8;

Value = HighByte | LowByte;

Und mit einem geeigneten Protokoll weiß man was wann gesendet wird bzw. 
angekommen ist.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

S. R. schrieb:
> Weil das Internet Protocol ein Binärprotokoll ist, ist ein
> ASCII-Protokoll im Internet logisch unmöglich? Unfug schreibst du ja
> öfter, aber ich wüsste manchmal gerne, warum.

 Einen ASCII-Protokoll gibt es nicht.
 Das, wovon du redest sind Nutzdaten, es ist absolut uninteressant ob
 da ASCII-Zeichen oder binäre Daten übertragen werden.
 Schreib nicht wieder so einen Unfug bitte, du machst dich nur immer
 wieder lächerlich mit deinem Halbwissen.

S. R. schrieb:
> Thomas hat vollkommen Recht und Marc schreibt mal wieder halbgaren
> Unfug.

 Erstens ist das nicht wahr und zweitens ist das, was ich vorgeschlagen
 habe weder die einzig richtige Methode, noch habe ich geschrieben,
 dass der Thomas Unrecht hat und seine Methode falsch ist.

 Was willst du also beweisen (ausser deinem Unwissen und notorischem
 rumhaken an mir weil ich klüger und wahrscheinlich auch schöner bin) ?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

ms schrieb:
> es gibt leute die hier was lernen wollen.
> Ob man jetzt ASCII oder Binär
> verwendet kommt auf die Situation drauf an.

Das sehe ich genauso.

> Ich bin auch kein freund von
> ASCII aber hier in diesem fall scheint es passend zu sein.

Auch hier stimme ich Dir zu. Der mögliche Wertebereich liegt bei max. 5 
Ziffern, ist zudem portabel und ist unabhängig von Endianess des Senders 
oder Empfängers.

> @Moderator
> ein Moderator sollte das Ziel (Fragestellung) nicht aus den Augen
> verlieren.
> Er lenkt das gespräch gezielt auf eine Lösung hin und nicht zu einer
> Diskussion. Punkt.

Das allerdings sehe ich anders. Auch die Anregung zu einer Diskussion 
kann zu einer Führung der Teilnehmer auf den richtigen Weg führen und 
hat sogar noch einen gewissen Vorteil: die Teilnehmer können sich die 
Lösung selbst erarbeiten.

Aber so oberlehrerhaft möchte ich das ganze gar nicht aufhängen: auch 
ich bin in der Regel ein ganz normaler Forumsteilnehmer, der sich hier 
gerne an solchen Diskussionen beteiligen möchte.

Aus meiner Erfahrung mit IR-Protokollen kann ich jedoch beurteilen, dass 
eine Rahmung des Frames mit einer Präambel, die selbst nicht in den 
Nutzdaten vorkommen kann,  zu einer erheblichen Verbesserung der 
Kommunikationssicherheit führt. Genau das wollte ich mit meinen 
Beiträgen als Erwiderung auf Marcs 0xAA-0xA9-Lösung zum Ausdruck 
bringen.

Ich sehe daher keinen Grund zur Aufregung.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc V. schrieb:
> Nicht nötig, du weisst auch, dass so etwas ohne Probleme geht.

Sorry, Marc. An dieser Stelle kann ich Dir nicht folgen. Ich habe es 
versucht, aber ich kann beim besten Willen bei dem einfachen 
zeilenweisen Protokoll,

12345 <NL>
23456 <NL>
34567 <NL>
...

wo ein simples Newline-Zeichen, welches selbst in den Nutzdaten nicht 
vorkommen kann, lediglich einen einzigen Frame durch Wegnehmen, 
Hinzufügen oder Kippen eines Bits im Datenstrom kaputtmachen - mehr 
nicht.

Ich bekomme es nicht hin, hier mehr als einen Frame zu zerstören.

> Aber ich kann mir sinnvollere Sachen vorstellen, als mit Gewalt
> unrealistische Beispiele zu konstruieren.

Bei dem Beispiel ging es um das Vorkommen der Präambel/Postambel in den 
Nutzdaten, was durchaus bei Deinem 0xAA-0xA9-Protokoll vorkommen kann. 
Genau das habe ich durchexerziert. Dabei kann man leicht zeigen, dass 
durch genau einen Übertragungsfehler, ein, zwei oder mehr Frames 
zerstört werden. Zugegebenermaßen war mein Beispiel der Worst-Case, der 
passieren kann. Aber es gibt noch jede Menge andere mögliche 
Kombinationen, die mehr als einen Frame dabei kaputtmachen. Allein die 
theoretische Möglichkeit sollte einen davon abbringen, solch eine Lösung 
zu wählen. Murphy existiert!

Ich beschäftige mich schon seit vielen Jahren mit 
Kommunikationsprotokollen, zudem habe ich mit der Entwicklung von 
IRMP und der Dekodierung von mittlerweile 50 IR-Protokollen jede 
Menge Erfahrung sammeln können. Das Fazit daraus: Ohne eine 
ausgezeichnete Präambel wird es verdammt schwierig, die Daten sicher 
sicher zu extrahieren. Da habe ich schon immer die Entwickler des 
Denon-Protokolls verflucht. Alle anderen mir bekannten Protokolle 
arbeiten da glücklicherweise anders.

Okay, eine ausgezeichnete Präambel ist eher wichtig bei 
Übertragungswegen, bei denen es bei Übertragungspausen zu vermehrten 
Rauschen kommen kann. Das ist eher bei Funk und bei IR der Fall. Bei 
UART-Übertragung kann man darauf verzichten, daher ist dort nicht 
unbedingt eine Form von

    <STX>Data<ETX>

notwendig. Hier reicht daher ein Trenner per Postambel, zum Beispiel das 
einfache Newline. Wichtig ist aber auch hier, dass dieses Zeichen nicht 
in den Nutzdaten vorkommt.

: Bearbeitet durch Moderator
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Kommunikationssicherheit führt. Genau das wollte ich mit meinen
> Beiträgen als Erwiderung auf Marcs 0xAA-0xA9-Lösung zum Ausdruck
> bringen.

 Es ist keine Lösung, natürlich. Es war nur ein Vorschlag, nur wusste
 ich damals noch nicht, dass die Verbindung bei binärer Übertragung
 so schlecht ist, bei ASCII-Zeichen aber einwandfrei funktioniert,
 sonst hätte ich gleich CRC oder Checksum vorgeschlagen...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc V. schrieb:
> Es ist keine Lösung, natürlich. Es war nur ein Vorschlag, nur wusste
> ich damals noch nicht, dass die Verbindung bei binärer Übertragung
> so schlecht ist, bei ASCII-Zeichen aber einwandfrei funktioniert,
> sonst hätte ich gleich CRC oder Checksum vorgeschlagen...

Eine ausgezeichnete Präambel/Postambel schützt natürlich noch lange 
nicht vor gefälschten Daten. Sie hilft nur bei der Eingrenzung der 
Frames. Wer hier auch noch eine gewisse Datensicherheit innerhalb der 
Frames möchte, kommt natürlich nicht um die zusätzliche Übertragung von 
redundanten Daten herum. Die damit verbundene Erhöhung der 
Datensicherheit ist mathematisch berechenbar. Ein Paritätsbit ist dabei 
die geringstmögliche Erhöhung (fifty-fifty, also 1/2), eine CRC8 erhöht 
die Sicherheit immerhin schon auf 255/256. Und so weiter...

: Bearbeitet durch Moderator
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Sorry, Marc. An dieser Stelle kann ich Dir nicht folgen. Ich habe es
> versucht, aber ich kann beim besten Willen bei dem einfachen
> zeilenweisen Protokoll,
>
> 12345 <NL>
> 23456 <NL>
> 34567 <NL>

 Normalerweise ja.
 Aber diese von mir konstruierte Verbindung ist ein bisschen komisch
 - es wird genau der <NL> verschluckt und das auch nur wenn
 ASCII-Zeichen übertragen werden - bei binären Werten funktioniert die
 Übertragung ausgezeichnet :)


> Ich beschäftige mich schon seit vielen Jahren mit
> Kommunikationsprotokollen

 Ich auch, deswegen schrieb ich, dass ich da noch eine Routine habe,
 welche bei auftretendem Fehler die schon empfangenen Bytes nach SOF
 abklappert und dann von dort wieder anfängt.
 Und es ist sehr, sehr selten, dass mit UART/RS485/CAN ein Byte
 verschluckt wird - falsch empfangen ja, dann aber mit Frame error
 und der CRC oder Checksum stimmt dann auch nicht mehr.

 Bei IR vielleicht möglich, da habe ich wenig bis Null Erfahrung.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc V. schrieb:
> bei binären Werten funktioniert die Übertragung ausgezeichnet :)

Bei binären Werten ist es natürlich auch um das Newline schlecht 
bestellt. Bei reiner ASCII-Übertragung (d.h. der Übertragung von 
druckbaren 7-Bit-Zeichen) klappt natürlich auch die Übertragung mit 
<AA>...<A9>, da der Wertebereich der Daten hier nur maximal von 0x20 bis 
0x7E geht.

Bei binären Daten, welche zudem auch noch eine variable Länge haben, 
kann man sich natürlich auch einen Frame-Trenner aussuchen, der dann in 
den Daten selbst "escaped" wird.

Beispiel:

Wir benutzen als Frame-Trenner das Newline <NL>, oder auch Linefeed <LF> 
(0x0A) genannt. Kommt es in den Daten selbst vor (binäre Übertragung), 
dann wird ein <ESC> (0x1B) vorangestellt. Kommt das <ESC> in den Daten 
vor, wird es verdoppelt.

Aus dem Datenstrom <ESC> wird also <ESC><ESC>, aus <LF> wird <ESC><LF>. 
Alle anderen Zeichen werden 1:1 ausgegeben und am Ende des Frames mit 
<LF> terminiert. Man muss jedoch auf der Empfängerseite darauf achten, 
dass die Datengröße eines Frames sich im Worst-Case verdoppeln kann.

Diese Methode benutzten in der Vergangenheit schon Modem-Protokolle wie 
Kermit, X-Modem und wie sie alle hießen, um Binärdaten zu übertragen.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Die oben genannte Methode, Frametrenner selbst zu "escapen", kann man 
natürlich auch in C übersetzen:
1
#define ESC  0x1B
2
#define LF   0x0A
3
4
void put16 (uint16_t w)
5
{
6
   uint8_t h = w >> 8;
7
   uint8_t l = w & 0xFF;
8
9
   if (h == ESC || h == LF)
10
   {
11
       putc (ESC);
12
   }
13
14
   putc (h);
15
16
   if (l == ESC || l == LF)
17
   {
18
       putc (ESC);
19
   }
20
21
   putc (l);
22
23
   putc (LF);
24
}

(Der Code ist ungetestet hier reingetippt, ohne Gewähr auf Tippfehler)

Hier wird das obere Byte zuerst übertragen, dann das untere Byte. Das 
kann man natürlich auch umdrehen. Die Framelänge wird durch das 
"escapen" variabel, d.h. sie kann zwischen 3 und 5 Bytes betragen.

Die Empfängerroutine überlasse ich dabei dem geneigten Leser :-)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Aus dem Datenstrom <ESC> wird also <ESC><ESC>, aus <LF> wird <ESC><LF>.
> Alle anderen Zeichen werden 1:1 ausgegeben und am Ende des Frames mit
> <LF> terminiert.

 Ohne jetzt endlos auf verschiedenen Vorteilen und Nachteilen
 rumreiten zu wollen, aber ich mache es seit langem so:

 <SOF><RcvAdr><SndAdr><Len><Cmnd><Data>...<CRC><EOF>

 Habe die entsprechenden Bibliotheken geschrieben, brauche nicht mehr
 darüber nachzudenken, wird einfach eingebunden.
 Funktioniert ohne irgendwelche Probleme. Fehler werden erkannt und
 (fast alle) selbständig in der Routine behandelt - nochmaliges senden,
 automatische Bestätigung und ähnlich.

 Aber ob es sich lohnt, so etwas für 2 Bytes zu schreiben, ist eine
 ganz andere Frage.

 Eine Pause zwischen 2 Blocks würde es auch ohne weiteres tun, da
 könnte man in der Timerroutine ganz einfach den Flag für ein neues
 Packet setzen...

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Marc V. schrieb:
> Ohne jetzt endlos auf verschiedenen Vorteilen und Nachteilen
>  rumreiten zu wollen, aber ich mache es seit langem so:

Ohne Frage, wenn man die obige put16()-Funktion um beliebige Datenmengen 
plus zusätzlicher CRC erweitern will, wird man irgendwann auf dieselbe 
oder zumindest ähnliche Form kommen, die Du mit

>  <SOF><RcvAdr><SndAdr><Len><Cmnd><Data>...<CRC><EOF>

skizziert hast. Dabei kann <Data> auch eine "escaped" Form sein, was 
dann im Ganzen gesehen die höchstmögliche Frame- und Datensicherheit 
bringen kann.

Bei lediglich 16-Bit-Daten ist das jedoch wie Kanonen auf Spatzen.

> Eine Pause zwischen 2 Blocks würde es auch ohne weiteres tun, da
> könnte man in der Timerroutine ganz einfach den Flag für ein neues
> Packet setzen...

Ich bin kein Freund davon. Stecken zwischen Sender und Empfänger 
irgendwelche Repeater, Medienwandler (z.B. UART-IP-UART-Brücke) oder 
ähnliches, ist das Zeitverhalten schlecht vorhersehbar. Da müsste man 
die Pausen schon arg lang machen, um sich sicher zu sein. Das drückt 
aber die Datenrate.

: Bearbeitet durch Moderator
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
> Ich bin kein Freund davon. Stecken zwischen Sender und Empfänger
> irgendwelche Repeater, Medienwandler (z.B. UART-IP-UART-Brücke) oder

 Ich auch, aber der TO hat dieses Problem ganz eindeutig nicht ;)

 Bei ihm würde eine Pause von etwa 3-4 Bytes vollkommen reichen.

von S. R. (svenska)


Lesenswert?

Marc V. schrieb:
>  Einen ASCII-Protokoll gibt es nicht.

Stimmt, denn es wäre "ein ASCII-Protokoll", weil Substantiv Neutrum.

>  Das, wovon du redest sind Nutzdaten, es ist absolut uninteressant ob
>  da ASCII-Zeichen oder binäre Daten übertragen werden.

Nö. Bei HTTP sende ich einen Header, gefolgt von den eigentlichen 
Nutzdaten. Der Header hingegen besteht laut Standard ausschließlich 
aus ASCII-Zeichen (inklusive CR und LF).

Die Nutzdaten dürfen beliebige binäre Daten sein *und sind 
selbstverständlich nicht Teil des Protokolls*, denn das Protokoll sagt 
über deren Struktur nichts aus. (Sie sind aber Teil der Kommunikation.)

Da das Protokoll ausschließlich ASCII-Zeichen verwendet, spricht man von 
einem ASCII-basiertem Protokoll. Und die haben Vor- und Nachteile.

Du darfst das in deiner Welt natürlich jederzeit so umdefinieren, wie du 
möchtest, aber dann musst du damit leben, dass andere dir vorwerfen, 
Unfug zu schreiben.

Ich wäre dann damit raus, da der Marc ja laut eigener Aussage der 
klügste und schönste Unfugerzähler von allen ist. Merkt man ja auch 
daran, dass seine Aussagen grundsätzlich und vor allem hier auf 
vollständige Zustimmung stoßen.

von Georg (Gast)


Lesenswert?

Frank M. schrieb:
> Bei binären Werten ist es natürlich auch um das Newline schlecht
> bestellt.

Deine vollkommen erfolglosen Versuche, Marc klarzumachen, dass 
eindeutige Trennzeichen in den Daten nicht vorkommen dürfen, weil sie 
dann eben nicht mehr eindeutig sind, beweist nur eines:

Auch beim Programmieren hat das postfaktische Zeitalter begonnen.

Georg

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

S. R. schrieb:
>>  Einen ASCII-Protokoll gibt es nicht.
>
> Stimmt, denn es wäre "ein ASCII-Protokoll", weil Substantiv Neutrum.

 Tja, ich bin kein Deutscher, das ist nicht meine Muttersprache, ich
 benutze es in der letzten Zeit praktisch nur hier, im Forum.
 Im übrigen verweise ich auf Mark Twain und seine Bemerkungen dazu.

>>  Das, wovon du redest sind Nutzdaten, es ist absolut uninteressant ob
>>  da ASCII-Zeichen oder binäre Daten übertragen werden.
>
> Nö. Bei HTTP sende ich einen Header, gefolgt von den eigentlichen
> Nutzdaten. Der Header hingegen besteht laut Standard ausschließlich
> aus ASCII-Zeichen (inklusive CR und LF).

 Nö - Nein - No - Nada - Njet.
 Der Header, inclusive ev. Nutzdaten muss erst beim Empfänger ankommen.
 Dazu wird das Ganze in einem (oder mehreren) Paketen verschickt.
 Wenn dieser Paket beim Empfänger angekommen ist, sind sowohl der Header
 als auch ev. Nutzdaten 100% fehlerfrei.
 Das wird durch den benutzten Protokoll garantiert.

 Insofern ist es absolut uninteressant, ob da ASCII oder binary
 übertragen wird.

 Ist hoffe, dir ist das Ganze jetzt ein bisschen klarer geworden,
 obwohl, viel Hoffnung habe ich nicht...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Georg schrieb:
> Deine vollkommen erfolglosen Versuche, Marc klarzumachen, dass
> eindeutige Trennzeichen in den Daten nicht vorkommen dürfen, weil sie

 Du hast doch schon gezeigt, dass du ein Moron bist, musst du das
 immer wieder beweisen ?
 Und warum erklärst du es hier, warum schreibst du nicht die Firmen,
 die sich mit Protokollen beschäftigen und davon leben ?

 Vielleicht sehen diese ihren Fehler ein, gehen zu ASCII rüber und
 du wirst reich und berühmt?

: Bearbeitet durch User
von Werner M. (Gast)


Lesenswert?

Marc V. schrieb:
> Das, wovon du redest sind Nutzdaten, es ist absolut uninteressant ob
>  da ASCII-Zeichen oder binäre Daten übertragen werden.

Das kommt wohl ganz schwer auf das Protokoll drauf an. Wenn das 
spezielle Steuerzeichen für die Synchronisation verwendet, z.B. für 
Start einen Datenblocks, kann es durchaus passieren, dass diese 
Steuerzeichen nicht anderweitig im Datenstrom auftauchen dürfen, bzw. 
mittels zusätzlicher Escape Sequenz markiert werden müssen. Es sei denn, 
man baut zusätzlichen Protokolloverhead ein, um sich dagegen zu 
schützen. Bei reinen ASCII-Daten kannst du Codes für Daten und Steuerung 
trennen, bei Binärdatenübertragung nicht.

Früher (tm) hat man für eine saubere Synchronisation bei Übertragung von 
16-Bit Binärdaten einfach 3 Byte übertragen, in jedem Byte ein Bit für 
die Synchronisation (S/s) reserviert und dann sogar noch Platz für eine 
Datensatzkennung/Adresse (a) mit 6 Bit, also z.B.
1
1        2        3
2
Saaaaaad sddddddd sddddddd
Das Synchronisationsbit wird beim ersten Byte auf 1 (S) gesetzt und beim 
zweiten und dritten auf 0 (s).

Heutzutage ist das bei nahezu unbegenzter Datenrate wohl zu einfach und 
Protokollökonomie nicht sonderlich gefragt.

Mit weniger Overhead kann man bei diesen Simpelprotokoll aus, wenn man 
die Daten zu größeren Blöcken zusammenfasst und auf die Adressbits 
verzichtet, also bei einem Nutzdatenblock mit 7 oder 14 Bytes.

von M. K. (sylaina)


Lesenswert?

Ist schon lustig zu lesen, bin mal gespannt wie lange es noch dauert bis 
einer von euch erkennt, dass ihr beide recht habt und gezielt aneinander 
vorbei redet.

von Conny G. (conny_g)


Lesenswert?

Die Diskussion über Protokolle ist das Eine.

Aber die Ursache für die vermutlich gedroppten Bytes ist das andere.

Einmal: wenn die serielle Übertragung mit Parity konfiguriert ist, wie 
ist das bei UART auf der Empfängerseite, das Byte wird einfach 
verworfen?
Oder bekommt man das Byte trotzdem?

Ansonsten die Zuverlässigkeit der Verbindung:
Welche Baudrate, wie lange ist das Kabel und ist es geschirmt?
Ich finde es etwas seltsam dass so häufig etwas verschluckt wird.
Ich verwende mit uCs jede Menge serielle Übertragung und wenn man 
Baudrate etc passen sehe ich quasi nie falsche Bytes.

Damit meine ich jetzt nicht, dass es das Protokoll nicht braucht.
Aber ich meine da wurde ein Schritt übersprungen, die Verbindung 
zuverlässig genug zu machen.
Denn wenn am Ende nur 80% durchkommen ist das ja auch Mist.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

M. K. schrieb:
> Ist schon lustig zu lesen, bin mal gespannt wie lange es noch dauert bis
> einer von euch erkennt, dass ihr beide recht habt

 Kaum.
 Wenn das Ganze so rausgesendet würde, hätte er recht und ich nicht.
 Da dies aber nicht der Fall ist...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Conny G. schrieb:
> Einmal: wenn die serielle Übertragung mit Parity konfiguriert ist, wie
> ist das bei UART auf der Empfängerseite, das Byte wird einfach
> verworfen?
> Oder bekommt man das Byte trotzdem?

 Man bekommt es, nur wird der Flag PE gesetzt (für Parity Error).

> Denn wenn am Ende nur 80% durchkommen ist das ja auch Mist.

 Selbstverständlich.
 Und die ganze Diskussion über Trennzeichen und ähnliches auch.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Conny G. schrieb:
> Einmal: wenn die serielle Übertragung mit Parity konfiguriert ist, wie
> ist das bei UART auf der Empfängerseite, das Byte wird einfach
> verworfen?

Kommt drauf an. Bei den AVRs kann - wie von Marc beschrieben - das Byte 
trotzdem ausgeliefert werden. Bei Paritätsfehlern wird dann ein Flag 
gesetzt, welches man vor dem Lesen aus UDR checken muss. Bei anderen 
Systemen wie zum Beispiel Unix/Linux werden die Daten mit Parity-Error 
einfach verworfen.

> Oder bekommt man das Byte trotzdem?

Du bekommst es auf jeden Fall, wenn Du auf der Empfängerseite den UART 
ohne Parity, aber mit Anzahl Datenbits + 1, einstellst.

Beispiel:

  Sender 7E1
  Empfänger: 8N1

Dann kannst Du selbst entscheiden, ob Du das Paritätsbit auswerten 
willst oder nicht. Aber Du musst es auf jeden Fall aus den Daten 
rausmaskieren.

Ich benutze das an ATmegas mit vorgeschaltetem Multiplexer. Dort können 
dann Geräte wie z.B. Barcode-Leser sowohl mit 8N1 als auch mit 7E1 
angeschlossen werden. Auf Empfängerseite (ATmega) ist immer 8N1 
eingestellt und ich entscheide selbst über das Paritätsbit.

> Ich finde es etwas seltsam dass so häufig etwas verschluckt wird.

Das passiert meist dann, wenn man keinen oder einen zu kleinen 
Ringbuffer auf der Empfängerseite hat. Läuft der Ringbuffer voll, weil 
das Programm gerade mit etwas anderem beschäftigt ist, gehen Daten 
verloren.

Dagegen gibt es zwei Mittel - eventuell auch in Kombination:

1. Ringbuffer vergrößern

2. Mit dem Sender in einen Dialog treten, d.h. nach einer bestimmten 
Anzahl von Frames mit einer Quittung antworten, auf die der Sender 
warten muss. Dadurch kann man den Sender dann ausbremsen.

> Ich verwende mit uCs jede Menge serielle Übertragung und wenn man
> Baudrate etc passen sehe ich quasi nie falsche Bytes.

Das kommt immer auf die Anwendung an.

: Bearbeitet durch Moderator
von Reinhard O. (kristian_1955)


Lesenswert?

Moin,

ich wollte nur Bescheid sagen, dass ich mich Montag wieder zurückmelde 
sobald ich den Controller weiter programmiere.

Bis dahin ein schönes Wochenende

Viele Grüße

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Frank M. schrieb:
>> Oder bekommt man das Byte trotzdem?
>
> Du bekommst es auf jeden Fall, wenn Du auf der Empfängerseite den UART
> ohne Parity, aber mit Anzahl Datenbits + 1, einstellst.

 Man bekommt es immer, egal wie der UART auf der Empfängerseite
 eingestellt ist.
 Es werden nicht die Flanken oder ähnliches gezählt, es werden ganz
 einfach Samples zu bestimmten Zeiten genommen und am Ende wird nach
 Majority Prinzip entschieden, was da genau empfangen worden ist.

 D.h. konkret beim AVR werden 16 Samples pro bit genommen. Samples
 8,9 und 10 werden dannn ausgewertet.
 Beim Stoppbit sind es nur 10 Samples aber es sind wiederum die Samples
 8,9 und 10 die ausgewertet werden.

> Sender 7E1

> Empfänger: 7N1
 Byte wird empfangen, Parity wird als Stoppbit empfangen.

> Empfänger: 8N1
 Byte wird empfangen, Parity wird als bit7 empfangen, Stoppbit OK.

> Empfänger: 8E1
 Byte wird empfangen, Parity wird als bit7 empfangen, Stoppbit wird
 als Parity empfangen.

 Das gesendete Byte wird manchmal falsch, manchmal richtig gedeutet,
 aber es wird immer empfangen und bleibt in UDR.

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Marc V. schrieb:
>> Stimmt, denn es wäre "ein ASCII-Protokoll", weil Substantiv Neutrum.
>  Tja, ich bin kein Deutscher, das ist nicht meine Muttersprache,

Dann sei dir verziehen und fass es als Kompliment auf.
Mein Schwedisch ist bei Weitem nicht so gut.

>>>  Das, wovon du redest sind Nutzdaten, es ist absolut uninteressant ob
>>>  da ASCII-Zeichen oder binäre Daten übertragen werden.
>> Nö. Bei HTTP sende ich einen Header, gefolgt von den eigentlichen
>> Nutzdaten. Der Header hingegen besteht laut Standard ausschließlich
>> aus ASCII-Zeichen (inklusive CR und LF).
>  Nö - Nein - No - Nada - Njet.

Wenn im Protokoll festgeschrieben steht, dass die Daten ASCII zu sein 
haben, dann darf ich da keine beliebigen Binärdaten reinkippen. Außerdem 
ist die Interpretation der Daten ziemlich genau vorgegeben.

Beispiel:
"Content-Length: 1024\r\n" ist so spezifiziert, dass die Zeichenfolge 
"1024" als (beliebig lange!) ASCII(!)-Repräsentation einer 
Dezimalzahl(!) aufgefasst wird. Ich darf da kein Zeichen 
reinschreiben, welches nicht zwischen 0x30 und 0x39 liegt!

Diese Eigenschaft (also menschenlesbare Inhalte zu übertragen) zeichnet 
ASCII-Protokolle aus.

>  Der Header, inclusive ev. Nutzdaten muss erst beim Empfänger ankommen.

Nein. Bevor der Empfänger den Header nicht analysiert hat, weiß er noch 
nichtmal, wieviele Nutzdaten überhaupt ankommen werden.

Wenn ich eine 1 GB große Datei aus dem Internet herunterlade, dann ist 
für den Browser nur der HTTP-Header relevant, denn was in der Datei drin 
ist, hat ihn nicht zu interessieren. Er will aber wissen, wie sie heißt 
und wie groß sie ist - ohne sie vollständig herunterzuladen.

>  Insofern ist es absolut uninteressant, ob da ASCII oder binary
>  übertragen wird.

Nein. Nicht alle Transportkanäle erlauben die Übertragung von rohen 
Binärdaten. Da ASCII aber nur eine Teilmenge aller Binärwerte ist, muss 
der Kanal es aber auch nicht sein. Eine serielle Schnittstelle mit dem 
Format 7N1 wird den Bytewert 0xFF nur als 0x7F übertragen.

Aus genau diesem Grund sind Internet-Protokolle wie SMTP eben keine 
Binärprotokolle (sondern ASCII-Protokolle!), denn sie verlangen nicht, 
dass der Transportkanal "8 bit clean" sein muss. Und aus genau diesem 
Grund verlangt SMTP auch, dass die Nutzdaten keine Binärdaten sind.

Also werden E-Mails vor dem Versand so codiert (Base64, 
quoted-printable, ...), damit sie nur noch ASCII-Zeichen enthalten. Sie 
dürfen keine Binärdaten sein, denn sonst können sie nicht korrekt 
mittels SMTP übertragen werden!

>  Ist hoffe, dir ist das Ganze jetzt ein bisschen klarer geworden,
>  obwohl, viel Hoffnung habe ich nicht...

Für dich sind ASCII-Wert normale Binärwerte. Das ist auch richtig. Aber 
nicht jeder Binärwert ist auch ein ASCII-Wert und daraus ergeben sich 
Konsequenzen, die dazu führen, dass
- jedes ASCII-Protokoll ein Binärprotokoll ist, aber
- nicht jedes Binärprotokoll ein ASCII-Protokoll ist.

Und darum wird zwischen ASCII-Protokollen und Binärprotokollen 
unterschieden.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

S. R. schrieb:
>>  Der Header, inclusive ev. Nutzdaten muss erst beim Empfänger ankommen.
>
> Nein. Bevor der Empfänger den Header nicht analysiert hat, weiß er noch
> nichtmal, wieviele Nutzdaten überhaupt ankommen werden.

 Nachdem sich die Gemüter ein bisschen beruhigt haben, versuche ich zu
 erklären, was (meinerseits) gemeint ist:

 Du schickst ein Paket nach Schweden - was drin steht ist vorerst
 uninteressant, aber die Adresse muss draufstehen (und zwar in ASCII).
 Die Post hat die Aufgabe, dieses Paket unbeschädigt und ohne dessen
 Inhalt zu verändern, nach Schweden zu befördern.
 Das passiert auch, dieses Paket ist intakt nach Schweden angekommen,
 der erste Teil des Headers (die Adresse auf dem Paket) hat ihren
 Zweck erfüllt.
 Jetzt wird dein Paket aufgemacht und der Inhaltsverzeichnis (der
 zweite Teil des Headers) wird gelesen. Nachdem du das gemacht hast,
 weisst du was sich in dem Paket befindet (das wären dann Nutzdaten).

 Aber:
 Ob sich nun in deinem Paket Briefe oder Bücher auf Deutsch (ASCII)
 oder auf Chinesisch (Binär) befinden, spielt gar keine Rolle.

 Warum:
 Weil die Daten (oder Paket) dank der Post (Internet) fehlerfrei
 angekommen sind. Die Post ihrerseits hat verschiedene Systeme der
 Nachrichten- sowie Brief- und Paketübermittlung entwickelt. Du als
 Nutzer weisst gar nicht wie das alles funktioniert, brauchst du
 auch nicht, aber deswegen kann man nicht sagen:
1
 "Ich habe ein Paket ohne Beschädigung (Fehler) nach Schweden getragen"
 - nein, du hast nur dieses Paket bei der Post abgegeben.

 Somit sind Fehler bei der Übertragung (Zustellung) ausgeschlossen
 (bzw. nicht ausgeschlossen aber du hast keinen Einfluss auf diese)
 deswegen hat es auch keinen Sinn, in den Briefen nur jede zweite
 Zeile zu beschreiben oder nur auf Deutsch und nicht auf Chinesisch
 zu schreiben, um die Übertragung (Zustellung) sicherer zu machen.

 Ich hoffe, ich habe mich einigermassen verständlich ausgedrückt...

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Marc V. schrieb:
> Kaum.
>  Wenn das Ganze so rausgesendet würde, hätte er recht und ich nicht.
>  Da dies aber nicht der Fall ist...

Ich denke schon, dass ihr aneinander vorbei geredet habt und in den 
letzten Posts wird das IMO deutlich. Der eine redet von Protokollen, die 
die Datenübertragung betreffen, der andere redet von Protokollen, die 
die Dateninterpretation betreffen. Du hast das jetzt mit dem 
Postpaketbeispiel IMO schön verdeutlicht. Deshalb finde ich, dass ihr 
beide recht habt, ihr spracht nur nicht vom Gleichen ;)

von ms (Gast)


Lesenswert?

Hallo Hans,

vielleicht etwas altmodisch aber für deine Anwendung ideal.
Die serielle schnittstelle besteht nicht nur aus TX und RX du kannst 
auch noch das RST Signal verwenden.
Mein Vorschlag:
LabView aktiviert das RST vor dem senden nach einer kuzen pause sendet 
es deine [85][INT_LO/HI] [INT_LO/HI] und optinal [CS] danach eine kuze 
Pause und deaktiviert das RST.
Dein uC erkennt den Pegelwechsel vom RST und beginnt alle Variabel zu 
initalisieren und aktiviert den RX Interrupt. Nach einem erneuten Pegel 
wechesel des RST wird der RX Interrupt deaktiviert.Jetzt kann man die 
Prüfsumme abgleichen ist alles OK dan Flag setzen für das Hauptprogramm.
Jetzt dürfte es egal sein ob du 0-65535 als 1-5 byte ASCII oder nur mit 
2 Byte überträgst.

ms

von S. R. (svenska)


Lesenswert?

Ja, du hast dich verständlich ausgedrückt.

Das ändert aber nichts an der Tatsache, dass man sowohl das Format der 
Nutzdaten als auch das Format sämtlicher sonstiger Kommunikation auf 
ASCII einschränken kann.

Warum sollte man das tun? Weil du in deiner Analogie den Zollbeamten 
vergessen hast, der das Paket aufmacht und alles wegwirft, was er nicht 
lesen kann.

Protokolle, die auf ASCII aufbauen, sind oft einfacher zu
- verstehen und zu debuggen (Terminalprogramm reicht zum Zuschauen)
- erweitern (Länge des Headers nicht vorgegeben *)
- aktualisieren (weil z.B. Zahlenbereiche nicht implizit begrenzt sind)
- übertragen (geringere Anforderungen an den Transportweg).

* Beispiel: Weil HTTP die Datenlängen im Header als ASCII-Zahl 
überträgt, kann es implizit mit beliebig großen Dateien umgehen. 
Binärprotokolle können das nicht.

Das sind Gründe, ASCII-Protokolle von Binärprotokollen zu unterscheiden.

von Conny G. (conny_g)


Lesenswert?

Man könnte sagen: ASCII-Übertragung ist ein Protokoll mit Feldern 
variabler Länge, das mit Trennzeichen/Trenntags arbeitet. So wie XML und 
Verwandte.
Und ist damit robuster und flexibler als feste Länge mit/ohne Binär.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

S. R. schrieb:
> Warum sollte man das tun? Weil du in deiner Analogie den Zollbeamten
> vergessen hast, der das Paket aufmacht und alles wegwirft, was er nicht
> lesen kann.

 LOL.
 Frank hat eine Verbindung konstruiert, bei der nur ASCII fehlerfrei
 durchkommt, bei binär werden Zeichen an genau bestimmbaren Stellen
 verschluckt, du hast diesen Zollbeamten...

 Also:
 Zollbeamter wird gefeuert oder er muss einen Sprachkurs erfolgreich
 beenden.
 Punkt.
 Schande, sowas.

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Dann nimm eine serielle Verbindung mit 7N1 als Beispiel.
Da geht ASCII fehlerfrei durch, aber nicht jeder Binärwert.

Nachtrag: PS/2 wäre auch ein binäres Protokoll, wo selektiv Bytes 
verschluckt werden können. Viele Controller filtern nämlich sämtlichen 
Traffic, der nicht wie "kommt von einer Tastatur oder eine Maus" 
aussieht - das ist für (Multi-)Touchpads tatsächlich ein Problem.

Geht das nicht in deinen Kopf rein, dass sowas ein Problem sein kann 
(nicht muss)?

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

S. R. schrieb:
> .... Kommunikation auf
> ASCII einschränken kann.
>
> Warum sollte man das tun?

Nun, man muß sowas nicht wirklich tun, wenn die ganze Konfiguration 
überschaubar genug ist. Und in dem eingangs geschilderten Falle ist sie 
überschaubar.

Was der TO nicht wirklich verstanden hat ist, daß er hier zwei 
unabhängige Instanzen (PC und µC) vor sich hat, die eine Art 
Synchronisation benötigen, um sinnvoll miteinander kommunizieren zu 
können.

Ob man das über bestimmte ASCII-Zeichen macht oder mit anderen 
Binärwerten, ist vom Prinzip her egal. Wichtig sind nur zwei Dinge:
- Synchronisation, also Erkennung beim Empfänger, an welcher Stelle 
einer Datenübertragung man ist, wenn man ein Zeichen empfangen hat
- Fehlererkennung, also ob eine Übertragung OK ist oder nicht.

Oft ist ebenso wichtig, daß man mit leichtem Gepäck daherkommt, also 
ohne übertrieben aufwendigen Umfang an zusätzlichem Zeugs.

Nochwas:
Wenn man bei beiden Teilnehmern sowas wie 8N1 einstellt und back to back 
sendet, dann ist die Gefahr groß, daß man damit nach einiger Zeit einen 
Übertragungsfehler verursacht, weil die Bit-Takte beider Teilnehmer 
dezent differieren können. Ist ja häufig, daß man im µC eine gewünschte 
Baudrate nicht ganz exakt hinbekommt und einen Restfehler von einigen 
Prozent hat. Dagegen hilft eigentlich immer, mit 8N2 zu senden oder mal 
eine Pause einzulegen.

W.S.

von Georg (Gast)


Lesenswert?

W.S. schrieb:
> Wenn man bei beiden Teilnehmern sowas wie 8N1 einstellt und back to back
> sendet, dann ist die Gefahr groß, daß man damit nach einiger Zeit einen
> Übertragungsfehler verursacht, weil die Bit-Takte beider Teilnehmer
> dezent differieren können

In Zahlen:

Ist der Sender langsamer als der Empfänger, so trifft das nächste 
Startbit später ein als erwartet, das ist garkein Problem, ist ja 
asynchron. Im umgekehrten Fall kommt das Starbit zu früh; es gibt zwar 
unzählige Implementationen von UARTs, aber i.A. kann man davon ausgehen, 
dass der Empfänger zufrieden ist, wenn er das Stopbit (in der Mitte der 
Bit-Zeit) verifiziert hat, also darf das nächste Startbit um maximal 
eine halbe Bitzeit zu früh kommen, das ergibt also 9,5 statt 10 
Bitzeiten und damit 5% zulässige Abweichung. Das ist bei Quarz auf 
beiden Seiten kein Problem, andrerseits erklärt das auch, warum eben 
Quarztakt für UARTs empfohlen wird.

Allerdings wird das in diesem Forum immer wieder vehement bestritten.

Georg

von S. R. (svenska)


Lesenswert?

W.S. schrieb:
>> .... Kommunikation auf ASCII einschränken kann.
>> Warum sollte man das tun?
> Nun, man muß sowas nicht wirklich tun, wenn die ganze Konfiguration
> überschaubar genug ist.

Marc behauptete, es gäbe keine ASCII-Protokolle, und dem widerspreche 
ich vehement.

Wenn die Bandbreite kein Problem darstellt, bevorzuge ich 
ASCII-Protokolle allein aus dem Grund, dass ich einen Teilnehmer 
entwickeln und im Terminal testen kann, bevor die Gegenstelle bereit 
ist. So habe ich zu jeder Zeit nur eine Baustelle.

> Wenn man bei beiden Teilnehmern sowas wie 8N1 einstellt und back to back
> sendet, dann ist die Gefahr groß, daß man damit nach einiger Zeit einen
> Übertragungsfehler verursacht, weil die Bit-Takte beider Teilnehmer
> dezent differieren können.

Ja, ist eine allgemeine Grundregel für Kommunikation:
- ist der Empfänger zu schnell, nutzt du die Bandbreite nicht optimal,
- ist der Sender zu schnell, gibt es irgendwann Datenverlust.

Georg schrieb:
> Allerdings wird das in diesem Forum immer wieder vehement bestritten.

Hängt vom Anwendungsfall ab. Eine serielle Debugschnittstelle, die nur 
im Labor bei Raumtemperatur benutzt wird, braucht keinen Quarztakt. Aber 
die wird auch nicht dauerhaft senden...

von W.A. (Gast)


Lesenswert?

S. R. schrieb:
> Ja, ist eine allgemeine Grundregel für Kommunikation:
> ...
> - ist der Sender zu schnell, gibt es irgendwann Datenverlust.

Prinzipiell gibt es doch das Stop-Bit als Puffer. Je nach dem, wo der 
Empfänger das Stop-Bit abtastet, könnte er doch sofort danach wieder auf 
die Flanke vom nächsten Start-Bit warten und damit deutlich schneller 
sein, als der Sender, auch wenn die Symbolrate des Senders etwas nach 
oben abweicht.

von S. R. (svenska)


Lesenswert?

Ist der Sender dauerhaft schneller als der Empfänger, wird irgendwann 
jeder dazwischenliegende Puffer voll sein. Egal welcher Größe.

Außerdem redest du davon, dass der Empfänger schneller ist, nicht der 
Sender.

: Bearbeitet durch User
von W.A. (Gast)


Lesenswert?

S. R. schrieb:
> Außerdem redest du davon, dass der Empfänger schneller ist, nicht der
> Sender.

Nein, ich rede davon, dass der Empfänger mit einer etwas geringeren 
Symbolrate abtastet als der Sender die Zeichen sendet und damit 
langsamer bezogen auf die Bitrate ist. Einen gewissen Taktratenfehler 
kann er trotzdem ausgleichen, wenn er das Stopbit nicht am Ende 
abtastet, sondern vorher schon wieder in Idle geht und auf die nächste 
Start-Flanke wartet, während der Sender das Stop-Bit in voller Länge 
senden muss.

von S. R. (svenska)


Lesenswert?

Verstehe. Ob moderne UARTs das machen, weiß ich allerdings nicht - ich 
vermute "eher nein".

von Klaus (Gast)


Lesenswert?

Ich hielt das OSI Schichtenmodell eigentlich für zu theoretisch. Aber 
wenn ich lese, wie hier die Übertragung von Bits, die Sicherung der 
Übertragung und die Nutzdaten durcheinandergeworfen werden, sollte so 
mancher sich doch damit beschäftigen.

http://www.elektronik-kompendium.de/sites/kom/0301201.htm

MfG Klaus

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Klaus schrieb:
> Ich hielt das OSI Schichtenmodell eigentlich für zu theoretisch. Aber
> wenn ich lese, wie hier die Übertragung von Bits, die Sicherung der
> Übertragung und die Nutzdaten durcheinandergeworfen werden, sollte so
> mancher sich doch damit beschäftigen.

 LOL.
 Stimme ich voll zu, nur wollte ich nicht wieder derjenige sein, der
 darauf rumreitet.

von M. Keller (Gast)


Lesenswert?

Ihr redet tatsächlich an einander vorbei. Denn ihr habt beide recht, da 
ihr verschiedene OSI Schichten meint...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

M. Keller schrieb:
> Ihr redet tatsächlich an einander vorbei. Denn ihr habt beide recht, da
> ihr verschiedene OSI Schichten meint...

 Kann sein, nichtsdestotrotz hat der HTTP mit Transport, sicherer
 Übertragung und Datenintegrität genausoviel zu tun, wie die
 Würstchenbude an der Ecke, nämlich genau nichts.

 Schritt 1.
 Client bereitet eine HTTP-Anfrage vor.

 Schritt 2.
 Die Anfrage wird fur den Versand vorbereitet, also in einen Paket
 verpackt. Die Headerdaten werden dafür benutzt.

 Schritt 3.
 Das Paket wird über Internet verschickt. Ab jetzt ist der ganze
 HTTP-Kram nur noch Paketinhalt, also Nutzdaten.

 Schritt 4.
 Paket ist beim Empfänger angekommen, wird ausgepackt, die Headerdaten
 werden wieder benutzt.

 Schritt 5.
 Ab jetzt wird HTTP wieder verwendet.

 Es geht um Schritt 3 und 4, also um sicheren Transport der Daten.
 Was vorher und nachher mit diesen Daten gemacht wird und wie das Ganze
 dann interpretiert wird, ist eine ganz andere Baustelle und hat mit dem
 Transport nichts zu tun.

 Insofern ist es absolut uninteressant, was da als Nutzdaten
 transportiert wird - ASCII, Binär, HTTP, Deutsch, Chinesisch...

 P.S.
 Auch ein Zollbeamter hat mit Transport herzlich wenig zu tun...

: Bearbeitet durch User
von M. Keller (Gast)


Lesenswert?

Marc V. schrieb:
> Schritt 3. Das Paket wird über Internet verschickt. Ab jetzt ist der
> ganze
>  HTTP-Kram nur noch Paketinhalt, also Nutzdaten

Ja klar. Ab hier ist die nächste Schicht verantwortlich, nämlich TCP.
Es ging w.a. darum, dass die niedrigen Schichten  (transport, 
sicherungsschicht...) ebenfalls ASCII basiert sein können, wodurch diese 
Schichten einfacher zu debuggen sind.

Z.b. modbus, das gibt es als ASCII oder RTU (binär)

von Klaus (Gast)


Lesenswert?

Marc V. schrieb:
> Kann sein, nichtsdestotrotz hat der HTTP mit Transport, sicherer
> Übertragung und Datenintegrität genausoviel zu tun, wie die
> Würstchenbude an der Ecke, nämlich genau nichts.

Richtig. Und genausowenig hat es etwas mit Paketen zu tun.

Marc V. schrieb:
> Schritt 2.
>  Die Anfrage wird fur den Versand vorbereitet, also in einen Paket
>  verpackt. Die Headerdaten werden dafür benutzt.

Bei HTTP hab ich noch nie Pakete gesehen. Da schreibt man einfach in 
einen Socket, solange man was zu sagen hat. Und sowohl die HTML-Header 
als auch der HTML-Body sind reines 7-Bit ASCII, selbst simple Umlaute 
muß man escapen. Ist man fertig, schließt man den Socket wieder.

Will man Pakete sehen, muß eine Schicht tiefer schauen, da sieht man 
aber HTTP nicht. In den Paketen könnte auch SMTP oder FTP oder auch 
Telnet sein. Das Protokol auf dieser Ebene heißt aber auch TCP und nicht 
HTTP.

MfG Klaus

von S. R. (svenska)


Lesenswert?

Lassen wir das.

Marc geht davon aus, dass jeder Übertragungskanal fähig ist, binäre 
(Nutz-)Daten vollständig zu übertragen und folgert daraus korrekt, dass 
jede Datenübertragung im Endeffekt binär ist. Jede Beschränkung (z.B. 
auf ASCII) ist daher Verschwendung und Unsinn.

Dieses Weltbild ist schlüssig.

Da aber die Annahme in dieser Allgemeinheit falsch ist, sind auch die 
Schlussfolgerungen nicht gültig. Gegenbeispiele habe ich genannt.

Ob binäre Nutzdaten nun durch einen ungeeigneten Kommunikationskanal, 
einen übereifrigen Zollbeamten (technisch: "Firewall mit DPI") oder 
einen Programmfehler dahingerafft werden, ist unerheblich. Gewöhnliches 
ASCII hat hier eine höhere Überlebenschance (nebst anderen Vor- und 
Nachteilen).

von Conny G. (conny_g)


Lesenswert?

S. R. schrieb:
> Lassen wir das.
>
> Marc geht davon aus, dass jeder Übertragungskanal fähig ist, binäre
> (Nutz-)Daten vollständig zu übertragen und folgert daraus korrekt, dass
> jede Datenübertragung im Endeffekt binär ist. Jede Beschränkung (z.B.
> auf ASCII) ist daher Verschwendung und Unsinn.
>
> Dieses Weltbild ist schlüssig.
>
> Da aber die Annahme in dieser Allgemeinheit falsch ist, sind auch die
> Schlussfolgerungen nicht gültig. Gegenbeispiele habe ich genannt.
>
> Ob binäre Nutzdaten nun durch einen ungeeigneten Kommunikationskanal,
> einen übereifrigen Zollbeamten (technisch: "Firewall mit DPI") oder
> einen Programmfehler dahingerafft werden, ist unerheblich. Gewöhnliches
> ASCII hat hier eine höhere Überlebenschance (nebst anderen Vor- und
> Nachteilen).

Stimmt nicht ganz. Wenn Daten kaputt gehen, dann geht auch ASCII kaputt.
Aber das Prinzip ASCII + Control Characters vermischt einfach Nutzdaten 
und Übertragungssteuerung in einem Byte, also zwei verschiedene 
Schichten des ISO-Modells :-)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

S. R. schrieb:
> jede Datenübertragung im Endeffekt binär ist. Jede Beschränkung (z.B.
> auf ASCII) ist daher Verschwendung und Unsinn.

 Nein, selbstverständlich nicht.
 Bei 100% fehlerfreier Übertragung ist ASCII eine (ganz akzeptable)
 Möglichkeit, Datenpakete zuverlässig zu unterscheiden, genau wie
 Präambel oder <SOF>.

 Bei GPS (NMEA) startet eine Nachricht mit "$" und endet mit CR/LF.
 Checksum ist Bestandteil der Nachricht. Funktioniert fehlerfrei, da
 diese Zeichen sonst nirgendwo in der Nachricht vorkommen.
 Aber es gibt auch ein binär Protokoll für GPS, welches viel schneller
 ist, aber nicht HR ist.

 Natürlich macht es für mich keinen Sinn, GPS mit ASCII zu benutzen,
 da die Umwandlung nach binär doppelte Arbeit darstellt.
 Aber zur Kontrolle (Debug) ist es natürlich besser.

> Da aber die Annahme in dieser Allgemeinheit falsch ist, sind auch die
> Schlussfolgerungen nicht gültig. Gegenbeispiele habe ich genannt.

 Nein, missverstanden, bin in dieser Beziehung niemals ausschlieslich
 geworden, ASCII hat auch Vorteile, unbestritten.

von W.S. (Gast)


Lesenswert?

S. R. schrieb:
> Verstehe. Ob moderne UARTs das machen, weiß ich allerdings nicht - ich
> vermute "eher nein".

Ich hab's beim Schreiben des STM32-Bootlader-Programms neulich mal 
wieder erlebt: FTDI-Chip auf PC-Seite, Bootlader per uart1 auf STM 
Seite. Kann jeder nachvollziehen. Mit 8N2 am PC war die Sache dann 
erledigt.

W.S.

von Reinhard O. (kristian_1955)


Lesenswert?

Moin Thomas,

ich bin jetzt soweit, dass ich mit LabView einen Wert an den uC senden 
möchte. Ich habe im Control Panel, ein uint16 Eingabefeld. Wenn ich da 
eine 77 (dezimal) eintrage, muss ja zum uC der String 4D gesendet 
werden.
Kannst du mir erklären, wie ich einen uint16 so in LabView umrechne, 
dass das richtige an den uC geschickt wird?

Danke & viele Grüße

Thomas E. schrieb:
> Du dekodierst deine Daten im Hauptprogramm. Das Befehlsbyte liegt vor
> den Daten. Dieses kommt in eine Variable(unsigned char) und die
> eigentlichen Daten in eine andere Variable(unsigned int). Und dann
> wertest du das aus:
>
> if(Befehlsbyte == 85)
> {
> //  tu was
> }
>
> oderswitch(Befehlsbyte)
> {
>  case 0:
>   //tu dies
>   break;
>  case 1:
>   //tu das
>   break;
>  case 85:
>   //tu jenes
>   break;
> }
>
> Alles im Hauptprogramm oder in Funktionen, die aus dem Hauptprogramm
> aufgerufen werden.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Hans D. schrieb:
> Kannst du mir erklären, wie ich einen uint16 so in LabView umrechne,
> dass das richtige an den uC geschickt wird?


Das ist wohl das finale Ergebnis des gesamten Threads.

W.S.

von S. R. (svenska)


Lesenswert?

Hans D. schrieb:
> Ich habe im Control Panel, ein uint16 Eingabefeld. Wenn ich da
> eine 77 (dezimal) eintrage, muss ja zum uC der String 4D gesendet
> werden.

Nein.

Ich fürchte, du hast den Unterschied zwischen Dezimalzahl, 
Hexadezimalzahl und String nicht verstanden.

von Wolfgang (Gast)


Lesenswert?

Conny G. schrieb:
> Stimmt nicht ganz. Wenn Daten kaputt gehen, dann geht auch ASCII kaputt.

Dann nimm nicht ASCII, sondern irgendwelche Codeworte mit einem 
Hammingabstand größer zwei. Schon damit kannst du Einzelfehler im 
Codewort korrigieren und die effektive Sicherheit der Übertragung 
erheblich steigern.

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.