Forum: Mikrocontroller und Digitale Elektronik µC zu langsam?


von Gast (Gast)


Angehängte Dateien:

Lesenswert?

Hi Leute,

ich habe folgendes Problem: Ich sende Packete vom PC zum µC und dann 
soll der µC darauf reagieren. Schicke ich die Packete per Hand über 
Console, dann funktioniert alles. Schicke ich allerdings die Packete per 
PC, bleibt das Programm hängen in der Abfrage.
Beispiel für ein Packet:
FF 00 01 02 03

FF = Startbedingung
00 = Seq. Nr.
01 = Länge des Packetes (wieviele Befehle bzw. Daten)
02 = Befehlsnr. (z.b. Live Übertragung)
03 = Checksumme (Länge+Befehlsnr. + eventuele Daten)

Schicke ich das per Hand, funktioniert alles (also zuerst FF, dann 
00,...) Schicke ich allerdings alles per PC oder in der Konsole direkt 
FF00010203, dann bleibt das Programm vor der Abfrage nach der Befehlsnr. 
hängen. (und wartet auf weitere Daten).

Hier die Abfragefunktion:
1
/*******************************************************
2
  Funktion :    Hole Packet / Reagiere auf Befehlscode
3
  Eigenschaften:  Gib Befehlsnummer zurück
4
  Übergabewert:  -
5
  Rückgabewert:  1 Byte Befehlsnummer (0xFF = Fehler)
6
********************************************************/
7
uint8_t usart_recieve_packet(void)
8
{
9
  uint8_t data;
10
  length = 0;
11
12
  data = usart_get();                    // Hole Start-Signal
13
  if (data == COMMAND_START)                 // Wurde Start übermittelt?
14
  {
15
    data = usart_get();                  // Hole Seq Nr
16
    if(data == seq_nr)                  // Stimmen Seq Nummern überein?
17
    {
18
      length = usart_get();              // Hole Länge
19
      data = usart_get();                // Hole Befehlsnr.
20
      switch(data)
21
      {
22
        case COMMAND_SEND_ALL_DATA:          //Schicke alle Daten
23
        {
24
          data = usart_get();              // Hole Pruefsumme
25
          checksum = length + COMMAND_SEND_ALL_DATA;  // Berechne Pruefsumme
26
27
          if (data == checksum)
28
          {
29
            usart_seq_plus();          // Erhöhe Sequenz nr.
30
            return COMMAND_SEND_ALL_DATA;    // Return Befehlsnr.
31
          }
32
          else
33
          {
34
            usart_error(EC_USART_SEND_ALL_DATA);
35
            return 0xFF;            // Fehler
36
          }
37
        } break;
38
39
        case COMMAND_LIVE_MODUS:          //Live Übertragung
40
        {
41
          data = usart_get();            // Hole Pruefsumme
42
          checksum = length + COMMAND_LIVE_MODUS;  // Berechne Pruefsumme
43
  
44
          if (data == checksum)
45
          {
46
            usart_seq_plus();          // Erhöhe Sequenz nr.
47
            return COMMAND_LIVE_MODUS;      // Return Befehlsnr.
48
          }
49
          else
50
          {
51
            usart_error(EC_USART_LIVE_MODUS);
52
            return 0xFF;            // Fehler
53
          }
54
        } break;
55
56
        case COMMAND_LIVE_MODUS_STOP:        // Live Stopp
57
        {
58
          data = usart_get();            // Hole Pruefsumme
59
          checksum = length + COMMAND_LIVE_MODUS_STOP;  // Berechne Pruefsumme
60
61
          if (data == checksum)
62
          {
63
            usart_seq_plus();          // Erhöhe Sequenz nr.
64
            return COMMAND_LIVE_MODUS_STOP;    // Return Befehlsnr.
65
          }
66
          else
67
          {
68
            usart_error(EC_USART_LIVE_MODUS_STOP);
69
            return 0xFF;            // Fehler
70
          }
71
        } break;
72
73
        case COMMAND_RECEIVE_TIME:           //Uhrzeit empfangen
74
        {
75
          //Hole Uhrzeit-Daten
76
          pc.year = usart_get();
77
          pc.month = usart_get();
78
          pc.date = usart_get();
79
          pc.hours = usart_get();
80
          pc.minutes = usart_get();
81
          pc.seconds = usart_get();
82
83
          data = usart_get();            // Hole Pruefsumme
84
          checksum = length + COMMAND_RECEIVE_TIME + pc.year + pc.month + pc.date + pc.hours 
85
                + pc.minutes + pc.seconds;   // Berechne Pruefsumme
86
87
          if (data == checksum)
88
          {
89
            usart_seq_plus();          // Erhöhe Sequenz nr.
90
            flag.right_values = 1;        // Werte waren richtig (wegen Prüfsumme)
91
            return COMMAND_RECEIVE_TIME;    // Return Befehlsnr.
92
          }
93
          else
94
          {
95
            flag.right_values = 0;        // Werte waren falsch (wegen Prüfsumme)
96
            usart_error(EC_USART_RECEIVE_TIME);
97
            return 0xFF;            // Fehler
98
          }
99
        } break;
100
101
        case COMMAND_RECEIVE_ACK:           // ACK empfangen
102
        {
103
          pc_seq_nr = usart_get();        // Hole Seq Nr
104
          data = usart_get();            // Hole Pruefsumme
105
          checksum = length + COMMAND_RECEIVE_ACK + pc_seq_nr; // Berechne Pruefsumme
106
107
          if(data == checksum)
108
          {
109
            usart_seq_plus();          // Erhöhe Sequenz nr.
110
            return COMMAND_RECEIVE_ACK;      // Return Befehlsnummer
111
          }
112
          else
113
          {
114
            usart_error(EC_USART_RECEIVE_ACK);
115
            return 0xFF;            // Fehler
116
          }              
117
        } break;
118
119
        case COMMAND_PARAMETERS:          //Paramters
120
        {
121
          
122
          // Hole Startzeit
123
          start.year = usart_get();
124
          start.month = usart_get();
125
          start.date = usart_get();
126
          start.hours = usart_get();
127
          start.minutes = usart_get();
128
          start.seconds = usart_get();
129
130
          //Hole Endzeit
131
          end.year = usart_get();
132
          end.month = usart_get();
133
          end.date = usart_get();
134
          end.hours = usart_get();
135
          end.minutes = usart_get();
136
          end.seconds = usart_get();
137
138
          // Hole Sampling Rate
139
          // Speichere in Zwischenvariablen für Pruefsumme
140
          sampling_rate_array[0] = usart_get();
141
          sampling_rate_array[1] = usart_get();
142
          sampling_rate_array[2] = usart_get();
143
144
          sampling_rate = sampling_rate_array[0];        // Schreibe 1tes Byte
145
          sampling_rate = (sampling_rate << 8);        // Verschiebe 1tes Byte
146
          sampling_rate |= sampling_rate_array[1];      // Schreibe 2tes Byte
147
          sampling_rate = (sampling_rate << 8);        // Verschiebe 2tes Byte
148
          sampling_rate |= sampling_rate_array[2];      // Schreibe 3tes Byte
149
          
150
          // Hole Messwertemaske
151
          // Speichere in Zwischenvariablen für Pruefsumme
152
          measurement_mask_array[0] = usart_get();
153
          measurement_mask_array[1] = usart_get();
154
          measurement_mask_array[2] = usart_get();
155
          measurement_mask_array[3] = usart_get();
156
          measurement_mask_array[4] = usart_get();
157
          measurement_mask_array[5] = usart_get();
158
159
          measurement_mask_high = measurement_mask_array[0];  // Wie bei sampling rate (oben)
160
          measurement_mask_high = (measurement_mask_high << 8);
161
          measurement_mask_high |= measurement_mask_array[1];
162
163
          measurement_mask_low = measurement_mask_array[2];
164
          measurement_mask_low = (measurement_mask_low << 8);
165
          measurement_mask_low |= measurement_mask_array[3];
166
          measurement_mask_low = (measurement_mask_low << 8);
167
          measurement_mask_low |= measurement_mask_array[4];
168
          measurement_mask_low = (measurement_mask_low << 8);
169
          measurement_mask_low |= measurement_mask_array[5];
170
          
171
          data = usart_get();                  // Hole Pruefsumme
172
          
173
          // Berechne die Pruefsumme
174
          checksum = length + COMMAND_PARAMETERS + start.year + start.month + start.date + start.hours + start.minutes + start.seconds
175
                 + end.year + end.month + end.date + end.hours + end.minutes + end.seconds + sampling_rate_array[0]
176
                 + sampling_rate_array[1] + sampling_rate_array[2] + measurement_mask_array[0] 
177
                 + measurement_mask_array[1] + measurement_mask_array[2] + measurement_mask_array[3] 
178
                 + measurement_mask_array[4] + measurement_mask_array[5];
179
180
          if(data == checksum)
181
          {
182
            usart_seq_plus();                // Erhöhe Sequenz nr.
183
            flag.right_values = 1;              // Werte richtig (wegen Prüfsumme)
184
            return COMMAND_PARAMETERS;            // Return Befehlsnr.
185
          }
186
          else
187
          {
188
            flag.right_values = 0;              // Werte falsch (wegen Prüfsumme)
189
            usart_error(EC_USART_COMMAND_PARAMETERS);
190
            return 0xFF;                  // Fehler
191
          }
192
        } break;
193
        
194
        case COMMAND_STATUS_REQUEST:          // Status-senden Aufforderung
195
        {
196
          data = usart_get();              // Hole Pruefsumme
197
          checksum = length + COMMAND_STATUS_REQUEST;  // Berechne Pruefsumme
198
199
          if (data == checksum)
200
          {
201
            usart_seq_plus();          // Erhöhe Sequenz nr.
202
            return COMMAND_STATUS_REQUEST;    // Return Befehlsnr.
203
          }
204
          else
205
          {
206
            usart_error(EC_USART_STATUS_REQUEST);
207
            return 0xFF;            // Fehler
208
          }
209
        } break;
210
        
211
        case COMMAND_RESET:
212
        {
213
          goto packet_reset;
214
        }
215
        default:            // Falscher Befehlscode
216
        {
217
          usart_error(EC_USART_WRONG_CODE);
218
          return 0xFF;        // Fehler
219
        }
220
      }
221
    }
222
    else
223
    {
224
      length = usart_get();              // Hole Länge
225
      data = usart_get();
226
227
      if(data == COMMAND_RESET)
228
      {
229
        packet_reset:
230
        data = usart_get();              // Hole Pruefsumme
231
        checksum = length + COMMAND_RESET;      // Berechne Pruefsumme
232
        
233
        if (data == checksum)
234
        {
235
          usart_seq_plus();          // Erhöhe Sequenz nr.
236
          return COMMAND_RESET;        // Return Befehlsnr.
237
        }
238
        else
239
        {
240
          usart_error(EC_USART_RESET);
241
          return 0xFF;            // Fehler
242
        }
243
244
      }
245
      else
246
      {
247
        usart_error(EC_USART_WRONG_SEQ);  // Falsche Seq Nr. ==> Error
248
        return 0xFF;            // FEHLER
249
      }
250
    }
251
  }
252
  else
253
  {
254
    usart_error(EC_USART_NO_START);      // Kein Start erhalten ==> Error
255
    return 0xFF;              // FEHLER
256
  }
257
}

