Forum: Mikrocontroller und Digitale Elektronik Protokoll für Kommandos an den MC selber schreiben


von W. M. (muhh)


Lesenswert?

Hey Leute,

da ich jetzt mit USART Daten vom PC zum MC (Atmel ATXmega xplained A1 
Board) schicken kann und umgekehrt, möchte ich nun ein PWM Signal mit 
bestimmten Befehlen steuern, die ich vom PC aus schicke.

Mit dem bisherigen Code kann ich zwar die Pulsweite verändern, 
allerdings glaube ich nicht, dass meine Variante die beste ist.

Wie geht man an sowas ran? Wie könnte ich so eine Kommando-Abfrage mit 
dem MC realisieren?

Zur Funktionsweise:
Mein Code guckt die ganze Zeit nach einem Startbit (0x01), bei dem es 
die Zählvariable cmd inkrementiert. Danach schickt der MC in der 
while-Schleife andauernd den string "Geben Sie einen Wert ein" an den 
PC, weil cmd 1 ist.
Wenn man nun den ersten Wert (für den 16-bit Timer die oberen 8 bit) 
schickt, wird cmd wieder inkrementiert, dass gleiche für den zweiten 
Wert auch.
Bei cmd = 3 kommt man in der main in die if-Schleife, die den Compare 
Wert des Timers auf den vom PC gesendeten Wert setzen soll.

Komischer weise funktioniert das ganze nur, wenn ich die if-Abfragen für 
cmd=1 und cmd=2 mit einbaue, wenn ich die auskommentiere funktioniert 
der Code nicht mehr :S


Soll man nicht normalerweise die ISR nur für Zuweisungen und ganz kurzen 
Code benutzen?

