Forum: Compiler & IDEs _delay_ms(500) funktioniert nur sporadisch


von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

zum Thema "_delay_ms()" gibt's ja schon einige Beiträge, aber habe 
leider keine Lösung zu meinem konkreten Problem gefunden...

Also ich habe ein Programm mit folgender Funktionalität/Ablauflogik 
geschrieben:

- Empfangen und Dekodieren einer IR-Sequenz (NEC-Standard) (Modus=0)
--> empfangene 32 Datenbits werden in die Variable "datenbits" 
geschrieben

- anschließend Anzeige der 4 Datenbytes (Modus=1)
--> dabei soll zwischen den 4 Zahlen jeweils eine halbe Sekunde Pause 
(Display aus) eingelegt werden.

Hier der Codeausschnitt dafür:

for (i=0;i<4;i++)
{
displayZahl(datenbyte[i],dauer);
_delay_ms(500);
}

In der Anlage der gesamte Code des Programms, damit der Kontext klar 
wird (die besagte Stelle ist auf S. 5 rot markiert). Bitte nicht durch 
die Länge des Codes abschrecken lassen, es geht nur um die o. g. 
Schleife...

Ich habe gelesen, dass eventuell Interrupts _delay_ms() beeinflussen 
könnten (aber eher, dass die Verzögerung länger wird). M. E. sollte das 
in meinem Programm aber nicht das Problem sein (ich hatte zur Sicherheit 
auch mal das _delay_ms() in ein cli()... sei() eingeschlossen). Außerdem 
fällt die Pause manchmal aus und wird nicht länger.

Das Programmverhalten ist so, dass in etwa der Hälfte der Durchläufe die 
Pause korrekt eingehalten wird - in der anderen Hälfte fehlen ein oder 
zwei Pausen (z. B. zwischen 1. und 2. Zahl oder zwischen 3. und 4. 
Zahl). Das Verhalten ist ziemlich "wechselhaft" (habe kein Muster 
erkannt)

Ich kann mir das nicht erklären, da nach dem Aufruf displayZahl() der 
Delay kommt und dann erst die nächste Zahl angezeigt werden soll... hat 
jemand eine Idee?

Vielen Dank!

: Verschoben durch Admin
von Oliver J. (skriptkiddy)


Lesenswert?

Bitte als Textdatei anhängen mit der Endung c.

Gruß Oliver

von Electronics'nStuff (Gast)


Lesenswert?

Aber sonst funktioniert das Programm einwandfrei?

von Electronics'nStuff (Gast)


Lesenswert?

Und wenn ich dir noch einen Tipp geben darf (hat eig. nix mit dem Thema 
zu tun)..

if(eingabe) ist das gleiche wie if(eingabe ==1)
und if
(!eingabe) ist das gleiche wie if (eingabe == 0)

von Georg G. (df2au)


Lesenswert?

Electronics'nStuff schrieb:
> if(eingabe) ist das gleiche wie if(eingabe ==1)

uint8t eingabe,
[...]
eingabe = 123;

Immer noch identisch? Stell dir vor, eingabe ist der Rückgabewert einer 
Zeicheneingabe und 0x00 bedeutet "nichts vorhanden".

von Thomas E. (thomase)


Lesenswert?

Georg G. schrieb:
> Immer noch identisch?
Immer.
Egal, was du dir vorstellst.

mfg.

von Electronics'nStuff (Gast)


Lesenswert?

Georg G. schrieb:
> Immer noch identisch?

Naja, diese Aussage war nicht auf Variabeln sondern auf Eingänge bezogen 
(darum auch der kreative Name "eingang").

Ich glaube nicht, dass ein Eingang den Wert 123 annehmen kann, würde 
mich doch sehr wundern.

von Georg G. (df2au)


Lesenswert?

Thomas Eckmann schrieb:
> Egal, was du dir vorstellst.

Dann viel Spaß mit deinen Programmen...
if (eingabe == 1)
ist also das gleiche wie
if (eingabe != 0)
oder
if (eingabe == 123)

Aber man lernt ja nie aus...

von Thosch (Gast)


Lesenswert?

>> if(eingabe) ist das gleiche wie if(eingabe ==1)

Thomas Eckmann schrieb:
>> Immer noch identisch?
> Immer.
> Egal, was du dir vorstellst.

Hmm, wohl kaum.
if(eingabe) ist das gleiche wie if(eingabe != 0)
und nicht das gleiche wie if(eingabe == 1).

man sollte sich aber nie darauf verlassen, daß ein boolscher Ausdruck
genau gleich 1 oder gleich 0 ist.

von Thomas E. (thomase)


Lesenswert?

Georg G. schrieb:
> Dann viel Spaß mit deinen Programmen...
Danke.

Thosch schrieb:
> man sollte sich aber nie darauf verlassen, daß ein boolscher Ausdruck
> genau gleich 1 oder gleich 0 ist.
Ein boolescher Ausdruck ist true oder false.

mfg.

von Georg G. (df2au)


Lesenswert?