Ich benutze übrigens einen 8 MHz Quarz und eine Baudrate von 19200. (bei 
höheren Baudraten werden immer falsche Daten übertragen) Wenn ich im PC 
Programm ein Delay von 50 ms einbaue, funktioniert es wieder... aber 50 
ms ist schon sehr sehr groß....

Hat jemand eine Idee, woran es liegen kann? Im Prinzip mache ich ja 
zwischen den Abfragen nicht viel! Also warum ist der µC zu langsam?
Sicherheitshalber habe ich das ganze Projekt noch angehängt. (fehler ist 
in usart.c)

von Εrnst B. (ernst)


Lesenswert?

Probiers mal mit nem Baudratenquarz. Der Fehler ist zwar jetzt 
(8MHz/19200Baud) nur bei 0.2%, aber vielleicht schaukelt sich das bei 
vielen Bytes hintereinander auf. Mit der Pause dazwischen entzerrt sich 
das ganze dann wieder.

von Gast (Gast)


Lesenswert?

Baudratenquarz ist nicht. Das ganze muss bis morgen funktionieren oO 
Können die 2 if Abfragen daran Schuld sein? Sprich, dass während dennen 
kein Signal empfangen wird?

von Peter (Gast)


Lesenswert?

Oder probiere es mal mit 9600 Baud...