Mein Code:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#include "debouncing.h"
6
7
/***********************    Global Variables     ***********************/
8
9
volatile uint8_t rx_buffer;      // USART receive buffer
10
uint8_t cmd;
11
uint8_t pwm_buffer_H;
12
13
/***********************    Function Prototype     ***********************/
14
15
void ConfigPeripherals(void);    // Configure Peripherals
16
void ConfigCLK(void);        // Configure ClockSystem
17
void InitUSART(void);        // Configures and initialize USART
18
void InitPWM(void);          // Configure PWM Timer
19
void InitDebouncing(void);      // Configure Debouncing Timer
20
21
void USART_sendInt(uint8_t data);
22
void USART_sendChar(unsigned char c);
23
void USART_sendString(char *data);
24
25
/***********************        MAIN       ***********************/
26
27
int main(void)
28
{
29
  
30
  
31
  
32
//   PORTE.DIR = 0xff;    // LED-Port als Ausgang schalten
33
//   PORTE.OUT = 0xff;    // LEDs ausschalten
34
  
35
  ConfigCLK();        // Configure ClockSystem
36
  
37
  InitUSART();        // Configures and initialize USART
38
  InitPWM();
39
  ConfigPeripherals();    // Configure Peripherals
40
  
41
  cmd = 0;
42
  
43
    while(1)
44
    {
45
      PORTE.OUTTGL = 0x01;
46
      if (cmd == 1)
47
      {
48
        USART_sendString("Geben Sie einen Wert ein:\n");
49
      }
50
      if (cmd == 2)
51
      {
52
        USART_sendInt(pwm_buffer_H);
53
      }
54
      if (cmd == 3)
55
      {
56
        TCC0.CCAH = pwm_buffer_H;
57
        TCC0.CCAL = rx_buffer;
58
        cmd = 0;
59
      }
60
    }
61
}
62
63
/***********************  Interrupt Service Routine   ***********************/
64
65
ISR( USARTC0_RXC_vect )
66
{
67
  if (cmd == 1)
68
  {
69
    pwm_buffer_H = USARTC0.DATA;
70
    cmd++;
71
  } else if (cmd == 2)
72
  {
73
    rx_buffer = USARTC0.DATA;
74
    cmd++;
75
  } else
76
  {
77
    rx_buffer = USARTC0.DATA;            // read received data to rx_buffer
78
  }  
79
  
80
  if (rx_buffer == 0x01 && cmd == 0) cmd = 1;
81
}
82
83
/*********************** Configuration and Initialisation ***********************/
84
85
void ConfigPeripherals(void)  // Configure Peripherals
86
{
87
  PORTE.DIR = 0xff;                  // set PORTE as output
88
  PORTE.OUT = 0xff;                  // set PORTE to high (LED = off)
89
  
90
  PORTC.DIR = 0xff;
91
  PORTC.OUT = 0xff;
92
}
93
94
void ConfigCLK(void)      // Configure ClockSystem
95
{
96
  OSC.CTRL = 3;                    // set internal oscillator to 32MHz
97
  while(OSC.STATUS != 3);
98
  CCP = 0xD8;
99
  CLK.CTRL = 1;
100
}
101
102
void InitUSART(void)      // Configures and Initialize USART
103
{
104
  cli();                        // disable Global Interrupts
105
  
106
  USARTC0.BAUDCTRLA = 137;              // set baud rate to 2Meg
107
  USARTC0.BAUDCTRLB = 0xf0;              // BSCALE = 0
108
  USARTC0.CTRLA = USART_RXCINTLVL_HI_gc;        // Receive Interrupt Enable, Interrupt Level High
109
  USARTC0.CTRLC = USART_CHSIZE_8BIT_gc |        // set 8bit Mode
110
          USART_CMODE_ASYNCHRONOUS_gc |    // Asynchronous Mode
111
          USART_PMODE_DISABLED_gc;      // disable Parity Bit
112
  USARTC0.CTRLB = USART_TXEN_bm | USART_RXEN_bm;    // Transmit + Receive enable
113
  PORTC.DIR = 0x08;                  // set TxD Pin as output
114
  
115
  PMIC.CTRL = PMIC_HILVLEN_bm;            // High Level Interrupts
116
  sei();                        // Global Interrupts
117
}
118
119
void InitPWM(void)        // Configure PWM Timer - Peripherals must be configured after PWM Initialization
120
{
121
  TCC0.PER = 30000;                  // set TOP value to choose period T
122
  TCC0.CCA = 0;                    // set PulseWidth to 0%
123
  TCC0.CTRLA = TC_CLKSEL_DIV1_gc;            // set clock (SystemClock)
124
  TCC0.CTRLB = 0x13;                  // enable OCn pin, set SingleSlope PWM WG Mode
125
}
126
127
void InitDebouncing(void)    // Configure Debouncing Timer - You may have to change debouncing.h to fit to your project
128
{
129
  TCC1.PER = 1.0*F_CPU /1024 /2 * 30e-3 -1;      // set PER register for 30ms sampling
130
  TCC1.CTRLB = TC_WGMODE_NORMAL_gc;          // set Normal Mode
131
  TCC1.INTCTRLA = TC_OVFINTLVL_HI_gc;          // set Overflow Interrupt Level to High
132
  TCC1.CTRLA = TC_CLKSEL_DIV1024_gc;          // select Prescaler (1024)
133
}
134
135
/***********************        Function       ***********************/
136
137
void USART_sendInt(uint8_t data)
138
{
139
  while (!(USARTC0.STATUS & USART_DREIF_bm));      // wait until Data register is empty
140
  USARTC0.DATA = data;
141
}
142
143
void USART_sendChar(unsigned char c)
144
{
145
  while (!(USARTC0.STATUS & USART_DREIF_bm));      // wait until Data register is empty
146
  USARTC0.DATA = c;
147
}
148
149
void USART_sendString(char *data)
150
{
151
   while (*data)
152
   {
153
     USART_sendChar(*data);
154
     data++;
155
   }
156
}

von Stefan (Gast)


Lesenswert?

Das würde ich ganz anders angehen.

Die Interrupt Routine schreibt die empfangenen Zeichen in einen Puffer, 
bis sie einen Zeilenumbruch empfängt. Dann setzt sie ein fertig-Flag auf 
1 und ignoriert alle weiteren Zeichen, solange das Flag noch auf 1 ist.

Das Hauptprogramm Gibt die Eingabeaufforderung aus. Dann wartet es, bis 
das fertig-Flag=1 ist. Danach kann es den empfangenen Befehl auseinander 
nehmen und abarbeiten. Danach setzt das Hauptprogramm das fertig-flag 
wieder auf 0 und sende die nächste Eingabeaufforderung.