Thomas Eckmann schrieb:
>> man sollte sich aber nie darauf verlassen, daß ein boolscher Ausdruck
>> genau gleich 1 oder gleich 0 ist.
> Das ist so ziemlich das einzige, worauf man sich verlassen kann.

Also... ich habe mal gelernt, dass man sich auf false = 0 verlassen 
kann. Und true definiert sich als !false, nicht aber als 1.

Aber das ist Jahrzehnte her, möglich, dass man das heute anders sieht 
(was dann die Güte und Zuverlässigkeit vieler moderner Programme 
erklären würde).
(SCNR)

von Thomas E. (thomase)


Lesenswert?

Georg G. schrieb:
> Also... ich habe mal gelernt, dass man sich auf false = 0 verlassen
> kann. Und true definiert sich als !false, nicht aber als 1.
Da hat sich ja auch nichts dran geändert.
Deswegen fragt man das ja auch nicht so ab: if(a == 1), sondern if(a).

Georg G. schrieb:
> if (eingabe == 123)
Das ist eine Abfrage auf ein Integer.

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Mike schrieb:

Der Code kommt mir sehr bekannt vor.
Den hatten wir doch vor ein paar Tagen schon mal. Wie war denn da in 
diesem Thread die letzte Erkenntnis?

> zum Thema "_delay_ms()" gibt's ja schon einige Beiträge, aber habe
> leider keine Lösung zu meinem konkreten Problem gefunden...

Dein Problem hat ziemlich sicher nichts mit dem _delay_ms zu tun. Dort 
manifestiert sich nur das Problem. Sprich: Du siehst da die Symptome. 
Aber dein Problem liegt woanders.

von Karl H. (kbuchegg)


Lesenswert?

Ich sag nicht, dass es DER Fehler ist. Aber es ist EIN Fehler.

> volatile uint8_t ziffer[3]; // 4 Ziffern fuer aktuell anzuzeigende Zahl

No. Ein Array der Länge 3 hat auch nur 3 Elemente. Ein 4.tes existiert 
nicht.

Wenn du an ziffer[3] etwas zuweist, dann knüddelst du dir irgendwas 
anderes im Speicher nieder. Nur Gott alleine weiß, was dann alles 
passiert (oder ich, wenn ich es lang genug ananylsiere. Aber dazu hab 
ich erst mal keine Lust).

von Karl H. (kbuchegg)


Lesenswert?

> uint8_t datenbyte[3]; // Aufsplitten in 4 Bytes fuer Anzeige

selbiges in Grün.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Georg G. schrieb:
> Und true definiert sich als !false, nicht aber als 1.

Nein, das war noch nie so.  true (im Sinne des Ergebnsises der
Vergleichsoperatoren) hatte in C schon immer den Wert 1 und nichts
anderes, wie du im C Reference Manual von 1975 schon nachlesen kannst:

http://cm.bell-labs.com/cm/cs/who/dmr/cman.pdf

Mit diesem Wert ist es später auch im Standard festgeschrieben worden.

Allerdings muss man natürlich unterscheiden: diese Aussage bezieht
sich ausschließlich auf das Ergebnis der Operatoren, die einen
Booleschen Wert zum Ziel haben.  Die Anweisungen, die auf Wahrheit
oder Falschheit testen, akzeptieren (und zwar ebenfalls durch den
Standard garantiert) außer dem Wert 1 auch jeden beliebigen anderen
von 0 verschiedenen Wert als "wahr".

von Mike (Gast)


Lesenswert?

Electronics'nStuff schrieb:
> Aber sonst funktioniert das Programm einwandfrei?

Ja, nach vielen Iterationen und mit viel Support hier aus dem Forum, ja.

Karl Heinz Buchegger schrieb:
> Der Code kommt mir sehr bekannt vor.
>
> Den hatten wir doch vor ein paar Tagen schon mal. Wie war denn da in
>
> diesem Thread die letzte Erkenntnis?

Es gab noch ein Problem mit der Wiederholbarkeit, das ich durch Erhöhung 
der Toleranz der Phasenlängen beheben konnte - bei den sehr kurzen 
Phasen scheint die Schwankung doch bis zu 35% zu sein.

Auf das Problem mit dem _delay_ms() hatte ich kein Feedback bekommen 
(Thread wurde in GCC-Forum verschoben)

Karl Heinz Buchegger schrieb:
> No. Ein Array der Länge 3 hat auch nur 3 Elemente. Ein 4.tes existiert
>
> nicht.
>
>
>
> Wenn du an ziffer[3] etwas zuweist, dann knüddelst du dir irgendwas
>
> anderes im Speicher nieder. Nur Gott alleine weiß, was dann alles
>
> passiert

Autsch - jetzt muss ich mich schon fast für meine Dummheit 
entschuldigen... ich werde das ändern und schauen, ob es vielleicht auch 
das Delay-Verhalten löst...

Falls nicht, hast Du einen Tip, wie ich dem Problem selbst auf die 
Schliche kommen könnte (glaub mir, ich habe schon einige Stunden 
gesucht, aber es fehlt wohl die Erfahrung)?