Schon möglich dass der uC bzw Dein Programm zu langsam ist! Ich würde 
die UART-Kommunikation in eine ISR packen, dann kannst Du auch locker 
mit 115200 Baud arbeiten.

von Peter (Gast)


Lesenswert?

leider ist dein Programm nicht so leicht zu verstehen, viel zu viel 
geschachtelt. Die vermutung ist das der Fehler nicht in der funktion 
usart_recieve_packet ist sondern schon vorher, der Atmel kann ja bloss 
1byte buffern, wenn du jetzt zu lange braucht um in die funktion 
usart_recieve_packet zu kommen dann gehen dir zeichen verloren.

Warum macht du die ganze sache nicht in einer ISR, jedesmal wenn ein 
zeichen ankommt?

von Uwe .. (uwegw)


Lesenswert?

Es könnte helfen, die Daten vom UART erst mal in einem Ringbuffer zu 
speichern, und sie dann in Ruhe zu bearbeiten. Es könnte nämlich sein, 
dass du mit irgendeiner Berechnung länger brauchst als die Zeit zwischen 
zwei Bytes. Du wartest ja immer auf ein Byte, dann passiert was, und 
dann wird wieder gewartet. Wenn nun die Berechnung nach einem Byte so 
lange dauert, dass inzwischen mehr als ein Byte angekommen ist, gehen 
Bytes verloren.