Ich würde die Eingabeaufforderung allerdings weg lassen, wie es auch 
Modems tun. Stattdessen würde ich nach jedem empfangenen befehl Feedback 
geben, ob er erfolgreich oder nicht erkannt wurde.

Der Empfangspuffer muss natürlich groß genug sein, um den längsten 
möglichen Befehl aufnehmen zu können.

Wenn Du statt eines einfachen Puffers zwei Puffer nimmst, die 
abwechselnd für Empfang befüllt werden, kannst du den nächsten Befehl 
schon empfangen während der erste abgearbeitet wird. Das würde ich aber 
erst angehen, wenn der einfache Puffer schon funktioniert.

von W. M. (muhh)


Lesenswert?

Hallo Stefan,

also lege ich sozusagen eine Art Paket fest das immer eingehalten wird?

z.B:

1. Byte: Befehl
2. Byte: MSB Wert
3. Byte: LSB Wert
4. Byte: Stopbit (du hattest \n vorgeschlagen oder?)

Ist es sinvoll das Receive Interrupt nach dem Empfangen des Stopbits 
solange zu deaktivieren, bis man den Befehl abgearbeitet hat?

: Bearbeitet durch User
von cppler (Gast)


Lesenswert?

Willst Du nur Deine PWM steuern oder soll das nachher erweiterbar sein ?
Ein sinnvolles Protokoll wäre:

Startbyte|Datumbyte|...|Datumbyte|CRC|Endbyte

Packe das auf dem µC in einen Struct und werte das in einer eignen 
Routine aus.
In der Routine dann ein ACK an den PC zurückgeben das alles richtig 
angekommen ist.
Kommt das ACK nicht immer wieder die Sequenz senden.
Überlege Dir was Du realisieren willst und schreibe Dir erstmal im 
Klartext auf was alles notwendig ist um Deine Idee umzusetzen.

von W.S. (Gast)


Lesenswert?

Es ist überhaupt nicht sinnvoll, derart prozedural an sowas 
heranzugehen. Denk dir lieber eine Art Kommandoprozessor aus, dem du 
Kommandos geben kannst und der sie auswertet und das Gewünschte dann 
tut. Wenn dir das zu schwer ist, nimm den Kommandoprozessor aus der 
Lernbetty hier im Forum (..wieder tibetanische Gebetsmühle). Der ist in 
plain C geschrieben und läuft auf allem, was man mit C programmieren 
kann. Er ist auch klein, geradezu minimalistisch und hat doch mehr zu 
bieten als das, was du oben angedacht hast.

W.S.

von W. M. (muhh)


Lesenswert?

cppler schrieb:
> Willst Du nur Deine PWM steuern oder soll das nachher erweiterbar sein ?

Ja, soll auf jedenfall erweiterbar sein.

cppler schrieb:
> Startbyte|Datumbyte|...|Datumbyte|CRC|Endbyte

Was meinst du mit Datumbyte? Die Adresse?

W.S. schrieb:
> Es ist überhaupt nicht sinnvoll, derart prozedural an sowas
> heranzugehen. Denk dir lieber eine Art Kommandoprozessor aus, dem du
> Kommandos geben kannst und der sie auswertet und das Gewünschte dann
> tut.

Aber arbeitet der Kommandoprozessor nicht mit einem Protokoll? Irgendwie 
muss man ja schon die Abfolge von bestimmten Daten festlegen oder?

: Bearbeitet durch User
von cppler (Gast)


Lesenswert?

Willy M. schrieb:
> cppler schrieb:
>> Willst Du nur Deine PWM steuern oder soll das nachher erweiterbar sein ?
>
> Ja, soll auf jedenfall erweiterbar sein.
>

Dann schreibe Dir einen Ablaufplan dazu auf, z.B.:
1. auszuführender Befehl (PWM Tast, PWM Freq, LED usw. usf.)
2. Wert = Datum für den Befehl (PWM-OCRX, PWM-Hz, LED-hell usw. usf.)
3. Bestätigung alles korrekt empfangen zu haben

Das ganze packst Du dann in ein Protokoll mit Start/Stop und Prüfsumme.

> cppler schrieb:
>> Startbyte|Datumbyte|...|Datumbyte|CRC|Endbyte
>
> Was meinst du mit Datumbyte? Die Adresse?
>

