Ich kann falsch liegen, aber innerhalb einer Funktion funktioniert
static short n = 0;
nicht oder ist nicht Kompilerübergreifend.
Ersetze es mal (testweise) gegen die klassisce Variante, die Variable zu
setzen bevor sie das erste mal verwendet wird.
An deiner Steller wäre ausserdem eine for(n=0;n>=15;N++){..} besser.
Und du liegst in der Tat falsch. Innerhalb einer Funktion funktioniert
static genauso wie außerhalb; der einzige Unterschied ist, dass die
Variable außerhalb nicht sichtbar ist.
Das Problem ist wahrscheinlich, dass Werte kleiner 1.0 abgerundet
werden.
Mark schrieb:>> Aber wieso wird immer Null zurückgegeben?
Weil dein Delta_Alphaimmer < 15 ist?
Deklariere avgsum auch als float.
Davon abgesehen ist das kein gleitender Mittelwert (aka Mittelwert der
letzten n Werte) sondern ein IIR Tiefpassfilter. (IIR = Infinit Impulse
Response)
?! wieder was dazu gelernt..
Ich dachte in C ist static eine Konstante...
In Pascal kähme hier eine Fehlermeldung, das die Konstante nicht
verändert werden könnte..hmmm
Oberlehrer schrieb:> Da er n nicht zuruecksetzt, laeuft die Variable irgendwann> mal ueber, bzw. wird zu null.
Auch das nicht.
>> Oberlehrer
Sag mal, was genau unterrichtest du eigentlich?
Programmierung kanns ja wohl nicht sein
> Sag mal, was genau unterrichtest du eigentlich?> Programmierung kanns ja wohl nicht sein
Doch doch, das kann sehr wohl sein. Wenn ich mir anschaue, was meine
Kinder im Informatikunterricht in der Schule so alles (nicht) gelehrt
bekommen.
Gruß, Stefan
Timo schrieb:> achne..const war eine Konstante :->)
Vorsicht:
In C ist eine als 'const' markierte Variable nach wie vor eine Variable.
Allerdings eine von der du die Zusicherung machst, dass du sie in deinem
Programm nicht verändern wirst. Das 'const' bedeutet in C 'not
modifiable'.
Es ist KEINE Konstante!
Der Unterschied ist subtil und tritt dann zu Tage, wenn du versuchst
eine derartige vermeintliche 'Konstante' an Stellen zu verwenden, an
denen von der Syntax her tatsächlich eine Konstante gefordert wird. Wie
zb. bei einem 'case' in einem switch-case.
So wie die Funktion oben beschrieben ist macht sie
kein Mittelwert. Deshalb bin ich davon ausgegangen,
das sie irgendwo von ausserhalb in einer Schleife immer
wieder aufgerufen wird, um einen neuen Mittelwert zu
berechenen. (Warums sonst soll man in der Funktion
Variablen statisch halten?).
N wird bei jedem Aufruf um eins erhoeht, ergo irgendwann
laeuft N mal ueber.
Oberlehrer
Karl Heinz schrieb:> In C ist eine als 'const' markierte Variable nach wie vor eine Variable.> Allerdings eine von der du die Zusicherung machst, dass du sie in deinem> Programm nicht verändern wirst. Das 'const' bedeutet in C 'not> modifiable'.> Es ist KEINE Konstante!
"C" kommt mir vor, wie die Durchquerung eines Urwaldes voller Schlangen
und Skorpione in einer mondlosen Nacht ohne Taschenlampe.
MfG Paul
Oberlehrer schrieb:> So wie die Funktion oben beschrieben ist macht sie> kein Mittelwert. Deshalb bin ich davon ausgegangen,> das sie irgendwo von ausserhalb in einer Schleife immer> wieder aufgerufen wird, um einen neuen Mittelwert zu> berechenen.
So weit so gut,
Zum Beispiel von der Hauptschleife, die den ADC ausliest und die
sukzessive ermittelten Werte filtern lässt.
> (Warums sonst soll man in der Funktion> Variablen statisch halten?).
Damit sie von ausserhalb der Funktion nicht zugreifbar sind. Die
Variablen gehören konzeptionell zu der Funktion und sind nur innerhalb
der Funktion relevant.
Das ist eigentlich der Standardfall, warum man Variablen static macht.
>> N wird bei jedem Aufruf um eins erhoeht, ergo irgendwann> laeuft N mal ueber.
Und das hier
1
if(n<15){
zählt gar nichts?
n wird bis 15 hochgezählt (bei jedem erneuten Funktionsaufruf um 1 mehr)
und bleibt dann bei 15 stehen.
Und der Zweck besteht darin, dass er über die letzten 15 Werte Tiefpass
filtern möchte, allerdings das Problem hat, dass der ganze Klaperatismus
ja auch erst mal anlaufen muss. D.h. für die ersten 14 Messwerte kommt
eine andere Berechnung zum Zug, weil sich ja die Summe der ersten 15
Werte erst nach und nach mit jedem Funktionsaufruf aufbauen muss. Daher
wird nicht 1/15 der Summe abgezogen und daher wird da auch noch nicht
durch 15 dividiert.
Sobald die Funktion das 15.te mal (und folgende) aufgerufen wird ist die
ganze Sache mit dem n vom Tisch: Ab dann wird von der bisherigen Summe
1/15 abgezogen, der neue Messwert in die Summe eingerechnet und der
Durschnitt geliefert.
Eigentlich eine ganz einfache Funktion.
Oberlehrer schrieb:> Und ausserdem dividerst du durch 0!
Zwar nicht, aber diese Division ist fast genauso /umständlich/:
Mark schrieb:> return avgsum/15;
Man sollte sein Zielsystem kennen und wissen, dass so ein Rechenknecht
im Zweiersystem arbeitet. Dann kommt man pfeilschnell auf die Idee, dass
eine Filterweite von 16 und damit eine Division durch 16 wesentlich
geschickter wäre...
Mark schrieb:> float Filter_UohneL(float Delta_Alpha)
Worauf soll das Ganze nochmal laufen? Kann das Zielsystem mit float
umgehen?
Falls ja:
> static unsigned long avgsum=0;
Ich würde wenigstens diese lokale Summe dann auch zu einem float
machen...
Mark schrieb:> Der Code sieht folgendermaßen aus:
Der kommt mir bekannt vor... ;-)
http://www.lothar-miller.de/s9y/archives/25-Filter-in-C.html
> D.h. für die ersten 14 Messwerte kommt>eine andere Berechnung zum Zug, weil sich ja die Summe der ersten 15>Werte erst nach und nach mit jedem Funktionsaufruf aufbauen muss.
hier kann man sich fragen, ob das wichtig ist. Immerhin sinds nur die
ersten x(15) Werte, wo sich das aufbaut. Evtl. kann man das auch
ignorieren. So spart man sich einen Vergleich, der bis auf die ersten
paar Mal nie erfüllt ist...
Hallo
bin ein bisschen aus der Übung, aber beim Aufruf der Funktion wird n=0
gesetzt. Im IF auf 1 gesetzt und die Funktion verlassen.
Wie soll n hochzählen ?
karadur schrieb:> Hallo>> bin ein bisschen aus der Übung, aber beim Aufruf der Funktion wird n=0> gesetzt. Im IF auf 1 gesetzt und die Funktion verlassen.>> Wie soll n hochzählen ?
n ist static!
d.h. die Variable behält ihren Wert auch über mehrere Funktionsaufrufe
hinweg. Das 0 setzen passiert nur beim ersten Aufruf.
static, siehe:
http://de.wikipedia.org/wiki/Static_%28Schl%C3%BCsselwort%29
Das kleine Problem dabei:
Die Variablen avgsum und n gibt es nur einmal. Solange die Funktion
Filter_UohneL() nur an einer einzigen Stelle verwendet wird, gibt es
kein Problem. Sobald Du aber Dein Programm erweiterst, hast Du ein
Problem:
1
Delta_Alpha_gefiltert=Filter_UohneL(Delta_Alpha);
2
Delta_Beta_gefiltert=Filter_UohneL(Delta_Beta);
In avgsum wird jetzt Delta_Alpha_gefiltert UND Delta_Beta_gefiltert
aufaddiert - was zu falschen Ergebnissen führt.
Gruß, Stefan
Karl Heinz schrieb:> Es ist KEINE Konstante!
Aber, aber, Karlheinz.
Das kommt nämlich ganz auf die Umstände drauf an. Bei Zeugs, was auf
deinem PC komplett im RAM läuft, hast du ja Recht, aber initialisierte
Konstanten landen bei den µC, die ich vor der Nase habe, gnadenlos im
Flash und bleiben dort auch. Da ist Neese mit Zuweisungen aller Art.
Allenfalls kriegt man ne Data-Exception auf die Rübe.
Aber die Code-Kostproben, die hier kamen, sind schon grandios...
Eigentlich macht man's etwa so:
typ buf[zweierpotenz];
int zeiger;
typ summe;
void init_me(void)
{ summe = zeiger = 0; }
typ filtere (typ was)
{ typ tmp;
tmp = summe - buf[zeiger] + was;
buf[zeiger] = was;
zeiger = (zeiger+1) & (zweierpotenz-1);
return tmp>>zweierpotenz;
}
So. Hoffentlich nix vergessen...
Wer will, kann natürlich auch krumme Pufferlängen nehmen, dann ist eben
ein if(zeiger>=buflenge) zeiger=0 und eine Division am Ende nötig.
W.S.
Das Problem mit dem "ersten Einschwingen" kann man so elegant lösen:
man initialisiert die Summe auf den n-fachen Wert.
Entweder automatisch:
#define FS 64 //Filterstärke
firstTime=1;
im Filter:
if(firstTime){adcSum = FS * adc; firstTime = 0;}
else {adcSum += adc - adcSum / FS;}
Oder beim Initialisieren (z.B. wenn der Wert in etwa bekannt ist).
Oder man nimmt zuerst einen schwachen Filter:
#define FS1 8 //Filterstärke 1
#define FS2 8 * FS1 //Filterstärke 2
firstTimes=16;
if(firstTimes){
if(firstTimes-- == 16) {adcSum = FS2 * adc;} //Filter setzen
else {adcSum += FS2 / FS1 * adc - adcSum / FS2;} //schwach filtern
}
else {adcSum += adc - adcSum / FS2;} //stark filtern
Code wie immer ungetestet, kam mir gerade so in den Sinn ;-)
Oft ist es besser (genauer), am Ende des Filters adcSum nicht zu
dividieren, um in den Werte-Bereich von adc zu kommen, sondern direkt
mit der Summe weiterzurechnen.
> Vorsicht:> In C ist eine als 'const' markierte Variable nach wie vor eine> Variable. Allerdings eine von der du die Zusicherung machst,> dass du sie in deinem Programm nicht verändern wirst. Das> 'const' bedeutet in C 'not modifiable'. Es ist KEINE Konstante!
Daher ist es besser, Konstanten als Macros zu definieren.
eProfi schrieb:> if(firstTimes){
Naja.. meine Meinung dazu ist, den Filterkernel so klein wie möglich zu
halten. Da ist es eigentlich egal, ob bei den ersten 16 oder 32 Werten
Murks rauskommt und später läuft das Ganze ja sowieso, da ist dann ne
Fallabfrage nicht mehr nützlich.
W.S.
W.S. schrieb:> Karl Heinz schrieb:>> Es ist KEINE Konstante!>> Aber, aber, Karlheinz.> Das kommt nämlich ganz auf die Umstände drauf an.
Du solltest dir endlich mal angewöhnen zu akzeptieren, dass nicht deine
Compiler Implementierungen definieren, wie C zu funktionieren hat,
sondern einzig und allein der Standard.
> Bei Zeugs, was auf> deinem PC komplett im RAM läuft, hast du ja Recht, aber initialisierte> Konstanten landen bei den µC, die ich vor der Nase habe, gnadenlos im> Flash und bleiben dort auch.
Und? Ist komplett irrelevant
> Da ist Neese mit Zuweisungen aller Art.> Allenfalls kriegt man ne Data-Exception auf die Rübe.
Und auch das ist korrekt.
Beim Versuch der Veränderung einer const Variablen landet man in
'undefined behaviour land'. Hat nur leider nichts damit zu tun, das
const markierte Variablen in C keine Konstanten sind (im Gegensatz zu
C++)
Karl Heinz schrieb:> Hat nur leider nichts damit zu tun, das> const markierte Variablen in C keine Konstanten sind (im Gegensatz zu> C++)
Vielleicht wird dir der Unterschied (und das wovon ich eigentlich
spreche) bewusst, wenn du dieses 'Programm' einmal durch den C Compiler
und einmal durch den C++ Compiler jagst und dir die Fehlermeldungen mal
ansiehst
1
constintsize=5;
2
3
intdata[size];
4
5
intmain(intargc,char*argv[])
6
{
7
}
C: illegal. size ist keine Konstante
C++: legal. size ist eine Konstante
Mich würde da echt brennend interessieren, wie groß der Wert von float
Delta_Alpha ist. Wenn nämlich die Ganzzahl-Filtersumme kleiner als 15
ist, dann kommt bei avgsum/15 immer etwas kleineres als 1 und damit 0
raus.
Ich hatte das schon mal erwähnt, es scheint mir aber ein wenig
untergegangen zu sein...
Ja, Delta_Alpha ist immer kleiner 1.
Der Filter scheint im Betrieb zu funktionieren, nur beim allerersten
Anschalten werden erst n Werte gesammelt...
Siehe Foto (sorry wegen der Quali).
Das war aber nicht Sinn der Sache..
Jemand Rat?
Mark schrieb:> Der Filter
Welcher?
In diesem Thread wurden mindestens 3 verschiedene Implementierungen
gezeigt mit durchaus unterschiedlichen Charakteristiken.
Mark schrieb:> Der aus meinem ersten Beitrag.> Mit avgsum in float geändert.
Nö.
Der sammelt nicht, bis er das erste mal irgendein sinnvolles Resultat
kriegt. Der tut sein bestes um mit den n Werten, die er vorliegen hat
einen gefilterten Wert zu kriegen.
Hast du schon mal die Delta Werte numerisch verfolgt?
Numerisch verfolgen ist schlecht.
Aber verdoppele ich "n" so verdoppelt sich auch die "Totzeit" zu Beginn
des vorherigen Fotos.
Anscheinend ist Delta_alpha zu Beginn, solange n nicht seinen Max Wert
erreicht hat, wirklich null. Wüsste aber nicht wieso..
komisch..
Mark schrieb:> Numerisch verfolgen ist schlecht.
Das wiederrum ist ganz schlecht.
Einer der schlimmsten Fehler, den man meiner Meinung nach machen kann,
ist es sich von Anfang an keine Debugmöglichkeit zu verschaffen, an der
man auch mal Zahlenwerte rauskriegt. Die Methode 'Stochern im Nebel' war
zum Debuggen noch nie sehr effektiv.
Kannst du dir die ersten sagen wir mal 20 Werte nicht zb in ein EEPROM
schreiben lassen und dann später vom EEPROM auslesen? (Benutzt du
überhaupt einen AVR?)
> Anscheinend ist Delta_alpha zu Beginn, solange n nicht seinen Max Wert> erreicht hat, wirklich null. Wüsste aber nicht wieso..
Wo kommen die her und was passiert mit dem gefilterten Wert weiter?
Karl Heinz schrieb:> man auch mal Zahlenwerte rauskriegt. Die Methode 'Stochern im Nebel' war> zum Debuggen noch nie sehr effektiv.>
1. Versuch im Nebel zu stochern:
Ich mache eine Phasenanschnittssteuerung, aber sobald ich n , wie
gesagt, höher setze, wird zu Beginn mit dem größten Alpha angeschnitten.
PI_ohneL sieht so aus:
1
floatPI_ohneL(floatId_neu,floatId_alt,floatImax)//Für ohne Linearisierung
2
{
3
4
xd=(Imax-Id_neu);
5
xd_1=(Imax-Id_alt);
6
/*
7
if (PIdurchlauf == 1) //Um beim ersten Durchlauf P-Anteil nicht zu vernachlässigen
Zu früh gefreut.
Nach dem Bespielen (sprich Reset) des uC und starten des Programms läuft
alles wie es soll.
Nur nach dem erneuten Starten des Programms durch einen Taster steigt
und fällt die anfängliche Totzeit mit n!?
Was muss ich denn wo nullsetzen?
Mir würde es ja einleuchten, wenn die vorherigen Werte noch gespeichert
wären, aber wieso die ersten n Werte nach dem fortsetzen des Programms
mit Null initialisiert werden das verstehe ich nicht.
Und entschuldigung falls ich nerve, aber eine Frage noch:
Funktioniert die Funktion PI_ohneL so wie sie soll?
Weil ich new_u_ist einfach ganz normal als float innerhalb der header
Datei in der die Funktion geschrieben ist, definiert habe, nicht als
static..
Karl Heinz schrieb:> Einer der schlimmsten Fehler, den man meiner Meinung nach machen kann,> ist es sich von Anfang an keine Debugmöglichkeit zu verschaffen, an der> man auch mal Zahlenwerte rauskriegt. Die Methode 'Stochern im Nebel' war> zum Debuggen noch nie sehr effektiv.
Der einzig vernünftige Weg, so etwas komplexes (1) zum Laufen zu
bekommen, ist, es erst in C auf dem PC zu implementieren, die Funktion
mit reichlich Testszenarien zu füttern und Diagramme der Ausgabe zu
malen a la meintest.exe > zahlen.csv und Excel.
Wenn das vernünftige Werte liefert, schiebt man tiefpass.c und
tiefpass.h einfach in uc-Projekt.
(1) relativ zum Kenntnisstand
Mark schrieb:> Zu früh gefreut.> Nach dem Bespielen (sprich Reset) des uC und starten des Programms läuft> alles wie es soll.> Nur nach dem erneuten Starten des Programms durch einen Taster steigt> und fällt die anfängliche Totzeit mit n!?>> Was muss ich denn wo nullsetzen?> Mir würde es ja einleuchten, wenn die vorherigen Werte noch gespeichert> wären, aber wieso die ersten n Werte nach dem fortsetzen des Programms> mit Null initialisiert werden das verstehe ich nicht.
Sind sie auch. n und avgsum werden nur beim laden des Programms auf 0
gesetzt. Das ist die schonmal oben angesprochene Falle von static
Variabblen.
Mark schrieb:> Wie kann man denn eine static zurücksetzen wenn man möchte?
Gar nicht.
Genau das ist der Sinn der Sache mit 'static', dass du ausserhalb der
Funktion an diese Variable nicht ran kommst.
Also entweder verpasst du der Funktion ein Argument, mit dem du ihr
mitteilst: "jetzt gehts von vorne los" oder du machst dir dieses 'n'
(nenn die Variable aber dann anders) global um in der
Programmstartsequenz es auf 0 setzen zu können.
> Lag wohl doch daran, dass n int war.
In dem Fall hätte es nur eine einzige Lösung gegeben:
Wenn dein Compiler so verkorkst ist, dass er so etwas einfaches wie eine
Datentypanpassung (die genau geregelt ist) nicht hinkriegt, dann will
ich gar nicht wissen, was dieser Compiler noch alles nicht hinkriegt.
Dann gibt es nur eine Lösung: Diesen Haufen Schrott entsorgen und einen
wenigstens halbwegs vernünftigen Compiler nehmen.
Mark schrieb:> Funktioniert die Funktion PI_ohneL so wie sie soll?
Was wird das jetzt eigentlich schon wieder mal?
Schon wieder eine Nachhilfestunde in elementaren C Kentnissen? Denkst du
nicht, dass du derartige Dinge schon längst beherrschen solltest, ehe du
dich an dein erstes reales Projekt wagst?
Ich kann immer nur immer wieder den Kopf schütteln. Was waren wir doch
für Trottel damals, als wir unsere Programmiersprache von der Pieke auf
gelernt haben. Offenbar braucht mann das ja gar nicht. Seltsam ist immer
nur, dass es genau wir sind, die dann immer aushelfen müssen. Hmm. Ob da
wohl ein Zusammenhang besteht?
Karl Heinz schrieb:> Du solltest dir endlich mal angewöhnen zu akzeptieren, dass nicht deine> Compiler Implementierungen definieren, wie C zu funktionieren hat,> sondern einzig und allein der Standard.
Ach Karlheinz, mir scheint, daß dir mal wieder nach etwas Zoff oder
zumindest nach etwas Reibung zumute ist. Halte ich für völlig
überflüssig, aber was soll man machen, wenn ein Mod sich daneben
benimmt...
Also, das Einzige, was ICH akzeptiere, ist die blutige Praxis.
Theoretisierendes Geschwafel und Scholastik mag ich nicht. Eher schon
echte und vorzugsweise mathematische Logik. Deshalb sind die real in
dieser Welt existierenden Compiler-Implementierungen wichtiger als das
Wälzen irgend eines Standards - der zumindest für mich in einigen Teilen
höchst zweifelhaft ist. Und letztendlich sieht es eben genau so aus,
wie ich das geschrieben habe.
So. Wo const draufsteht, ist auch const drin - und du darfst dich nun
freuen (oder eher nicht), wenn dir dein Compiler beim Beschreiben einer
const Entity nicht auf die Finger haut. Du darfst also dir das Nötige
dafür angewöhnen.
Uff!
Aber mal zum grundsätzlichen Prinzip beim gleitenden Mittelwert als dem
zweitsimpelsten aller Filter:
1. es ist das am schnellsten berechenbare Filter
2. es ist das einzige, was wirklich formgetreu arbeitet, also keinerlei
Ripple und keinen Phasengang besitzt
3. es hat wie alle Filter eine konstante Signalverzögerung von
Taps/FSample. Da kommt man grundsätzlich nicht drum herum.
4. es ist der Sauberkeit zuliebe sicherlich eine gute Idee, den
Samplepuffer vor Erstverwendung zu nullen, aber wirklich notwendig ist
es nicht
Ähem.. das simpelste wäre ein IIR Filter:
Meßwert = (AlterMeßwert + AktuellerMeßwert)/2;
W.S.
W.S. schrieb:> So. Wo const draufsteht, ist auch const drin - und du darfst dich nun> freuen (oder eher nicht), wenn dir dein Compiler beim Beschreiben einer> const Entity nicht auf die Finger haut.
Ich stelle fest: Du hast kein Wort verstanden.
Wieder mal Halbwissen. Allerdings diesmal gepaart mit
Selbstüberschätzung.
Du treibst gerade eine tote Sau durchs Dorf. Denn das ...
> wenn dir dein Compiler beim Beschreiben einer const Entity nicht> auf die Finger haut.
... ist nicht der Unterschied den C zwischen einer 'non modifable
variable' und einer 'compile-time constant' macht. Auch Flash, ROM,
EEPROM, PROM, etc. haben damit aus Sicht der Sprache genau gar nichts zu
tun. Wenn dein Compiler const markierte Variablen ins Flash legt - schön
für ihn. Genau darum gehts aber nicht.
Es geht darum, dass der Begriff 'Konstante' eine definierte Bedeutung
hat. Und eine als const markierte Variable, qualifiziert sich nicht für
diese Bedeutung. Das wiederrum hat Konsequenzen, weil an einigen Stellen
in der C-Syntax explizit eine Konstante gefordert wird.
Nur mal eine kurze Anmerkung, weil ich stutzig geworden bin: Wenn man so
ein Filter nicht mittels Programm sondern mit Bauelementen realisiert,
dann muß doch nach dem ersten Einschalten auch erst mal einen Moment
gewartet werden, bis "hinten raus" brauchbare Sachen kommen.
Warum wollt ihr in dem Programm offenbar mit Gewalt diesen Moment, bis
15 oder 16 "Stützstellen" eingelaufen sind, nicht abwarten?
(Bitte die Frage in Klartext beantworten, ich kann kein "C" und will
(und muß) es auch nicht mehr lernen.)
MfG Paul
Paul Baumann schrieb:> gewartet werden, bis "hinten raus" brauchbare Sachen kommen.
'brauchbar' ist aber nicht 'es kommt zuerst mal nur 0 raus'.
> Warum wollt ihr in dem Programm offenbar mit Gewalt diesen Moment, bis> 15 oder 16 "Stützstellen" eingelaufen sind, nicht abwarten?
jedes Filter muss sich erst mal einschwingen.
Seines tut das offenbar nicht. Und das sollte eigentlich nicht so sein.
D.h. da gibt es irgendetwas im Programm, was entweder
* fehlerhaft
* oder nicht komplett verstanden
ist. Und das ist kein gutes Zeichen. Dem muss man nachgehen.
> (Bitte die Frage in Klartext beantworten, ich kann kein "C" und will> (und muß) es auch nicht mehr lernen.)
Das wär in BASCOM auch nicht anders.
Wenn du eine Berechnung hast, von der du weisst, dass sie nicht 0
ergeben kann und es kommt trotzdem 0 raus, dann ist irgendwo etwas faul.
Das können natürlich auch Eingangsdaten sein, die nicht die Werte haben,
die man annimmt das sie haben. Im Laufe der Jahre hab ich gelernt, genau
da als erstes Nachzuhaken: Sind die Werte, die ich in ein System
reingebe auch wirklich die, die ich die ganze Zeit einfach annehme ohne
sie gesehen zu haben? Öfter als mir lieb ist, stellt sich nämlich raus:
Ooops, sie sind es nicht.
Würde hier bedeuten: Der Filter ist vollkommen in Ordnung, aber die
ersten Datenwerte sind tatsächlich 0.
W.S. schrieb:> Das kommt nämlich ganz auf die Umstände drauf an. Bei Zeugs, was auf> deinem PC komplett im RAM läuft, hast du ja Recht, aber initialisierte> Konstanten landen bei den µC, die ich vor der Nase habe, gnadenlos im> Flash und bleiben dort auch. Da ist Neese mit Zuweisungen aller Art.> Allenfalls kriegt man ne Data-Exception auf die Rübe.
$OS kann Const in Readonly Pages tun.
Also an alle sich Beteiligenden schon ein Mal ein recht herzliches
Dankeschön.
Mir ist bewusst, dass man einfache Sachen von der Programmierumgebung
simulieren kann (AVR Studio 6). Aber eben nur einfache Sachen, das
setzen von Bits für INTs oder ADCs geht auch, macht mir aber schon
wieder keinen Spaß mehr.
Und Formeln habe ich natürlich vorher auch in Exel eingegeben und was
als Ergebnis rauskommt überprüft.
Eine RS232 Schnittstelle und Ausgabe auf HTerm etc. habe ich in meinem
Leben auch schon gemacht und halte ich für ziemlich wichtig, aber wenn
es die Platine nicht zulässt, ist es doof..
C Programmierung habe ich schon das ein oder andere Mal gemacht, aber
anscheinend zuvor nie mit static Variablen. Zugegeben habe ich den
Filter aus dem Netz, von dem sich hier auch bereits gemeldeten Person ;)
Trotzdem geht ja anscheinend auch alles mit globalen Variablen, die
behalten ja ihren Wert auch.. also mein Programm läuft, static war da
einfach der für mich unnötige Zusatz..
Gebe ich jedem Recht, dass man sich selber mit dem Thema und den
Grundlagen auseinander setzen muss. Und diese simplen Fragen zu
Grundlagen tuen mir Leid.
Ich bin beim Durchspielen im Kopf allerdings immer noch nicht ganz
darauf gekommen, wieso man avgsum und n auf null setzen muss.. Aber es
geht jetzt so, indem ich sie in der Tasterfunktion nulle.
Aber dazu eine Frage: wieso sollte ich nicht "n" als Variable benutzen?
Das tu ich nämlich. Man benutzt doch auch "i" zB..
Und eine weitere Frage: ist es jetzt ein IIR oder doch ein gleitender
Mittelwert Filter?
Mark schrieb:> Aber dazu eine Frage: wieso sollte ich nicht "n" als Variable benutzen?> Das tu ich nämlich. Man benutzt doch auch "i" zB..
Das kommt drauf an.
In einer Funktion mit optisch überschaubarem Geltungsbereich sind
einbuchstabige Variablennamen, besonders wenn es sich um Zähler handelt,
absolut kein Problem.
Wenn aber eine Variable global wird, dann läuft man schnell Gefahr, dass
in einem anderen Modul es auch eine Variable namens n gibt. Und dann
kollidiert das ganze. Je größer der Sichtbarkeitsbereich einer Variablen
ist, desto aussagekräftiger sollte ihr Name sein. Das heisst jetzt
nicht, dass da Wortmonster entstehen müssen. Aber mit einem
"nrFilterSamples" kann man auch in einem halben Jahr noch eruieren, was
der Zweck der Variablen war, und das das mit einem 'n' in der LCD
Ansteuerung nichts zu tun hat.
EInbuchstabige Variablen benutzt man gerne an Stellen, an denen man eine
Variable braucht, weil man etwas braucht was sich verändern kann aber
der genaue Name nicht so wichtig ist. Typischerweise sind das zb die
Laufvariablen in for-Schleifen; zb bei der Abarbeitung eines Arrays
1
for(i=0;i<irgendwas;i++)
2
data[i]=....
hier kommt es nicht wirklich auf den Namen an. Der 'Einsatzbereich'
dieser Variablen ist überschaubar eng. Ein längerer Name würde keinen
Lesevorteil bieten. Die Variable i hat keine spezielle spezifische
Bedeutung.
Mark schrieb:> Eine RS232 Schnittstelle und Ausgabe auf HTerm etc. habe ich in meinem> Leben auch schon gemacht und halte ich für ziemlich wichtig, aber wenn> es die Platine nicht zulässt, ist es doof..
Auch nicht, indem du die beiden Pins für die UART kurzerhand und mit
einem Messer von ihrer jetzigen Aussenbeschaltun befreist und einen
UARTzugang mit ein paar Drahtstücken und einem auf einem STück
Lochraster gelötetem MAX232 herstellst?
Ich würde das ins Auge fassen, ehe ich da jetzt Stunden in Rätselraten
investiere.
Da oben hast du sowieso noch sowas wie einen PID Regler, wenn ich das
richtig sehe. Auch bei dem wird sich so eine Ausgabemöglichkeit noch als
nützlich erweisen um mal zu sehen, wie sich eigentlich die PID Werte
zeitlich entwickeln.
Ok, danke für die ausführliche Antwort.
Evtl. werde ich das morgen in Angriff nehmen.
Aber da es ein wirklich winziger SMD uC ist, wird kein Kabel lange daran
halten..
Na mal sehen.
Und den Filter würde ich einfach VZ1 Filter nennen?
Mit gleitender Mittelwertbildung?
Mark schrieb:> Ok, danke für die ausführliche Antwort.>> Evtl. werde ich das morgen in Angriff nehmen.> Aber da es ein wirklich winziger SMD uC ist, wird kein Kabel lange daran> halten..
Es muss nur lang genug halten :-)
> Und den Filter würde ich einfach VZ1 Filter nennen?> Mit gleitender Mittelwertbildung?
es ist ein IIR Filter. Aber häng dich da jetzt nicht am Namen auf.
Karl Heinz schrieb:> Ich stelle fest: Du hast kein Wort verstanden.> Wieder mal Halbwissen. Allerdings diesmal gepaart mit> Selbstüberschätzung.
Du agierst nach dem Motto "Haltet den Dieb!.."
Tja, das Halbwissen und die Selbstüberschätzung gebe ich dir postwendend
zurück. Werde entweder konkret oder laß das Diskutieren mit mir sein.
Manchmal sehe ich bei dir einen Hang zur böswilligen Unterstellung,
insbesondere bei:
Karl Heinz schrieb:> ... ist nicht der Unterschied den C zwischen einer 'non modifable> variable' und einer 'compile-time constant' macht. Auch Flash, ROM..
Ganz konkret, du meinst wohl:
#define Karl 123
im Gegensatz zu
const int Heinz = 456;
Bei letzterem haben sehr wohl Flash, Rom und Konsorten was zu sagen,
denn dort landet Heinz, vorausgesetzt, es handelt sich um ne Firmware,
die dort gespeichert wird.
Jaja - beim alten Borland Pascal war das anders, da stand ganz fett in
der Doku, daß initialisierte Variablen eben nur initialisiert sind und
man dennoch schreibend drauf zugreifen kann. Also:
const
Karl = 123;
Heinz : integer = 456;
Aber das galt für einen Betrieb des Programmes im RAM ohne Schutz für
das Code- und Konstanten-Segment. Vielleicht ist das bei deinem Free-BSD
anders, daß man da lustig im Code oder den Konstanten herumschreiben
kann, ohne vom OS dabei erwischt zu werden.
W.S.
W.S. schrieb:> Ganz konkret, du meinst wohl:> #define Karl 123> im Gegensatz zu> const int Heinz = 456;
Karl Heinz hat das doch oben anhand eines Beispiel erläutert:
1
constintsize=5;
2
3
intdata[size];
Das geht in C nicht (in C++ schon). C erwartet als Größenangabe eines
Arrays einen konstanten Ausdruck.
Eine Variable (in diesem Fall size), auch wenn sie als const deklariert
wurde, ist aber kein konstanter Ausdruck im Sinne von C.
Sie ist es auch nicht, wenn sie vom Compiler/Linker ins Flash gelegt
wurde.
Sie ist es auch nicht, wenn statt des Flash maskenprogrammiertes ROM
verwendet wird.
Sie ist es auch nicht, wenn sie in Granit gemeißelt wurde.
Nicht einmal Diamant wäre hart genug, um aus der Variable einen
konstanten Ausdruck gemäß C-Standard zu machen.
Du kannst es drehen und wenden wie du willst: Obiges Code-Schnipsel ist
einfach kein korrektes C und wird von jedem C-Compiler zurecht angemahnt
werden.
Deswegen sollte man den Unterschied zwischen einer const-deklarierten
Variablen und einem konstanten Ausdruck kennen, egal, auf welcher
Architektur man programmiert.
Man kann jetzt beliebig lange darüber diskutieren, warum das Ganze
unlogisch ist. Ja, es ist unlogisch und wurde deswegen in C++ geändert.
Und es steht jedem, den das stört, frei, von C auf C++ umzusteigen. Der
Umstellungsaufwand ist nicht sehr groß.
Yalu X. schrieb:> Nicht einmal Diamant wäre hart genug, um aus der Variable einen> konstanten Ausdruck gemäß C-Standard zu machen.
Ich habe immer geahnt, daß C eine harte Sprache ist. Aber/so/ hart
-nein, das geht über alle Befürchtungen hinaus.
;-)
MfG Paul
Yalu X. schrieb:> Das geht in C nicht (in C++ schon). C erwartet als Größenangabe eines> Arrays einen konstanten Ausdruck.
Ach Yalu, erstmal Dank an dich für Sachlichkeit.
MIR ist das alles durchaus klar. ICH weiß durchaus zu unterscheiden
zwischen Ausdrücken (inc. konstanten Ausdrücken) einerseits und
Variablen, die gelegentlich als const Variablen deklariert sind und
deshalb eben ne Konstante sind bzw. gefälligst sein sollen, wodurch das
Wort "Variable" eigentlich sachlich falsch ist und besser "Konstante"
genannt werden sollte.
Karl Heinz schrieb:> Vorsicht:> In C ist eine als 'const' markierte Variable nach wie vor eine Variable.> Allerdings eine von der du die Zusicherung machst, dass du sie in deinem> Programm nicht verändern wirst. Das 'const' bedeutet in C 'not> modifiable'.> Es ist KEINE Konstante!
Da habe wir's: Karl Heinz verwechselt "Konstante" mit "konstanter
Ausdruck".
Genau DAS DAS DAS ist der elende Aufhänger:
Eine const Variable IST eine Konstante und ihr wurde in ihrer
Deklaration der Wert eines "konstanten Ausdruckes" zugewiesen. Das hat
nix mit gemachten Zusicherungen zu tun.
Uff. Ich hoffe, wir haben's jetzt endlich.
Es gibt bei vielen heutigen C-Compilern in dieser Hinsicht ein ganz
anderes Problem, nämlich, daß man const Variablen ohne typecast (sofern
technisch möglich) nicht als Argumente für Funktionen verwenden kann,
ohne vom Compiler angemosert zu werden, "warning: argument xyz looses
'const' property" oder so ähnlich. Das hat ja bei Harvard-Architekturen
durchaus seinen Sinn, weil dort ja ein Pointer, der in den Datenbereich
zeigt, etwas ganz anderes ist als einer, der in den Programm- und
Konstantenbereich zeigt. AVR's oder PIC's sind da typische Vertreter.
Aber bei nem ARM nervt sowas.
W.S.
W.S. schrieb:> Es gibt bei vielen heutigen C-Compilern in dieser Hinsicht ein ganz> anderes Problem, nämlich, daß man const Variablen ohne typecast (sofern> technisch möglich) nicht als Argumente für Funktionen verwenden kann,> ohne vom Compiler angemosert zu werden, "warning: argument xyz looses> 'const' property" oder so ähnlich.
Das liegt üblicherweise nicht am Compiler, sondern am Programmierer.
In folgendem Beispiel ist my_array als const deklariert, der Formalpara-
meter array von func aber nicht:
1
voidfunc(intarray[]);
2
3
intmain(void){
4
constintmy_array[3]={0,1,2};
5
6
func(my_array);
7
8
return0;
9
}
Beim Aufruf von func mit my_array könnte nun func die Elemente von
my_array überschreiben, was aber wegen der const-Deklaration von
my_array nicht sein darf. Das meckert der Compiler zurecht an.
Das Problem lässt sich dadurch beheben, dass der Formalparameter von
func ebenfalls als const deklariert wird:
1
voidfunc(constintarray[]);
Damit verschwindet die Fehlermeldung, es sei denn, func versucht
trotzdem, die Array-Elemente zu ändern. In diesem Fall wird eine
Fehlermeldung beim Kompilieren von func ausgegeben.
Man ist in C aber nicht gezwungen, const-Deklarationen zu verwenden. Nur
wenn man es tut, muss man es konsequent überall im gesamten Code tun.
> Das hat ja bei Harvard-Architekturen durchaus seinen Sinn
Auch hier: Das hat nicht primär etwas mit der Hardwarearchitektur zu
tun. Indem ich eine Variable als const deklariere, teile ich dem
Compiler mit, dass er davon ausgehen kann, dass sie bei jedem Zugriff
denselben Inhalt hat. Der Compiler kann dadurch ggf. Variablenzugriffe
wegoptimieren.
Mit der const-Deklaration bitte ich den Compiler aber auch nachzusehen,
ob in meinem Code die Variable nicht versehentlich doch irgendwo
beschrieben wird. Das wäre dann ein Programmierfehler, und es freut
mich, wenn er bereits zur Compile-Zeit aufgedeckt wird.
Ein const in der Variablendeklaration bedeutet übrigens nicht unbedingt,
dass der Variableninhalt bereits zur Compile-Zeit bekannt ist und die
Variable deswegen im nichtflüchtigen Speicher angelegt werden kann. Es
bedeutet lediglich, dass die Variable, nach dem sie einmal initialisiert
worden ist, für den Rest ihrer Lebensdauer nicht mehr geändert wird. Der
Initialisierungswert muss auch nicht unbedingt ein konstanter Ausdruck
sein.
Beispiel:
1
voidfunc(intn){
2
constintn2=n*n;
3
.
4
.
5
}
Hier kann n2 bei jedem Aufruf von func einen anderen Wert annehmen
(abhängig vom Argument n). Bis zum Ende von func kann n2 aber kein neuer
Wert zugewiesen werden.
Mark schrieb:> Nur nach dem erneuten Starten des Programms durch einen Taster steigt> und fällt die anfängliche Totzeit mit n!?
Wie bekommst du da ein n Fakultät in deine Rechnung? Das solltest du
noch mal genau prüfen.
Yalu X. schrieb:> Das Problem lässt sich dadurch beheben, dass der Formalparameter von> func ebenfalls als const deklariert wird:> void func(const int array[]);
Na klasse.
So, und nun schreib mal, wie du dir einen Treiber vorstellst, der
beides ohne Warnung verträgt, z.B. sowas:
bool String_Out(char* P, int UART) {....}
also einen Peripherietreiber, der sowohl den Inhalt von Pufferarrays als
auch konstante Strings ausgeben kann.
Nee, ich meine hier NICHT NUR sowas:
String_Out("YALU", COM1); //(das geht immer)
sondern eben auch
const char yalu[] = { 'Y','A','L','U',0 };
char buf[120];
...
String_Out(buf, COM2);
und
String_Out(yalu, COM3);
Egal wie du es drehst und wendest, entweder plazierst du bei wenigstens
einem Aufruf nen Cast oder du mußt mit der Warnung leben. Das war der
Punkt den ich angesprochen hatte.
W.S.
W.S. schrieb:> Egal wie du es drehst und wendest, entweder plazierst du bei wenigstens> einem Aufruf nen Cast oder du mußt mit der Warnung leben. Das war der> Punkt den ich angesprochen hatte.
Wieso hast du das const vor dem char *P nicht einfach mal ausprobiert?
Dann wäre dir vielleicht ein Licht aufgegangen.
Natürlich kannst du jederzeit eine Nicht-Const-Variable in einem
Const-Kontext verwenden, nur umgekehrt nicht.
Oder anders ausgedrückt:
Es ist zwar verboten, eine Const-Variable zu verändern, es ist aber
nicht verboten, eine Nicht-Const-Variable unverändert zu lassen.