Schau dir mal die UART-Lib von http://jump.to/fleury an. Dort ist so ein 
Ringbuffer drin. Die Daten werden im Interrupt empfangen, und das 
Hauptprogramm kann sie dann verarbeiten, wenn es Zeit dafür hat.

von Gast (Gast)


Lesenswert?

Ok, wenn er z.b. ein Live Packet schickt, dann sendet er:

FF 00 01 02 03

Er sendet FF, danach gibt es eine IF Abfrage.
Danach sendet er 00, und es gibt wieder eine If Abfrage.
Anschließend kommt 01 und 02. Und dann ein Select Case.
Anschließend würde er die Checksum holen (also 03).

Fakt ist, er bleibt aber schon nach der 3ten Abfrage hängen (also nach 
01). Dazwischen befinden sich nur 2 IF Abfragen und sonst gar nichts.

Ich habe diese 2 IF Abfragen jetzt sogar rausgenommen und hole direkt 
alle Werte von USART, allerdings fehlen wieder die letzteren!

Die Funktion wird allgemein erst gestartet, wenn etwas im USART Speicher 
ist.
Das FF erhalte ich richtig, genauso die Seq Nr (00) und auch die Länge 
(01) nur ich erhalte einfach kein 02 und 03 mehr! Obwohl keine Befehle 
dazwischen sind!


Wie schauts mit diesem 1k Byte Buffer aus??? Ich benutze einen atmega32L 
und habe 47% Programmspeicher voll und 96,8% Variablenspeicher.

von Peter (Gast)


Lesenswert?

bist auch sicher das du die bytes in der Reihenfolge empfängst? Denn die 
IF anweissung ist auf jeden Fall schnell genug.
Es ist aber nicht genau zu erkennen wieviel Zeit dein Programm von dem 
FF bis zu aufruf der Funktion usart_recieve_packet braucht. Wenn diese 
Zeit zu lang ist, dann kannst du später auch nichts mehr retten.

von Ulrich (Gast)


Lesenswert?