Karl Heinz Buchegger schrieb:
> oder ich, wenn ich es lang genug ananylsiere. Aber dazu hab
>
> ich erst mal keine Lust

das verstehe ich. Aber ansonsten ist der Code jetzt (verglichen zu den 
früheren Versionen) ganz ok, oder? So auf den ersten Blick?

von Mike (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ich sag nicht, dass es DER Fehler ist. Aber es ist EIN Fehler.

...war leider nur EIN Fehler, nicht DER Fehler

Karl Heinz Buchegger schrieb:
> Dein Problem hat ziemlich sicher nichts mit dem _delay_ms zu tun. Dort
>
> manifestiert sich nur das Problem. Sprich: Du siehst da die Symptome.
>
> Aber dein Problem liegt woanders.

Vermutlich. Hat jemand eine Idee, welche Art von Problem zu diesem 
Symptom führen könnte bzw. wie ich es näher eingrenzen/analysieren 
könnte? Welche "Dummheiten" könnten _delay_ms() stören - ok, vermutlich 
alle möglichen ;-)

Ansonsten funktioniert das Programm zuverlässig - und sonstige Fehler in 
Syntax oder Logik hab ich auch keine mehr gefunden...

von Mike (Gast)


Lesenswert?

Ok, war wohl ein Interrupt-Problem. Lasse Interrupts jetzt nur noch zu, 
wo undbedingt notwendig:

  sei();
  while(LED_interrupt_count>0);
  cli();

Meine Vermutung wäre, dass bei Aufruf von _delay_ms(500) Interrupts 
gesperrt sein müssen, da 500 zwei Bytes belegt?

von Thomas E. (thomase)


Lesenswert?

Mike schrieb:
> Ok, war wohl ein Interrupt-Problem. Lasse Interrupts jetzt nur noch zu,
> wo undbedingt notwendig:
Unsinn. Du doktorst nur an den Symptomen herum, beseitigst aber nicht 
das Problem.

Mike schrieb:
> Meine Vermutung wäre, dass bei Aufruf von _delay_ms(500) Interrupts
> gesperrt sein müssen, da 500 zwei Bytes belegt?
Auch Unsinn. Das hat überhaupt nichts miteinander zu tun.

Nachdem ich mir dein pdf jetzt mal angesehen habe, fällt mir allerdings 
auf, daß du mit Variablen rumschmeisst wie ein Großer.
Dazu diverse Multiplikationen, Divisionen(modulo) etc. Sowas kostet jede 
Menge Speicher.
Und das alles auf einem Tiny 2313 mit einem Furz von 128 Byte RAM. Kein 
Wunder, daß das nicht funktioniert.
Geht manchmal, bleibt manchmal hängen, stürzt manchmal ab sind ganz 
typische Symptome für Stacküberläufe. Läuft bis der nächste IRQ den 
Stack in die Variablen schiebt.

Mike schrieb:
> Ansonsten funktioniert das Programm zuverlässig - und sonstige Fehler in
> Syntax oder Logik hab ich auch keine mehr gefunden...
Entweder es funktioniert oder es funkioniert nicht. Dein Programm 
funktioniert eindeutig nicht.

mfg.

von Mike (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> fällt mir allerdings
>
> auf, daß du mit Variablen rumschmeisst wie ein Großer.

Das heißt wahrscheinlich (höflich formuliert), dass ich versuchen 
sollte, mit den Variablen etwas sparsamer umzugehen. Ein konkreter Tip, 
welche Variable(n) aus Deiner Sicht überflüssig ist/sind, wäre natürlich 
hilfreich.

Thomas Eckmann schrieb:
> Und das alles auf einem Tiny 2313 mit einem Furz von 128 Byte RAM. Kein
>
> Wunder, daß das nicht funktioniert.
>
> Geht manchmal, bleibt manchmal hängen, stürzt manchmal ab sind ganz
>
> typische Symptome für Stacküberläufe. Läuft bis der nächste IRQ den
>
> Stack in die Variablen schiebt.

Gibt es da eine konkrete Regel, wieviel Speicher man in Anspruch nehmen 
darf/soll? Bzw. einen Artikel/Beitrag, wie man das "berechnet"? Auch 
hier wäre ein etwas konkreterer Hinweis zur LÖSUNG hilfreicher als nur 
die Beschreibung/Vermutung eines PROBLEMS

Thomas Eckmann schrieb:
> Entweder es funktioniert oder es funkioniert nicht. Dein Programm
>
> funktioniert eindeutig nicht.

Bis auf die sporadisch fehlende Pause in der Anzeige (das bedeutet das 
Wort "Ansonsten") hat das Programm funktioniert. Nach der Änderung 
(Symptombekämpfung?) funktioniert auch das. Wie kommst Du darauf, dass 
es "eindeutig nicht funktioniert"? Was funktioniert nicht (woran lässt 
sich das feststellen) und vor allem warum nicht und was wäre die Lösung 
(abgesehen von anderem Prozessor kaufen)?

Wenn ein Programm das tut, was es soll, und ca. 80% des Speicher nutzt - 
wie kann ich da konkret berechnen, dass es nicht funktionieren kann? 
Hört sich für mich jetzt eher an wie "kommt mir etwas speicherintensiv 
vor und dürfte deshalb nicht funktionieren" ;-)

von Peter D. (peda)


Lesenswert?

Wer kommt denn auf so eine dumme Idee, Code als PDF zu posten.
Keiner kann das mit dem Compiler/Simulator checken. So wirst Du also 
kaum Hilfe bekommen.

Code immer nur als *.c !!!

von Peter D. (peda)


Lesenswert?

Mike schrieb:
> Ansonsten funktioniert das Programm zuverlässig

Es gibt kein "Ansonsten". Entweder ein Programm funktioniert oder es 
funktioniert nicht.
Und solange auch nur eine einzige Sache nicht funktioniert, ist das 
gesamte Programm verdächtig, den Fehler zu beinhalten.
Es gibt keinen Codeteil, den man von der Fehlersuche ausschließen kann.

von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Peter Dannegger schrieb:
> Code immer nur als *.c !!!

siehe Anlage. Wollte nur dick und rot markieren, wo sich der Fehler 
(dessen Ursache natürlich überall versteckt sein kann) bzw. dessen 
Symptome zeigen. Sonst wird wieder gemeckert, dass das Programm so lang 
ist und man selbst die Stelle suchen muss ;-) aber zukünftig nur als 
*.c, versprochen.