http://de.wikipedia.org/wiki/Daten

> W.S. schrieb:
>> Es ist überhaupt nicht sinnvoll, derart prozedural an sowas
>> heranzugehen. Denk dir lieber eine Art Kommandoprozessor aus, dem du
>> Kommandos geben kannst und der sie auswertet und das Gewünschte dann
>> tut.
>
> Aber arbeitet der Kommandoprozessor nicht mit einem Protokoll? Irgendwie
> muss man ja schon die Abfolge von bestimmten Daten festlegen oder?

Ja sicher, s.o. Du kannst auch eine Statemachine implementieren oder 
einen einfachen Parser oder oder oder, das ist dann aber die Auswertung 
der Befehle und Daten die Du verarbeitet haben willst und hat nichts mit 
dem Übertragungsprotokoll zu tun.
Wie gesagt schreibe Dir erstmal auf was Du realisieren willst und 
überlege Dir welche Befehle und Daten dazu notwendig sind.
Dann überlegst Du Dir wie Du die Befehel und Daten übermittelst und dann 
implementierst Du erstmal die Übermittlung und shaust nach ob auch alles 
wie gewünscht angekommen ist, z.B. indem Du in der Auswertungfunktion 
erstmal alles wieder zurückschickst.
Dann gehst Du hin und implementierst die Auswertungsfunktion, ob das nun 
ein Parser wird oder eine Statemachine hängt davon ab was Du willst und 
kannst.
Am einfachsten ist ein simpler Parser der via defines die Befehle 
zuweist und dann die entsprechenden Routinen mit den übergebenen Daten 
aufruft.

von W. M. (muhh)


Lesenswert?

Okay, also ich habe mir jetzt aufgeschrieben, was ich allgemein gerne 
für Möglichkeiten mit dem Übertragungsprotokoll haben möchte.

--------------------------------------------

Funktionen:

* Übertragungsprotokoll dient nur zum Übertragen von Befehlen und 
dazugehörigen Werten

- sichere Übertragung mit CRC-Prüfsumme (1 byte)
- senden einer Empfangsbestätigung (1 byte)
- einstellbare Anzahl an Befehlbytes (2 byte = 2^16 Befehle)
- einstellbare Anzahl an Datenbytes (1-4 byte, ist ja variabel)

Aufbau:

Startbyte | Befehlbyte(s) | Datum-/Datenbyte(s) | CRC | Endbyte
(so wie von cppler vorgeschlagen)

Startbyte: 0xAA = 0b10101010
Endbyte:   0x55 = 0b01010101

--------------------------------------------

Habt ihr vielleicht noch Hinweise, was man verbessern könnte? Muss ich 
mir eine Option für eine 2byte Prüfsumme offen halten?

Wonach wähle ich den Grad meines Generatorpolynoms für meine CRC 
Checksum?
Darf man die frei wählen?

: Bearbeitet durch User
von cppler (Gast)


Lesenswert?

Willy M. schrieb:

> Aufbau:
>
> Startbyte | Befehlbyte(s) | Datum-/Datenbyte(s) | CRC | Endbyte
> (so wie von cppler vorgeschlagen)
>
> Startbyte: 0xAA = 0b10101010
> Endbyte:   0x55 = 0b01010101
>
> --------------------------------------------
>
> Habt ihr vielleicht noch Hinweise, was man verbessern könnte? Muss ich
> mir eine Option für eine 2byte Prüfsumme offen halten?

Du hast jetzt grundsätzlich drei Möglichkeiten wegen der variablen 
Anzahl von Daten/Befehlen:

1. Du machst für jeden Befehl und Datum ein anderes Startbyte bzw. einen 
Code danach um unterscheiden zu können was übertragen wird.
Also jedesmal ein einzelnes Paket übertragen.

2. Du siehst ein zusätzliches Feld vor indem die Anzahl an 
Befehlen/Daten mit übermittelt werden.

3. Du machst Dein Protokoll statisch und füllst die nicht verwendeten 
Felder mit Sonderzeichen um sie als leer zu markieren.

Die Prüfsumme muß über das gesamte Paket gehen, lies Dir z.B das mal 
durch:
http://www-stud.rbi.informatik.uni-frankfurt.de/~haase/crc.html