Wenn man einen kleinen Fehler in der Bautrate hat, hilft es manchmal 
beim Sender (PC) 2 Stoppbits einzustellen. Dann können sich Fehler duch 
ein zu kurzes Stopbit nicht aufaddieren.

Der Ringpuffer ist ein Speicher mit z.B. 32 Bytes Länge, der immer Reihe 
rum genutzt wird. Dazu gibts einen Index zum Schreiben und eine zu 
Lesen. Das könnte aber eng werden mit nur noch rund 3% freiem RAM.


Ein Problem in dem Programm könnte sein, zum Teil etwas auch einer 
anderen UART ausgegeben wird, wenn die Daten nicht dem Mustser 
entsprechen. Dann gibt es natürlich probleme, denn dann kommen die daten 
schneller als man sie auswertet.

von Benjamin S. (recycler)


Lesenswert?

meiner meinung, braucht die abarbeitung länger als dein isr
deshalb wird in der isr der alte wert (der buffer) überschreiben und 
deine statemachine läuft sonst wo hin.

ich würde es so machen.
_______________________________________
isr_uart:
wenn neues byte -> puffer + got_data=1
_______________________________________
statemachine:

while (!got_data);
data = buffer;

von Gast (Gast)


Lesenswert?

Hmmm hab jetzt den Fehler... das erste Packet ist 08. D.h. die vorrigen 
werden überschrieben und der Grund liegt in einer Joystick Abfrage, 
welche zu Lange dauert. Ohne dieser Abfrage funktioniert alles!

Aber wie löse ich jetzt das Problem?? Ich benötige diesen Joystick... 
Und Ringbuffer wie gesagt, 3% nur noch frei außerdem empfange ich 
x-beliebig viele Daten... sprich bei Befehlsnr 03 nur 1 Byte Daten, bei 
Befehlsnr. 08 dann schon 20 Byte Daten?

von Peter (Gast)


Lesenswert?

>Ich benutze einen atmega32L und habe 47% Programmspeicher voll
>und 96,8% Variablenspeicher.

96,8% ? Da würde ich mal davon ausgehen, dass es knallt, weil Du zuwenig 
Speicher für den Stack hast!

von Peter (Gast)


Lesenswert?

die musst vermutlich einige Teile des Programmes umschreiben. Du hast 
jetzt einige Timingprobleme. Wenn du in der Funktion 
usart_recieve_packet bist dann wartet er auf jedes Zeichen einzeln in 
der Zeit ist deine Main stillgelegt.

Verlagere das Empfangen von Daten auf der UART in die ISR, eventuell 
auch das Prüfen des Paketes aber nicht die Komplette bearbeitung.

Setzte ein Flag das die Main weiss, das ein neues Paket empfangen wurde 
und verarbeite es.

In der gleichen Art und weisse musst du das mit dem Joystick machen. In 
der Main sollte also die die Ababreitung von den Daten erfolgen das 
Erfassen der Daten kann man meist in die ISR auslagern, damit sollte es 
dann schon gehen

von Gast (Gast)


Lesenswert?

Sorry Leute wenn ich jetzt nerve, aber kann mir bitte jemand kurz ein 
Codestück geben, wie ich das Interrupt einprogrammiere?

Also nur was ich machen muss, damit Funtkion xy beim Interrupt ausgelöst 
wird oO
(habe vorher noch nie mit interrupts programmiert :/ und ich sollte das 
heute noch fertig bekommen)

Danke aufjedenfall schon

von Karl H. (kbuchegg)


Lesenswert?

Am besten schaust du dir wirklich die UART Lib vom Peter Fleury (danach 
googeln) an. Dort solltest du alles finden was du brauchst.

von rene (Gast)


Lesenswert?

Zwar in pascal, aber...
http://www.ibrtses.com/embedded/avruart.html
dafuer auch mit einer Zustandsmaschine im Interrupt und der 
nichtblockierenden verarbeitung im Main.

von Benjamin S. (recycler)


Lesenswert?

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=48188

Als erstes Einstellungen vornehmen und Interrupt aktivieren.
Die Empfangsroutine könnte so aussehen:
1
char ReceivedByte; // globales byte
2
uint8_t got_byte;
3
4
ISR(USART_RXC_vect)
5
{
6
      ReceivedByte = UDR;
7
      got_byte = 1;
8
}