Peter Dannegger schrieb:
> Keiner kann das mit dem Compiler/Simulator checken. So wirst Du also
>
> kaum Hilfe bekommen.

Wie kann man das genau checken? Würde es ja gerne selbst näher 
analysieren... Also der Compiler gibt keine Warnungen und zeigt als 
Output u. a.:

Task "RunOutputFileVerifyTask"
Program Memory Usage   :  1838 bytes   89,7 % Full
Data Memory Usage     :  12 bytes   9,4 % Full


Freue mich auf Eure Hilfe und Verbesserungsvorschläge!

Peter Dannegger schrieb:
> Es gibt kein "Ansonsten". Entweder ein Programm funktioniert oder es
>
> funktioniert nicht.
>
> Und solange auch nur eine einzige Sache nicht funktioniert, ist das
>
> gesamte Programm verdächtig, den Fehler zu beinhalten.
>
> Es gibt keinen Codeteil, den man von der Fehlersuche ausschließen kann.

Ja, stimme ich ja im Prinzip zu. Aber wenn ich z. B. zum Leuchten der 
Kontroll-LED statt "PORTB&=!(1<<PB2)" schreiben würde 
"PORTB&=!(1<<PB1)", würde die LED nicht leuchten - aber der Rest des 
Programms könnte durchaus funktionieren. Es ist ein Fehler im Programm, 
den man mit "kritisch", "medium", "low" oder was auch immer 
klassifizieren könnte. So kenne ich das aus der Entwicklung/Einführung 
von Applikationssoftware. Welche große Software ist schon komplett 
fehlerfrei? Ansonsten müsste man wohl behaupten "SAP funktioniert 
nicht", "MS Office funktioniert nicht",... Aber ist wohl eher eine 
"philosophische" Diskussion...

Aber stimmt, bei "Phänomenen", die auf den ersten Blick "unerklärbar" 
erscheinen, sollte man natürlich keinen Codeteil ausschließen...

Thomas Eckmann schrieb:
> Geht manchmal, bleibt manchmal hängen, stürzt manchmal ab sind ganz
>
> typische Symptome für Stacküberläufe. Läuft bis der nächste IRQ den
>
> Stack in die Variablen schiebt.

Also vor der oben beschriebenen Änderung hatte ich das Symptom "geht 
manchmal" (bezogen auf Pause während Anzeige), nach der Änderung keines 
der genannten Symptome mehr. Also das Programm zeigt im 
Ergebnis/Verhalten aktuell KEINE Fehler/Symptome mehr. Es funktioniert 
zuverlässig und wiederholbar. Also ich stell jetzt gleich einen 
Beweisfilm ein ;-)

Aber es würde mich schon interessieren, wie man das Symptom "manchmal 
keine Pause zwischen Anzeige der Zahlen" sauber behoben hätte.

Aber will ja was lernen (bin erst seit etwa 6 Wochen dabei...):
Wie kann ich solche (potenziellen) Stacküberläufe und Speicherprobleme 
analysieren? Wenn der Programmcode zu groß, meckert der Compiler, das 
hab ich schon mitbekommen ;-) aber wie bzw. mit welchen Tools kann ich 
das Laufzeitverhalten analysieren? Debugger, Trace, ...?

von Thomas E. (thomase)


Lesenswert?

Mike schrieb:
> Also der Compiler gibt keine Warnungen und zeigt als
> Output u. a.:
>
> Task "RunOutputFileVerifyTask"
>
> Program Memory Usage   :  1838 bytes   89,7 % Full
>
> Data Memory Usage     :  12 bytes   9,4 % Full