von W. M. (muhh)


Lesenswert?

Ich glaube ich würde mich für Variante 2 entscheiden.

Ich würde das Übertragungsprotokoll dann so implementieren, dass die 
verschiedenen Werte die aufeinander folgen gleich in entpsrechende 
Buffer einsortiert werden, d.h. ein Befehlbuffer ein Wertebuffer ein 
CRC-Buffer. Die CRC-Überprüfung würde dann ein Algorythmus machen (für 
den ich vermutlich am längsten brauche) und bei einem Fehler ein Flag 
zurückschicken, dass den PC den gleichen Befehl so lange schicken lässt, 
bis korrekt Übertragen wurde (das hattest du [ccpler] auch schon 
vorgeschlagen).

Wenn ich die Anzahl der Bytes erhöhe, muss ich dann auch das CRC Polynom 
erhöhen?
Den Link hab ich mir schon durchgelesen, aber wie ich das in C schreibe 
ist mir noch ein Rätsel...

von cppler (Gast)


Lesenswert?

Willy M. schrieb:
> Wenn ich die Anzahl der Bytes erhöhe, muss ich dann auch das CRC Polynom
> erhöhen?
> Den Link hab ich mir schon durchgelesen, aber wie ich das in C schreibe
> ist mir noch ein Rätsel...

Die einfachste Prüfsumme wäre via XOR, lies mal das z.B.:
http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/xor.html
Und hier für Arduino:
http://timzaman.wordpress.com/code-c-arduino/checksum-xor-cpp/
Und alle "dummen" Fragen zu CRC allgemein:
http://www.flipcode.com/documents/crc.txt
Achja allgemein geht es um Parität:
http://de.wikipedia.org/wiki/Parit%C3%A4tsbit
Dir reicht es wenn Du einen Bitfehler erkennst und immer wieder neu 
senden kannst.

von W. M. (muhh)


Lesenswert?

Kann ich mein USARTC0.DATA Register mehrmals auslesen?

Gilt
1
if (USARTC0.DATA == STARTBYTE_bm) ... ;

als auslesen?

: Bearbeitet durch User
von Frank (Gast)


Lesenswert?

Ich habe ein Projekt, bei dem zwei XY-montierte Servos einen 
Laserpointer auf ein Regal richten, um anzuzeigen, wo etwas entnommen 
werden soll ("pick by light"). Diese Einheit wird von einem Arduino 
gesteuert, der per Ethernet seine Kommandos empfängt. In das IP-Socket 
kann man genau so seriell schreiben und am anderen Ende Lesen, wie bei 
der "normalen" seriellen bzw. USB-Verbindung. Ich schreibe immer 
Kommandos, die aus 6 Bytes bestehen:

- Startkennung (>127)
- Befehlskennung (>127, zB. X-Pos, Y-Pos, Laser an/aus/blink)
- High-Byte (<127)
- Low-Byte (<127)
- Prüfbyte (xor aus hig und low)
- Endekennung (>127)

Jedes eintreffende Byte wird in eine Quewe mit 6 Positionen geschoben. 
Also das älteste Byte gelöscht, die fünf weiteren um eine Position 
verschoben und das neue Byte auf die letzte Position geschrieben. Nach 
jedem empfangenen Byte werden die Bedingungen geprüft. Wird ein gültiges 
Kommando erkannt, werden die Paramter übernommen, die gesamte Quewe 
gelöscht, eine Bestätigung zum PC zurückgesendet und das Kommando 
ausgeführt. Empfängt der PC nach 6 gesendeten Bytes und einer kurzen 
Wartezeit keine Quittung, wird die letzte Sendung wiederholt ...

von W. M. (muhh)


Lesenswert?

Frank schrieb:
> Jedes eintreffende Byte wird in eine Quewe mit 6 Positionen geschoben.
> Also das älteste Byte gelöscht, die fünf weiteren um eine Position
> verschoben und das neue Byte auf die letzte Position geschrieben.