von Karl H. (kbuchegg)


Lesenswert?

Fleury-UART-Lib:

Und wenn irgendwie geht, würde ich sie so verwenden wie sie dir vom 
Peter gegeben wird. D.h. incl Ringbuffer.
Irgendwo wirst du schon noch ein paar Bytes SRAM freischaufeln können, 
um dir den Ringbuffer leisten zu können. Und wenn es nur 10 Bytes 
Ringbuffer sind, die dich davon befreien jedes einzelne Byte just in 
Time abholen zu müssen.

von Gast (Gast)


Lesenswert?

Sorry ich verstehs immer noch nicht ganz.... (und im Datenblatt ist das 
in meinen Augen blöd beschrieben...)

Also zuerst aktiviere ich die Interrupts mit sei();
Außerdem muss ich die Header Datei avr/interrupt.h includen

Anschließend komme ich automatisch in die Funktion:

ISR(USART_RXC_vect)
{
}

wenn ich Daten empfange??????? Oder muss ich davor noch irgendetwas 
machen?
Wenn ich diese Funktion einbaue, bekomme ich gleich mal 3 Warrnings:

../usart.c:819: warning: return type defaults to 'int'
../usart.c:819: warning: type of '__vector_13' defaults to 'int'
../usart.c:821: warning: control reaches end of non-void function


Ok 2 Fehlermeldungen kann ich weg machen, indem ich int vor dem 
Funktionsnamen schreibe und ein return einbaue. Aber was soll diese 2te 
Fehlermeldung????

Stimmt das so, wie ich es geschrieben habe? (ich will nicht wissen, was 
in der Funktion stehen soll, sondern wie ich über ein Interrupt diese 
Funktion aufrufe!)

von Karl H. (kbuchegg)


Lesenswert?

Gast schrieb:
> Also zuerst aktiviere ich die Interrupts mit sei();

Nein. Das machst du zum Schluss, wenn alles konfiguriert ist.

> Außerdem muss ich die Header Datei avr/interrupt.h includen

Ja

> Anschließend komme ich automatisch in die Funktion:

Nein. Kommst du nicht. Du musst die UART Interrupts auch noch spezifisch 
freigeben.

>
> ISR(USART_RXC_vect)
> {
> }
>
> ../usart.c:819: warning: return type defaults to 'int'
> ../usart.c:819: warning: type of '__vector_13' defaults to 'int'
> ../usart.c:821: warning: control reaches end of non-void function

Dann stimmt wahrscheinlich der ISR Name nicht.
Sieh in der spezifischen io.h nach, wie er wirklich heisst.

> Stimmt das so, wie ich es geschrieben habe? (ich will nicht wissen, was
> in der Funktion stehen soll, sondern wie ich über ein Interrupt diese
> Funktion aufrufe!)

Warum holst du dir nicht die Fleury Lib? Da ist das alles bereits 
fertig, inkl funktionierendem Testprogram.

von Gast (Gast)


Lesenswert?

Und wie kann ich die Interrupts freigeben (bzw. dieses spezielle für 
USART receive)? Habs jetzt schon hinbekommen, dass der name usw. passt, 
allerdings komme ich eben nicht in diese Funktion (wegen der fehlenden 
Konfiguration) Und im Datenblatt finde ich dazu nichts (oder ich bin 
einfach nur blind) Kann mir bitte das jemand kurz sagen, wird bestimmt 
eh nur 1-2 Zeilen sein oO (atmega32)

von Gast (Gast)


Lesenswert?

Datenblatt Seite 152
1
When the Receive Complete Interrupt Enable (RXCIE) in UCSRB is set, the USART Receive
2
Complete Interrupt will be executed as long as the RXC Flag is set (provided that global inter-
3
rupts are enabled). When interrupt-driven data reception is used, the receive complete routine
4
must read the received data from UDR in order to clear the RXC Flag, otherwise a new interrupt
5
will occur once the interrupt routine terminates.

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.