Bei mir kommt das raus:

Task "RunOutputFileVerifyTask"
Program Memory Usage   :  3416 bytes   166,8 % Full  (Memory Overflow)
Data Memory Usage     :  267 bytes   208,6 % Full  (Memory Overflow)

mfg.

von Fabian O. (xfr)


Lesenswert?

Aus meiner Sicht wäre es sinnvoll, wenn Du den Code mal sauber 
strukturierst, indem Du ihn in kleinere Teile zerlegst und einzeln 
testest. Ich gebe Dir mal ein Grundgerüst vor, das ich für sinnvoll 
halte:

main.c
1
#include "segment_display.h"
2
#include "ir_receiver.h"
3
#include <stdint.h>
4
#include <util/delay.h>
5
6
int main(void)
7
{
8
  segment_display_init();
9
  ir_receiver_init();
10
  
11
  while (1) {
12
    if (ir_receiver_data_received()) {
13
      // Daten ausgeben
14
      uint32_t ir_data = ir_receiver_get_data();
15
      for (uint8_t i = 0; i < 4; i++) {
16
        uint8_t ir_byte = ir_data;
17
        segment_display_output(ir_byte);
18
        ir_data = ir_data >> 8;
19
        _delay_ms(500);
20
      }
21
      segment_display_off();
22
    }
23
  }
24
}

So sieht Deine main.c am Ende aus. Darin steht, was das Programm macht. 
Wie die einzelnen Funktionen genau funktionieren, ist auf der Ebene 
nicht interessant.

Als erstes lässt Du die Infrarot-Geschichte aber mal außen vor, und 
kümmerst Dich nur um das Display:
1
#include "segment_display.h"
2
#include "ir_receiver.h"
3
#include <stdint.h>
4
#include <util/delay.h>
5
6
int main(void)
7
{
8
  segment_display_init();
9
  
10
  while (1) {
11
    uint16_t counter = 0;
12
    segment_display_output(counter);
13
    counter += 1234;
14
    if (counter > 9999) {
15
      counter = 0;
16
    }
17
    _delay_ms(500);
18
  }
19
}

Die Dateien für das Display sehen so aus:

segment_display.h
1
#ifndef SEGMENT_DISPLAY_H_
2
#define SEGMENT_DISPLAY_H_
3
4
#include <stdint.h>
5
6
void segment_display_init(void);
7
void segment_display_output(uint16_t number);
8
void segment_display_off(void);
9
10
#endif

segment_display.c
1
#include "segment_display.h"
2
#include <avr/io.h>
3
#inlucde <avr/interrupt.h>
4
5
// Hier Definition der Segmente usw.
6
7
static uint8_t digit[4];
8
9
void segment_display_init(void)
10
{
11
  // Ports für Segmentanzeige initialisieren
12
  // ISR für Display initialisieren
13
}
14
15
void segment_display_output(uint16_t number)
16
{
17
  // number in ziffer-Array umwandeln
18
}
19
20
void segment_display_off(void)
21
{
22
  // ziffer-Arrray auf aus setzen
23
}
24
25
ISR(TIMER1_COMPA_vect)
26
{
27
  // ziffer-Array auf Anzeige ausgeben
28
}

Damit spielst Du rum, bis Du Dir sicher bist, dass die Ausgabe wirklich 
zuverlässig funktioniert. Danach kommt die Infrarot-Geschichte:

ir_receiver.h
1
#ifndef IR_RECEIVER_H_
2
#define IR_RECEIVER_H_
3
4
#include <stdint.h>
5
#include <stdbool.h>
6
7
void ir_receiver_init(void);
8
9
bool     ir_receiver_data_received(void);
10
uint32_t ir_receiver_get_data(void);
11
12
#endif

ir_receiver.c
1
#include "ir_receiver.h"
2
#include <avr/io.h>
3
#inlucde <avr/interrupt.h>
4
5
enum {
6
  STATE_IDLE = 0,
7
  STATE_START_BIT_PULSE_RECEIVED,
8
  STATE_START_BIT_PAUSE_RECEIVED,
9
  STATE_DATA_BIT_PULSE_RECEIVED,
10
  // ...
11
};
12
13
static uint8_t state = STATE_IDLE;
14
static volatile uint32_t ir_data = 0;
15
static volatile bool     ir_data_received = false;
16
static volatile uint16_t time_since_change = 0;
17
18
void ir_receiver_init(void)
19
{
20
  // IR-Ports initialisieren
21
  // Timer für IR-Empfang initialisieren
22
}
23
24
bool ir_receiver_data_received(void)
25
{
26
  return ir_data_received;
27
}
28
29
uint32_t ir_receiver_get_data(void)
30
{
31
  uint32_t data = ir_data;
32
  ir_data_received = false;
33
  return data;
34
}
35
36
static void pulse_detected(uint16_t time)
37
{
38
  // Auswertung, State-Machine weiterschalten
39
}
40
41
static void pause_detected(uint16_t time)
42
{
43
  // Auswertung, State-Machine weiterschalten
44
}
45
46
ISR(TIMER0_COMPA_vect)
47
{
48
  time_since_change++;
49
}
50
51
ISR(PCINT_vect)
52
{
53
  uint16_t phase_time = time_since_change;
54
  time_since_change = 0;
55
  
56
  if (PINB & (1<<PB0)) {
57
    pulse_detected(phase_time);
58
  } else {
59
    pause_detected(phase_time);
60
  }
61
}