Wie sieht denn soetwas aus? Nehme ich ein Array dafür? Dann wäre mein MC 
beim Empfangen von Daten doch nur damit beschäftigt die Daten von einem 
ins andere Feld zu verschieben oder?
Und was passiert wenn das Array am Anfang noch leer ist, woher weiß den 
mein MC wo er einen Wert lesen muss, oder wird solange gewartet, bis so 
viele Daten gesendet wurden, dass z.B. mein Startbit bei arry[0] 
angelangt ist, weil immer an dieser Stelle gelesen wird?

von cppler (Gast)


Lesenswert?

Willy M. schrieb:
>  Nehme ich ein Array dafür?

Du solltest Dich erstmal mit USART beschäftigen und erkennen was man für 
eine kontinuierliche Datenübertragung braucht.
Üblicherweise macht man einen Ringbuffer und da Du ja Handshake hast 
sollte das kein Problem sein.
Implementiere doch erstmal was ich schon erklärt habe, ohne CRC und nur 
um das Handshake zu testen.
Dann nimmst Du Dir das CRC vor und dann die Steuerung des µCs ...

von Chris (Gast)


Lesenswert?

Hier ein Beispiel eines solchen Codes

static volatile unsigned char cmd[9]; // cmd+args

ISR( USARTC0_RXC_vect ) //
{ static unsigned char idx,crc=-1; char tmp; tmp=cmd[1]&7;
  crc+=cmd[idx]=USARTC0.DATA; // anstelle von += kann auch ^= sein
  if(idx)if(--idx);else if(crc)cmd[1]=0x10|tmp;
                        else*cmd^=(cmd[1]=0x8|tmp|*cmd&~31)&~31;
  else idx=(*cmd>>5)+1,crc=~*cmd;
}

cmd[1].b0-b2 = saved user state machine or user flags
cmd[1].b3 = new_cmd
cmd[1].b4 = new_cmd_crc_error
cmd[1].b5-b7=argument count
cmd[0]    = 5bit cmd
cmd[2-8]  = args // kann auf word/.. erweitert werden.

von W. M. (muhh)


Lesenswert?

Ich habe da doch nochmal eine-zwei Fragen.

Wieso benötige ich ein Endbit? Meine Framestrucktur sieht so aus:

Startbyte | FrameConfig Byte | Cmd Byte | (Cmd Byte) | Data Byte | ... | 
CRC Byte | (Endbyte)

Wenn ich mit dem FrameConfig Byte sowieso dynamisch festlegen kann, wie 
die folgenden Daten interpretiert werden sollen (z.B. 2 Cmd Bytes und 
nur ein Data Byte), dann weiß die MCU doch sowieso, nach wieviel Byte 
die Übertragung fertig ist oder?

Was mache ich wenn Daten ankommen, wo kein Startbit erkannt wird? Sollen 
die dann einfach gelöscht oder erst garnicht in den FIFO-Buffer 
geschireben werden?

von cppler (Gast)


Lesenswert?

Willy M. schrieb:
> Ich habe da doch nochmal eine-zwei Fragen.
>
> Wieso benötige ich ein Endbit? Meine Framestrucktur sieht so aus:
>
> Startbyte | FrameConfig Byte | Cmd Byte | (Cmd Byte) | Data Byte | ... |
> CRC Byte | (Endbyte)
>
> Wenn ich mit dem FrameConfig Byte sowieso dynamisch festlegen kann, wie
> die folgenden Daten interpretiert werden sollen (z.B. 2 Cmd Bytes und
> nur ein Data Byte), dann weiß die MCU doch sowieso, nach wieviel Byte
> die Übertragung fertig ist oder?
>
> Was mache ich wenn Daten ankommen, wo kein Startbit erkannt wird? Sollen
> die dann einfach gelöscht oder erst garnicht in den FIFO-Buffer
> geschireben werden?

Du hast Dir also immer noch keinen Ablaufplan auf ein Blatt Papier 
geschrieben.
Ob Du nun in Deiner Routine berechnest wie viele Datenpakete noch zu 
empfangen sind oder einfacher auf's Endbyte wartest bleibt Dir 
überlassen.
Wenn kein Startbyte kommt wird nix gemacht bis eines klar erkannt wurde.
Dann packst Du die Bytes in den Ringpuffer.
Wenn alles richtig im Puffer steht sendest Du das ACK and den PC und 
arbeitest in der Hauptschleife den Puffer ab.
Und nun nimm Dir ein Blatt Papier und erstelle einen Ablaufplan NUR für 
die Kommunikation ...

