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!
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)
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".
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.
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...
>> 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.
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.
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)
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.
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.
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).
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".
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?
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...
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?
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.
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" ;-)
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 !!!
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.
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, ...?
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.
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
intmain(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_tir_data=ir_receiver_get_data();
15
for(uint8_ti=0;i<4;i++){
16
uint8_tir_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
intmain(void)
7
{
8
segment_display_init();
9
10
while(1){
11
uint16_tcounter=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
voidsegment_display_init(void);
7
voidsegment_display_output(uint16_tnumber);
8
voidsegment_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
staticuint8_tdigit[4];
8
9
voidsegment_display_init(void)
10
{
11
// Ports für Segmentanzeige initialisieren
12
// ISR für Display initialisieren
13
}
14
15
voidsegment_display_output(uint16_tnumber)
16
{
17
// number in ziffer-Array umwandeln
18
}
19
20
voidsegment_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
voidir_receiver_init(void);
8
9
boolir_receiver_data_received(void);
10
uint32_tir_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
staticuint8_tstate=STATE_IDLE;
14
staticvolatileuint32_tir_data=0;
15
staticvolatileboolir_data_received=false;
16
staticvolatileuint16_ttime_since_change=0;
17
18
voidir_receiver_init(void)
19
{
20
// IR-Ports initialisieren
21
// Timer für IR-Empfang initialisieren
22
}
23
24
boolir_receiver_data_received(void)
25
{
26
returnir_data_received;
27
}
28
29
uint32_tir_receiver_get_data(void)
30
{
31
uint32_tdata=ir_data;
32
ir_data_received=false;
33
returndata;
34
}
35
36
staticvoidpulse_detected(uint16_ttime)
37
{
38
// Auswertung, State-Machine weiterschalten
39
}
40
41
staticvoidpause_detected(uint16_ttime)
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_tphase_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.
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.
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?
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?
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...
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.?
Mike schrieb:> Task "RunOutputFileVerifyTask">> Program Memory Usage : 1838 bytes 89,7 % Full>> Data Memory Usage : 12 bytes 9,4 % FullAVR 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.
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.
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
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/FestkommaarithmetikMike 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 ...
@ 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"
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)?
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.