So in etwa. Ich kenne mich mit Infrarot nicht aus, daher kannst Du ja 
ggf. passendere Namen für die Funktionen nehmen. Nimm Dir Zeit, Dir 
treffende Namen für jede Variable und Funktion zu überlegen. Das 
erleichtert es enorm, ein Programm zu verstehen.

Auf jeden Fall würde ich die Auswertung dann gleich im Interrupt machen. 
Wenn ein Signal komplett empfangen wurde, setzt Du data_received auf 
true. Solange es true ist, überschreibst Du es auch nicht wieder mit 
etwas neuem. Erst wenn das Hauptprogramm die Daten abgeholt hat, wird 
der nächste Datensatz empfangen.

Hoffe es hilft Dir, ein bisschen Struktur ins Programm zu bringen. Es 
erscheint vielleicht am Anfang als viel Overhead, aber es lohnt sich 
imo.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:

> Bei mir kommt das raus:

Seltsame Compiler müsst ihr haben:
1
% avr-gcc -Os -mmcu=attiny2313 -o test.elf Code_IR_Empfaenger_09022013.c
2
Code_IR_Empfaenger_09022013.c:49:1: warning: data definition has no type or storage class
3
Code_IR_Empfaenger_09022013.c:49:26: warning: data definition has no type or storage class
4
Code_IR_Empfaenger_09022013.c:55:1: error: expected ‘,’ or ‘;’ before ‘volatile’
5
Code_IR_Empfaenger_09022013.c:57:19: error: conflicting type qualifiers for ‘IR_counts_letzte_phase’
6
Code_IR_Empfaenger_09022013.c:49:1: note: previous definition of ‘IR_counts_letzte_phase’ was here
7
Code_IR_Empfaenger_09022013.c:60:19: error: conflicting type qualifiers for ‘LED_interrupt_count’
8
Code_IR_Empfaenger_09022013.c:49:26: note: previous definition of ‘LED_interrupt_count’ was here
9
Code_IR_Empfaenger_09022013.c: In function ‘main’:
10
Code_IR_Empfaenger_09022013.c:117:2: error: ‘IR_counter_active’ undeclared (first use in this function)
11
Code_IR_Empfaenger_09022013.c:117:2: note: each undeclared identifier is reported only once for each function it appears in
12
Code_IR_Empfaenger_09022013.c: In function ‘__vector_13’:
13
Code_IR_Empfaenger_09022013.c:304:6: error: ‘IR_counter_active’ undeclared (first use in this function)
14
Code_IR_Empfaenger_09022013.c: In function ‘__vector_11’:
15
Code_IR_Empfaenger_09022013.c:313:2: error: ‘IR_counter_active’ undeclared (first use in this function)

von Thomas E. (thomase)


Lesenswert?

Jörg Wunsch schrieb:
> Seltsame Compiler müsst ihr haben:
Mein Compiler verfügt über eine automatische Fehlerbeseitigung. Der 
meckert nicht einfach nur rum, sondern packt mit an.
Oder war ich das selber, der das fehlende Semikolon gesetzt und einen 
Zeilenumbruch beseitigt hat? Hmm...
Vorher kam aber auch das Gleiche wie bei dir raus.

mfg.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ja, hatte ich dann auch gemerkt (und bin ungefähr zu gleicher
Überbelegung des ATtiny2313 wie du gekommen).

Allerdings finde ich es immer sehr suspekt, wenn eine Datei schon
wegen offensichtlicher Syntaxfehler nicht compilierbar ist.  Dann
haben wir ganz offensichtlich ja nicht das, was Mike hat, sondern
irgendetwas Anderes.  Da stellt sich dann immer die Frage: war
das der einzige Fehler, oder unterscheidet sich seine Version noch
in anderen Dingen von unserer?

von Peter D. (peda)


Lesenswert?

Ich hab noch einen:
1
Code_IR_Empfaenger_09022013.c: In function 'displayZahl':
2
Code_IR_Empfaenger_09022013.c:361: warning: array subscript is above array bounds
3
Code_IR_Empfaenger_09022013.c: In function 'main':
4
Code_IR_Empfaenger_09022013.c:267: warning: array subscript is above array bounds

von Mike (Gast)


Lesenswert?

Fabian O. schrieb:
> Aus meiner Sicht wäre es sinnvoll, wenn Du den Code mal sauber
>
> strukturierst, indem Du ihn in kleinere Teile zerlegst und einzeln
>
> testest. Ich gebe Dir mal ein Grundgerüst vor, das ich für sinnvoll
>
> halte:

Super, vielen Dank!! Ich werde das entsprechend umstrukturieren. Hatte 
nur bisher mit diversen Fehlern und Problemchen gekämpft und die 
"Code-Optimierung" vor mir her geschoben.

Fabian O. schrieb:
> Damit spielst Du rum, bis Du Dir sicher bist, dass die Ausgabe wirklich
>
> zuverlässig funktioniert.

Aber das tut sie jetzt, wieso glaubt mir keiner? ;-)) Nein im Ernst, 
werde die Struktur verbessern, auch wenn es jetzt erstmal zuverlässig 
läuft (oder doch nur den Anschein macht?)

Jörg Wunsch schrieb:
> Seltsame Compiler müsst ihr haben:

aber wirklich. Bei mir kommen weder Fehler noch Warnungen (Option -Wall 
ist aktiviert). Welche Fehler sind das genau?
- fehlendes Semikolon --> hinter #define? --> scheint meinen Compiler 
nicht zu stören
--> muss da ein Semikolon hin?
- IR_counter_active undeclared und andere Fehler --> ist das Folge des 
fehlenden Semikolon?

von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Jörg Wunsch schrieb:
> Seltsame Compiler müsst ihr haben:

Uuups, hatte die falsche Version hochgeladen - sorry, sorry, sorry

Also jetzt die richtige - da kommen auch bei Euch hoffentlich diese 
Meldungen nicht mehr...

von Mike (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Allerdings finde ich es immer sehr suspekt, wenn eine Datei schon
>
> wegen offensichtlicher Syntaxfehler nicht compilierbar ist.  Dann
>
> haben wir ganz offensichtlich ja nicht das, was Mike hat, sondern
>
> irgendetwas Anderes.  Da stellt sich dann immer die Frage: war
>
> das der einzige Fehler, oder unterscheidet sich seine Version noch
>
> in anderen Dingen von unserer?

hatte eine nicht ganz aktuelle Version hochgeladen - SORRY!

Im letzten Beitrag aber nun die aktuelle Version - bekommt Ihr immer 
noch Fehler/Warnungen etc.?

von Thomas E. (thomase)


Lesenswert?

Mike schrieb:
> Task "RunOutputFileVerifyTask"
>
> Program Memory Usage   :  1838 bytes   89,7 % Full
>
> Data Memory Usage     :  12 bytes   9,4 % Full


AVR Memory Usage
----------------
Device: attiny2313

Program:    3418 bytes (166.9% Full)
(.text + .data + .bootloader)

Data:        268 bytes (209.4% Full)
(.data + .bss + .noinit)

Build succeeded with 1 Warnings...

Mike schrieb:
> Aber das tut sie jetzt, wieso glaubt mir keiner? ;-))

Entweder verarscht du uns hier oder du weisst überhaupt nicht, was du 
tust.
Wie soll das auf einem Attiny2313 laufen?

mfg.

von Peter D. (peda)


Lesenswert?

Mit WINAVR siehts o.k. aus:
1
IR_Empfaenger_LED_Anzeige_v04.c: In function 'main':
2
IR_Empfaenger_LED_Anzeige_v04.c:118: warning: unused variable 'zahl'
3
AVR Memory Usage
4
----------------
5
Device: attiny2313
6
7
Program:    1904 bytes (93.0% Full)
8
(.text + .data + .bootloader)
9
10
Data:         12 bytes (9.4% Full)
11
(.data + .bss + .noinit)

von Fabian O. (xfr)


Lesenswert?

Die heftige Größe kommt von dieser Zeile:
1
#define toleranz 0.5  // 50% Toleranz für Länge der Phasen

Die zieht die Floating-Point-Lib mit rein, aber anscheinend nicht mit 
jedem Compiler. Die Berechnung solltest Du auf Integer umstellen ...

von Peter D. (peda)


Lesenswert?

Thomas Eckmann schrieb:
> Data:        268 bytes (209.4% Full)

Achja, das ist die alte float Lib, die braucht 256 Byte SRAM.
Benutz mal "-lm", dann paßts rein.

von Mike (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Entweder verarscht du uns hier oder du weisst überhaupt nicht, was du
>
> tust.

weder noch - wobei ich (wie gesagt) nicht viel Erfahrung habe - also 
bitte etwas Verständnis mit den Anfängern.

Peter Dannegger schrieb:
> Mit WINAVR siehts o.k. aus

Danke - aber ich stell echt noch den Beweisfilm ein ;-)

Fabian O. schrieb:
> Die zieht die Floating-Point-Lib mit rein, aber anscheinend nicht mit
>
> jedem Compiler. Die Berechnung solltest Du auf Integer umstellen ...

war mir nicht bewusst, danke für den Hinweis. Also ich mach dann einfach 
50 statt 0.5 und dividiere in der Berechnung zusätzlich durch 100? Dann 
wird automatisch auf Integer gerundet, wenn das Ergebnis krumm ist, oder 
kommt da "hinten rum" auch die Floating-Point-Lib rein? Ich könnte 
natürlich auch die ganze Berechnung rausnehmen und fixe Werte 
hinterlegen (Toleranz war eigentlich nur zum Test).