von W. M. (muhh)


Lesenswert?

Ich versuche es ja, aber erstmal bin ich nicht gut darin, Ablaufpläne zu 
erstellen, zweitens zerbreche ich mir immer den Kopf über die Bedingung.

Folgendes habe ich: (ohne Überprüfung, ob die daten richtig gesendet 
wurden)


TF: Transmission Flag
1
Start
2
  |
3
  |  PC sendet Daten
4
  |                                                false
5
Wenn (Startbyte == USARTC0.DATA) und (TF == 0) -------------> warte auf Startbyte
6
  |
7
  | true
8
  |
9
setze TF
10
  |
11
  |                 false
12
Wenn TF gesetzt ----------------> warte auf Startbyte
13
  |
14
  | true
15
  |                        false
16
FIFO Buffer schreiben <---------------
17
  |                                   |
18
  |                                   |
19
Wenn (USARTC0.DATA == Endbyte) -------
20
  |
21
  | true
22
  |
23
lösche TF
24
  |
25
setzte Transmission Complete Flag
26
  |
27
sende ACK an PC
28
  |
29
lösche Transmission Complete Flag

Sowas in der Art hatte ich mir vorgestellt, aber was passiert, wenn 
einer meiner Datenbytes den gleichen wert hat wie das Endbyte?

Mit dieser Variante hätte ich in der ISR 3 if-Abfragen, geht das nicht 
auch anders oder komme ich nicht darum diese 3 Abfragen in der ISR zu 
machen?

Ist das überhaupt kritisch? Ich habe immer kein Gefühl dafür, ab wann in 
der ISR "zu viel" geschieht und wann nicht...

: Bearbeitet durch User
von cppler (Gast)


Lesenswert?

Willy M. schrieb:
> Sowas in der Art hatte ich mir vorgestellt, aber was passiert, wenn
> einer meiner Datenbytes den gleichen wert hat wie das Endbyte?
>

Was passiert wenn zufällig ein Startbyte entsteht ?
Du bist für das Protokoll verantwortlich.

> Mit dieser Variante hätte ich in der ISR 3 if-Abfragen, geht das nicht
> auch anders oder komme ich nicht darum diese 3 Abfragen in der ISR zu
> machen?
>
> Ist das überhaupt kritisch? Ich habe immer kein Gefühl dafür, ab wann in
> der ISR "zu viel" geschieht und wann nicht...

In einer ISR sind mehrere ifs o.ä. kaum problematisch, nur keine anderen 
Prozeduren aufrufen oder mit delays arbeiten ...
Wie schnell willst Du denn übertragen ?

Lies Dir mal das hier durch:
http://de.wikipedia.org/wiki/Kommunikationsprotokoll

Und welchen Grund hatte ich wohl Dir als erste Lösung was vorzuschlagen 
?
Wenn Du es einfacher haben willst dann mache einen Hardwarehandshake das 
ist bei RS232 vorgesehen:
http://de.wikipedia.org/wiki/RS232

Du kannst auch einfach eine Leitung der Schnittstelle dafür 
"mißbrauchen", also sobald Dein µC einen High-Pegel am SelectPin hat 
sendet der PC und der µC muß empfangen ist der Pegel Low ist die Sendung 
zuende und es muß nichts gemacht werden.

Kommunikationsprotokolle sind nicht trivial, Du könntest z.B. eine ASCII 
Tabelle anlegen und START/STOP mit Escapesequenzen realisieren und Deine 
Befehle als Buchstaben und die Werte als Zahlen übertragen, d.h. für 255 
als Zahlenwert brauchst Du dann drei Bytes usw. usf.

In Deinem Fall willst Du ja mitschicken wieviele Pakete kommen, also 
kannst Du wie schon gesagt auf's Endbyte verzichten und nachzählen oder 
Du einigst Dich auf eine Sequenz die ansonsten nicht vorkommen darf.
Du könntest z.B. auch alle relevanten Datenbytes via XOR mit dem Endbyte 
verknüpfen oder oder oder ...

Schreibe Dir einfach auf ein Blatt Papier welche Werte zu übertragen 
sind und welche Befehle und ob Du die unterschiedlich übertragen kannst.

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.