Zurück zum Thema: es treten keine Fehler(symptome) mehr auf - würdet Ihr 
(neben der besseren Strukturierung) sonst eine Änderung empfehlen? Und 
wie ist das mit der Analyse des Laufzeitverhaltens bzgl. Stackoverflow, 
Speicherverbrauch,...? Ich habe mal Debugging gemacht, aber geht das 
sinnvoll, wenn ich ein IR-Signal im ms-Bereich erwarte und verarbeite?

VG Mike

von Fabian O. (xfr)


Lesenswert?

Mike schrieb:
> war mir nicht bewusst, danke für den Hinweis. Also ich mach dann einfach
> 50 statt 0.5 und dividiere in der Berechnung zusätzlich durch 100? Dann
> wird automatisch auf Integer gerundet, wenn das Ergebnis krumm ist, oder
> kommt da "hinten rum" auch die Floating-Point-Lib rein?

Ja, das ist das Prinzip. Statt 100 ist es aber geschickter, eine 
2er-Potenz zu nehmen, z.B. 1024 oder 256. Dann kann der Compiler daraus 
eine effizientere Berechnung machen, z.B. mit Shift-Operationen. Du 
musst aber darauf achten, dass der Datentyp für das Zwischenergebnis 
genügend breit ist, um den Wert * 1024 aufnehmen zu könnnen, sonst gibt 
es einen Überlauf.

Floating-Point-Berechungen finden nur statt, wenn Du float- oder 
double-Datentypen benutzt oder irgendwo eine Kommazahl (bzw. eine mit 
einem Punkt) schreibst. Bei Integerarithmetik werden bei Divisionen die 
Nachkommastellen abgehackt, d.h. bei positiven Werten abgerundet, bei 
negativen aufgerundet.

Hier gibt es einen Artikel zu dem Thema:
http://www.mikrocontroller.net/articles/Festkommaarithmetik

Mike schrieb:
> es treten keine Fehler(symptome) mehr auf - würdet Ihr
> (neben der besseren Strukturierung) sonst eine Änderung empfehlen?

Wenn das Programm funktioniert und das sein endgültiger Zweck ist, dann 
kannst Du es natürlich einfach so lassen. Mehr als das tun, was Du 
willst, kann es nicht. Wenn Du den Code nochmal für was anderes 
verwendest willst, würde ich Dir die Umstrukturierung empfehlen. Danach 
kann man bestimmt immer noch was besser machen, "perfekt" wirds 
wahrscheinlich nie. Musst ja Du wissen, welche Anforderungen Du noch 
hast ...

von Thomas E. (thomase)


Lesenswert?

Mike schrieb:
> weder noch - wobei ich (wie gesagt)
Das hat sich jetzt ja geklärt. Die Verarschung nehme ich natürlich 
zurück.

mfg.

von Mike (Gast)


Lesenswert?

@ Fabian: Danke für die Erläuterungen bzgl. Floating Point - Artikel 
schau ich mir an. Umstrukturierung mach ich auch auf jeden Fall, da ich 
schon weitere Verwendungen plane - war erstmal nur ein "Lern- und 
Übungsprojekt"

von Mike (Gast)


Lesenswert?

Noch eine Verständnisfrage zur Aufteilung des Code auf mehrere Dateien. 
Habe dazu etwas gegoogelt, um das Grundprinzip von Header-Dateien etc. 
zu verstehen:

Zitat: Die Datei myheader.c wird jetzt kompiliert und eine so genannte 
Objektdatei erzeugt. Diese hat typischerweise die Form myheader.obj oder 
myheader.o. Zuletzt muss dem eigentlichen Programm die Funktionalität 
des Headers bekannt gemacht werden, wie es durch ein #include 
"myheader.h" geschieht, und dem Linker muss beim Erstellen des Programms 
gesagt werden, dass er die Objektdatei myheader.obj bzw. myheader.o mit 
einbinden soll.

Wie "sage" ich dem Linker, dass er die Objektdatei einbinden soll? Oder 
geht das automatisch, wenn alle Dateien in der gleichen Solution liegen 
(benutze Atmel Studio)?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mike schrieb:

> Zitat: Die Datei myheader.c ...

Sehr ungünstiger Name.  "header" nennt man die Datei, die auf .h
endet.  Diese enthält Definitionen und Deklarationen, aber (bis auf
ggf. inline-Funktionen) keinen Code selbst.

> Wie "sage" ich dem Linker, dass er die Objektdatei einbinden soll?

Indem man die Objektdatei auf der Kommandozeile mit angibt.

Übrigens enden die Objektdateien beim GCC normalerweise auf .o (nicht
auf .obj).  Das liegt an dessen Unix-Tradition.

> Oder
> geht das automatisch, wenn alle Dateien in der gleichen Solution liegen
> (benutze Atmel Studio)?

Du nimmst die zugehörige C-Datei irgendwie mit in dein Projekt auf.
Um den Reset kümmert sich das Atmel Studio.

von Mike (Gast)


Lesenswert?

verstanden, danke!

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.