Forum: Mikrocontroller und Digitale Elektronik Programmoptimierung


von Don Panso (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen!

Ich bin schon seit geraumer Zeit glücklicher Nutzer dieses Forums. Hier 
ist schon so manches meiner Probleme kompetent gelöst worden. Unter 
Zuhilfenahme anderer Forumseinträge habe ich es nun geschafft, selber 
ein Programm für einen Mikrocontroller zusammen zu schustern. Da ich 
niemanden persönlich kenne (mich eingeschlossen), der sich gut mit der 
Materie des µC-Programmierens auskennt, stelle ich das Programm zwecks 
Optimierung nun der allgemeinen Weisheit dieses Forums zur Verfügung.
Was ich sagen will, ist, das das Programm im Großen und Ganzen 
funktioniert (es gibt kleinere Probleme, auf die ich später noch 
eingehe). Jedoch gibt es bestimmt noch Verbesserungen zu machen. 
Villeicht gibt es sogar Fehler, die später noch zu größeren Problemen 
führen. Dem möchte ich vorbeugen. Deswegen die Frage: kann jemand bitte 
dieses Programm kontrollieren?

Ja klar, das klingt jetzt absolut hochgestochen, aber ich weiss, dass es 
Leute da draussen gibt, die gerne ihr Wissen mit Unwissenden teilen. Und 
an die wende ich mich. Also, wenn ihr die Zeit und den Willen aufbringen 
wollt und könnt, wäre das echt nett.
Und bitte denkt nicht, das läuft hier jetzt nach dem Motto "ICH habe 
MEIN perfektes Programm hier reingestellt, damit sich diese 
Möchtegern-Schlauen die Zähne ausbeissen. Muahahahaha!". So ist das 
nicht. Ich programmiere erst seit ein paar Wochen...die Grundlagen des 
Programmierens mit C kenne ich einigermaßen, aber ansonsten bin ich ein 
absoluter Noob. Ich bin von mir selbst überrascht, dass das Programm 
überhaupt einigermaßen funktioniert :-D

Also, das Programm tut folgendes:
Die Ausgansspannung eines Volumenstrom- (im Programm habe ich das 
Flowmeter genannt) und eines Differenzdrucksensors soll mittels ADC 
gemessen werden. Die Spannungswerte sollen in die dazugehörigen 
physikalischen Werte (mit den Einheiten Liter/min und mbar) umgerechnet 
und auf einem Display angezeigt werden. Bei Verlassen vorgegebener 
Sollwerte, soll ein piepender Alarmton ertönen, der auf Tastendruck 
wieder abgeschaltet werden kann.
Zur Verfügung stehen: - ATmega16L
                      - STK500
                      - 16x2 Display im 4bit-Modus
                      - Volumenstrommesser
                      - Differendrucksensor
                      - Taster
                      - kleiner Lautsprecher

Manchmal taucht das Problem auf, dass nach Abweichung der Sollwerte der 
Alarmton nur einmal zu hören ist und danach ausbleibt, obwohl die Werte 
immer noch Abweichen. Der Alarmton sollte aber so lange zu hören sein, 
bis der Taster gedrückt wird.

Konstruktive Kritik ist absolut willkommen. Was geht besser? Was sollte 
lieber gar nicht gemacht werden?

Vielen Dank und einen schönen Weltkindertag noch! :-)

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> Manchmal taucht das Problem auf, dass nach Abweichung der Sollwerte der
> Alarmton nur einmal zu hören ist und danach ausbleibt, obwohl die Werte
> immer noch Abweichen. Der Alarmton sollte aber so lange zu hören sein,
> bis der Taster gedrückt wird.

Wie ist dein Taster angeschlossen.
Ich sehe im Code nicht, dass du für die übliche Tasterbeschaltung einen 
Pullupwiderstand einschaltest?

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> Konstruktive Kritik ist absolut willkommen. Was geht besser? Was sollte
> lieber gar nicht gemacht werden?

Du hast einen Haufen magische Zahlenwerte mitten im Code

Ich würde mir auch noch Variablen machen, die aussgane ob der Messwert 
innerhalb der Grenzen ist oder nicht.

Dadurch:
   Sind die magischen Zahlenkonstanten für die Grenzen nur an einer
   Stelle
   die Abfrage ob der ALarmton eingeschaltet werden soll bzw. die andere
   vereinfacht sich und wird leichter lesbar
   Hast du auch noch eine simple Möglichkeit, wie du dem Benutzer zb
   mit einem zusätzlichen '!' im LCD anzeigen kannst, welcher Messwert
   eigentlich abweicht und zum Alarm geführt hat.


Aufteilen in Funktionen!
Die ADC Abfrage ist bis auf die Kanalnummer immer gleich -> perfekter 
Kansidat für eine Funktion

Das Konfigurieren von irgendwelchen Steuerregister durch Zuweisung von 
magischen Bitkonstanten ist verpönt. Im Datenblatt hat jedes Bit einen 
Namen. Mit der 1 << Bitname Syntax arbeiten!

1
  hilf_low_flow = ADCL;
2
  adcwert_flow = (ADCH << 8);
3
  adcwert_flow |= hilf_low_flow;
Dein Compiler weiß schon wie man 16 Bit Register ausliest und hält dafür 
Pseudoregister bereit:
1
  adcwert_flow = ADCW;

Den ADC liest man nicht nach einem _delay aus, sondern wenn der ADC 
'fertig' meldet.

von Peter D. (peda)


Lesenswert?

Don Panso schrieb:
> Manchmal taucht das Problem auf, dass nach Abweichung der Sollwerte der
> Alarmton nur einmal zu hören ist und danach ausbleibt, obwohl die Werte
> immer noch Abweichen. Der Alarmton sollte aber so lange zu hören sein,
> bis der Taster gedrückt wird.

Das schreit nach einer soliden SW-Entprellung.


Peter

von Uwe .. (uwegw)


Lesenswert?

Den ADC kann man in C (avr-libc) auch mit ADCW auslesen, statt sich den 
Wert aus ADCL und ADCH zusammenzusuchen.

Wenn die Sache zeitkritisch wäre (wovon ich wegen den vielen delays mal 
nicht ausgehe) könnte man die Fließkommaberechnung rauswerfen und durch 
Festkommaarithmetik ersetzen.

Die Taste sollte besser in einem Timer-Interrupt abgefragt und entprellt 
werden. Dann dauert es nicht 450ms, bis sie im worst-case reagiert. So 
wird auch kein kurzer Tastendruck zwischen zwei Abfragen übersehen.

von ff (Gast)


Lesenswert?

idealerweise nutzt man das loslassen des tasters aus


also merken wenn taster gedrückt ... wenn dieser taster auch nach einer 
gewissen zeit losgelassen wurde .. wollte man wirklich was ..
ansonst nix tuen...

anhand der loslasszeit kann man sogar noch dinge unterscheiden..


ich würde ALLE delays raushauen und mich mal an deiner stelle mit 
Statemaschines befassen

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Don Panso schrieb:
> Konstruktive Kritik ist absolut willkommen. Was geht besser? Was sollte
> lieber gar nicht gemacht werden?
Wähle doch bitte nächstes mal einen etwas besseren Threadtitel! Was hat 
das ganze den Bitte mit Programm"optimierung" zu tun?

von Peter D. (peda)


Lesenswert?

ff schrieb:
> idealerweise nutzt man das loslassen des tasters aus

Das ist überhaupt nicht ideal, sondern das Gegenteil.

Der Mensch erwartet eine Reaktion beim Drücken!

Ich möchte Dich mal sehen, wenn Deine PC-Tastatur die Zeichen erst beim 
Loslassen ausgeben würde. Du würdest das Keyboard in kürzester Zeit auf 
den Boden feuern und wutentbrand zertreten.


Peter

von Don Panso (Gast)


Lesenswert?

Guten morgen allerseits!
Mensch das ging ja schnell mit den Antworten. Vielen Dank dafür! Sorry, 
dass ich erst jetzt antworte...

Karl heinz Buchegger schrieb:
> Wie ist dein Taster angeschlossen.
> Ich sehe im Code nicht, dass du für die übliche Tasterbeschaltung einen
> Pullupwiderstand einschaltest?

Der Taster ist auf dem STK500. Dort ist die Stiftleiste des PortB mit 
der Stiftleiste der Taster verbunden. Da die Taster active low sind, 
habe ich die Abfrage des Tastendrucks mit "if(!(PINB & (1 << PINB0)))" 
vollzogen. Der Pullupwiderstand muss rein? Ok, dann füge ich noch ein 
"PORTB = 0x01;" ein.

Karl heinz Buchegger schrieb:
> Im Datenblatt hat jedes Bit einen
> Namen. Mit der 1 << Bitname Syntax arbeiten!

Du hast recht, das ist übersichtlicher, führt aber zuweilen zu ewig 
langen Zeilen bzw. zu mehr Schreibarbeit. Da ich faul bin habe ich mir 
das abgewöhnt, dennoch werde ich das in der nächsten Fassung des 
Programms beherzigen.

Karl heinz Buchegger schrieb:
> Ich würde mir auch noch Variablen machen, die aussgane ob der Messwert
> innerhalb der Grenzen ist oder nicht.

Meinst du z.B. eine Variable "int flowwert_zu_niedrig;", die man dann in 
einem if-Statement beispielsweise zu '1' setzt, wenn der flowwert zu 
niedrig wird?

Karl heinz Buchegger schrieb:
> Aufteilen in Funktionen!

Stimmt, die ADC-Routine ist gut in eine Funktionen zu fassen. Das wird 
übernommen ;-)

Karl heinz Buchegger schrieb:
> adcwert_flow = ADCW;

Sehr guter Vorschlag. Das kannte ich noch nicht...kommt auf jeden Fall 
rein.

Karl heinz Buchegger schrieb:
> Den ADC liest man nicht nach einem _delay aus, sondern wenn der ADC
> 'fertig' meldet.

Ok wird auch gemacht. Habe ich mal irgendwo gesehen wie das geht.


@Peter & Uwe
Mal gucken, ob ich das mit dem Tasten-Entprellen mache. Ist das wirklich 
nötig? Für den Benutzer ist das denke ich mal kein Problem den Taster 
ein bisschen länger gedrückt zu halten...

ff schrieb:
> idealerweise nutzt man das loslassen des tasters aus

Auch ein guter Vorschlag. Wird villeicht umgesetzt. Muss zwar noch 
herausfinden wie, aber das wird schon.

Läubi .. schrieb:
> Was hat
> das ganze den Bitte mit Programm"optimierung" zu tun?

Damit will ich sagen, dass das Programm zwar meistens das tut, was es 
soll, jedoch nicht perfekt ist. Das will ich mit eurer Hilfe ändern. Die 
Effizienz des Programms soll verbessert werden. Meines wissens nennt man 
das "Optimierung". Sollte ich aber mal einen anderen Thread eröffnen, 
stecke ich ein wenig mehr Gehirnschmalz in den Titel.


Ich kann nur nochmals sagen: vielen Dank für eure schnellen Antworten! 
Ich werde das Programm umschreiben und eure Ratschläge auf jeden Fall 
befolgen. Das wird wohl etwas dauern, aber wer die Geduld hat diesem 
Thread noch ein bisschen zu folgen (was ich natürlich von keinem 
verlange), der kann im Laufe des Tages womöglich noch die verbesserte 
Version des Programmes betrachten. Ich geh dann mal wieder zurück an die 
Arbeit ;-)

Vielen Dank nochmal und einen schönen Tag noch!

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> Der Taster ist auf dem STK500. Dort ist die Stiftleiste des PortB mit
> der Stiftleiste der Taster verbunden. Da die Taster active low sind,
> habe ich die Abfrage des Tastendrucks mit "if(!(PINB & (1 << PINB0)))"
> vollzogen. Der Pullupwiderstand muss rein? Ok, dann füge ich noch ein
> "PORTB = 0x01;" ein.

Das weiß ich nicht, weil ich nicht weiß, ob auf dem STK externe Pullup 
Widerstände verbaut sind oder nicht.

Irgendeinen Pullup muss es geben, sonst hängt der Eingang in der Luft, 
wenn der Taster nicht gedrückt ist.

Da ich allerdings davon ausgehe, dass dein Programm letztendlich nicht 
auf dem STK500 bleiben wird, sondern seine eigene Platine bekommen wird, 
sind die internen Pullups sicher eine gute Idee :-)


>> Im Datenblatt hat jedes Bit einen
>> Namen. Mit der 1 << Bitname Syntax arbeiten!
>
> Du hast recht, das ist übersichtlicher, führt aber zuweilen zu ewig
> langen Zeilen bzw. zu mehr Schreibarbeit.

Regel:
Code schreibt man einmal, man liest ihn aber viele male.

Lieber etwas mehr Aufwand beim Schreiben, als ihn jedesmal beim Lesen 
erneut entziffern zu müssen.

> Da ich faul bin habe ich mir
> das abgewöhnt,

Das gewöhnst du dir ganz schnell wieder an, wenn du jemals Code von 
einem Prozessor zu einem anderen portieren musst, der zwar dieselben 
Bits in denselben Registern aber in etwas anderer Reihenfolge hat.

Dann musst du nämlich mit der Bitnamen Syntax gar nichts tun, während du 
mit der Bitschreibweise rumpfriemeln musst.

>> Ich würde mir auch noch Variablen machen, die aussgane ob der Messwert
>> innerhalb der Grenzen ist oder nicht.
>
> Meinst du z.B. eine Variable "int flowwert_zu_niedrig;", die man dann in
> einem if-Statement beispielsweise zu '1' setzt, wenn der flowwert zu
> niedrig wird?

Nein.
ein
uint8_t flowwert_in_range;
wäre angebracht.

denn das ist es doch was dich interessiert: ist der Wert im erlaubten 
Bereich oder nicht.
1
   flowwert_in_range = ( flowwert > FLOW_MINIMUM && flowwert < FLOW_MAXIMUM );

und dann lesen sich deine Abfragen zb so
1
   if( flowwert_in_range )
2
     mach was
3
4
   if( !flowwert_in_range && alarm_enabled )
5
     fail_sound();

Schon fast ein kompletter Satz. Ich brauch mir nur ein paar Füllwörter 
wie der/die/das dazudenken und kann fast im Klartext lesen und verstehen 
was da eigentlich passiert.

> Ok wird auch gemacht. Habe ich mal irgendwo gesehen wie das geht.

Für solche Sachen sollte das AVR-GCC-Tutorial deine erste Anlaufstelle 
sein, nicht Code den du 'irgendwo' mal gesehen hast.

> @Peter & Uwe
> Mal gucken, ob ich das mit dem Tasten-Entprellen mache. Ist das wirklich
> nötig? Für den Benutzer ist das denke ich mal kein Problem den Taster
> ein bisschen länger gedrückt zu halten...

Es geht nicht darum, dass der Benutzer etwas länger drücken muss. Es 
geht darum, dass der Benutzer 1 mal drückt, der Alarm allerdings 2 mal 
ausgeschaltet wird. IMHO in deiner Anwendung kein Problem, denn ein 
Alarm der bereits abgeschaltet ist kann nicht weiter abgeschaltet 
werden.

>> idealerweise nutzt man das loslassen des tasters aus
>
> Auch ein guter Vorschlag.

Kein guter Vorschlag. Peter hat schon geschrieben warum.
Ausserdem: Was soll das?
Ich will den Alarm ausschalten, während ich Drücke komme ich drauf, dass 
ich das dann doch nicht will also bleib ich länger am Knopf, damit das 
Programm die Aufforderung ignoriert?

Sowas schmeiss ich dir um die Ohren, wenn du mir sowas andrehen willst.
Was kommt als nächstes?
1
    +------------------------------------------------------------+
2
    | Sie haben den Knopf gedrückt um den Alarm abzustellen!     |
3
    | Sind sie sicher?                                           |
4
    |                                                            |
5
    |  +-------+    +----------+     +--------------------+      |
6
    |  |  Ja   |    |   Nein   |     |   Weiß noch nicht  |      |
7
    |  +-------+    +----------+     +--------------------+      |
8
    +------------------------------------------------------------+

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>> Namen. Mit der 1 << Bitname Syntax arbeiten!

>Du hast recht, das ist übersichtlicher, führt aber zuweilen zu ewig
>langen Zeilen bzw. zu mehr Schreibarbeit. Da ich faul bin habe ich mir
>das abgewöhnt,

Schlechte Entscheidung.

> dennoch werde ich das in der nächsten Fassung des
>Programms beherzigen.

Gute Entscheidung!

>Meinst du z.B. eine Variable "int flowwert_zu_niedrig;", die man dann in
>einem if-Statement beispielsweise zu '1' setzt, wenn der flowwert zu
>niedrig wird?

Ja. Das nennt man allgemein Flags, also (binäre) Merker, welche 
bestimmte Dinge anzeigen. Sie werden vom "Verursacher" gesetzt und von 
der Auswertung wieder gelöscht. In deinem Fall heisßt dass, der Merker 
wird in einer if() Abfrage gesetzt und in einer andern Abfrage der 
entprellten Tasten gelöscht. Zwischendrin tutet es ununterbrochen ;-)

>> Den ADC liest man nicht nach einem _delay aus, sondern wenn der ADC
>> 'fertig' meldet.

>Ok wird auch gemacht. Habe ich mal irgendwo gesehen wie das geht.

Vielleicht hier?

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#ADC_.28Analog_Digital_Converter.29

>Mal gucken, ob ich das mit dem Tasten-Entprellen mache. Ist das wirklich
>nötig?

Es ist deutlich besser. Und tut auch nicht weh.

>Auch ein guter Vorschlag. Wird villeicht umgesetzt. Muss zwar noch
>herausfinden wie, aber das wird schon.

Siehe Entprellung.

>> Was hat
>> das ganze den Bitte mit Programm"optimierung" zu tun?

>Damit will ich sagen, dass das Programm zwar meistens das tut, was es
>soll, jedoch nicht perfekt ist. Das will ich mit eurer Hilfe ändern.

Dann schreib das in den Betreff!

"Hilfe zur Programmverbesserung gesucht".

> Die Effizienz des Programms soll verbessert werden.

Du bist noch lange nicht in der Liga, in der man von Effizienz oder gar 
deren Steigerung spricht. Du musst erstmal noch einige Grundlagen lernen 
und umsetzen.

>stecke ich ein wenig mehr Gehirnschmalz in den Titel.

Verbindlichsten Dank. Und lies vorher was über Netiquette und 
Bildformate, nur so als Vorwarnung.

MfG
Falk

von Peter D. (peda)


Lesenswert?

Don Panso schrieb:
> Damit will ich sagen, dass das Programm zwar meistens das tut, was es
> soll.

Dann ist es fehlerhaft und es muß nichts optimiert werden, sondern der 
Fehler beseitigt.

Optimieren bedeutet, daß Programm läuft fehlerfrei und man will z.B. den 
Flash-Verbrauch oder den Stromverbrauch (CPU-Last) reduzieren.

Fehler beseitigen und Optimieren sind 2 völlig verschiedene Dinge.
Es kann sich aber manchmal erst beim Optimieren ein Fehler bemerkbar 
machen, z.B. volatile-Fehler.


Peter

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
>>Damit will ich sagen, dass das Programm zwar meistens das tut, was es
>>soll, jedoch nicht perfekt ist. Das will ich mit eurer Hilfe ändern.
>
> Dann schreib das in den Betreff!
>
> "Hilfe zur Programmverbesserung gesucht".
Noch besser wäre eigentlich den Prozessortyp noch zu nennen und 
vieleicht irgenwie das Problem in den Vordergrund zu stellen (z.B. 
Tastendruck wird nicht immer erkannt). Das jemand Hilfe sucht ist in 
diesem FOrum meist sowieso anzunehmen ;)

von Karl H. (kbuchegg)


Lesenswert?

Mir schwant da noch was.
Zeig doch mal die Funktion fail_sound()

Wenn die so aussieht, wie ich zur Zeit vermute, dann zieh ich den 
Einwand mit der nicht notwendigen Entprellung wieder zurück.

Nicht weil die Entprellung unbedingt notwendig wäre (ich denke immer 
noch, dass ein prellender Taster in diesem konreten Fall kein Problem 
darstellt), sondern weil dir die PeDa Entprellung dafür sorgt, dass kein 
Tastendruck verloren gehen wird.

Je länger ich mir das alles ansehe um so mehr komme ich zum Schluss:
Das Programm ist zwar aus Newbie-Sicht bzw. für eine 
Desktop-Programmierer vernünftig aufgebaut.
Jemand der allerdings im Embedded Bereich arbeitet, schlägt die Hände 
über dem Kopf zusammen. So arbeitet man nicht, wenn ein Programm mehrere 
Dinge 'gleichzeitig' machen soll:
   Piepton ausgeben
   Taste überwachen
   Messwerte überwachen

Im Embedded Bereich gilt als Faustregel (mit ein paar kleinen 
Ausnahmen):
Sobald der erste _delay_ms auftaucht, ist das Programmdesign schon 
falsch.

von Don Panso (Gast)


Angehängte Dateien:

Lesenswert?

Hallo mal wieder!
Ok, das mit dem Thread-Titel tut mir leid. Das ist mein erster Thread 
und ich dachte einfach das ist ein guter Titel, der aussagt, was ich 
eigentlich will...dem scheint wohl nicht zu sein. Ich gelobe Besserung!

Falk Brunner schrieb:
> Und lies vorher was über Netiquette

Auch wenn das mit dem Gehirnschmalz ein wenig frech klang, möchte ich 
gerne an dieser Stelle anmerken, dass das nicht böse oder abwertend 
gemeint war. Ich respektiere und finde es sehr freundlich von euch, das 
ihr euch die Zeit nehmt, anderen Leuten zu helfen und mein Programm auf 
ein professionelleres Niveau zu heben. Alles was ich hier schreibe bitte 
nicht negativ sehen.

Karl heinz Buchegger schrieb:
>>> idealerweise nutzt man das loslassen des tasters aus
>>
>> Auch ein guter Vorschlag.
>
> Kein guter Vorschlag.

Stimmt...es lohnt sich nicht, den Taster gedrückt zu halten, nur weil 
man es sich anders überlegt hat und den Alarm doch anlassen will.
Ich hoffe, ihr nehmt es mir nicht übel, dass ich mich so hin und her 
reissen lasse. Ich denke, dass zeugt einfach davon, dass ich noch nicht 
so tief in der Materie drin bin.

Karl heinz Buchegger schrieb:
> Für solche Sachen sollte das AVR-GCC-Tutorial deine erste Anlaufstelle
> sein

Das erwähnte "irgendwo" schliesst das AVR-GCC-Tutorial mit ein. Dort 
habe ich schon viele Lösungen für Probleme gefunden.

Karl heinz Buchegger schrieb:
> Das weiß ich nicht, weil ich nicht weiß, ob auf dem STK externe Pullup
> Widerstände verbaut sind oder nicht.

Das STK500 besitzt keine externen Pullup-Widerstände, aber wenn die 
internen des µC auch ok sind, dann nehme ich die.

Karl heinz Buchegger schrieb:
> flowwert_in_range = ( flowwert > FLOW_MINIMUM && flowwert < FLOW_MAXIMUM );

Ich hoffe, da ist kein copyright drauf ;-)


Falk Brunner schrieb:
>>> Den ADC liest man nicht nach einem _delay aus, sondern wenn der ADC
>>> 'fertig' meldet.
>
>>Ok wird auch gemacht. Habe ich mal irgendwo gesehen wie das geht.
>
> Vielleicht hier?

Jup, genau da! Danke trotzdem nochmal für den Link. :-)

Falk Brunner schrieb:
>>Mal gucken, ob ich das mit dem Tasten-Entprellen mache. Ist das wirklich
>>nötig?
>
> Es ist deutlich besser. Und tut auch nicht weh.

Oooookkkkkk. Wenns nicht weh tut, dann entprelle ich eben den Taster. 
Ist ja auch im Tutorial gut beschrieben, wie das geht.

Karl heinz Buchegger schrieb:
> Zeig doch mal die Funktion fail_sound()

Ich füge die Header-Datei "fail_jingle.h", in der die Funktion 
"fail_sound()" definiert ist, in den Anhang ein. Funktioniert ganz gut 
mit einem Lautsprecher...auf die Weise kann man sogar ein Klavier 
programmieren, aber das ist eine andere Sache...

Karl heinz Buchegger schrieb:
> So arbeitet man nicht, wenn ein Programm mehrere
> Dinge 'gleichzeitig' machen soll

Ich weiss, dass das Programm sequentiell abläuft und das es z.B. nichts 
bringt, während dem Alarmton oder der ADC-Wandlung, den Taster zu 
drücken. Ich hab es jetzt nicht nachgerechnet, aber die maximale 
Wartezeit, bis der Tastendruck registriert wird, ist durchaus 
akzeptabel. Für professionelle Anwendungen ist das sicher nichts, aber 
ich denke, für dieses Problem hier wird das schon reichen.

Danke für eure Geduld und Hilfsbereitschaft.

P.S.: und ich hoffe, das mit dem Thread-Titel is jetzt geklärt :-D

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

>> So arbeitet man nicht, wenn ein Programm mehrere
>> Dinge 'gleichzeitig' machen soll
>
> Ich weiss, dass das Programm sequentiell abläuft und das es z.B. nichts
> bringt, während dem Alarmton oder der ADC-Wandlung, den Taster zu
> drücken.

Darum gehts in Wirklichkeit gar nicht.
Das mag jetzt in deiner Anwendung kein konkretes Problem sein, trotzdem 
sollte man die Dinge gleich richtig lernen, sofern das vom Aufwand her 
vertretbar ist.

Es geht darum, dass die nobelste Eigenschaft deines Programms darin 
besteht 2 Eingangswerte zu überwachen.
Das ist die Hauptaufgabe des Programms.
OK Dein Programm macht jetzt nichts weiter mit den Werten, aber wenn die 
Werte zb dazu benutzt werden würden, bei einer Überschreitung eine 
Notabschaltung oder sonstige Korrekturmassnahmen einzuleiten, dann ist 
es einfach nicht akzeptabel, wenn diese Überschreitung ein paar 100 
Millisekunden zu spät festgestellt wird oder die Massnahmen ein paar 100 
Millisekunden später beginnen, nur weil der µC damit beschäftigt ist, 
vor sich hin zu tröten.

Vor allen Dingen ist das deshalb nicht akzeptabel, weil man das alles 
durch den Einsatz eines Timers und Interrupts auch ganz einfach 
'parallelisieren' kann. So wie eine Timer ISR eine LED blinken lassen 
kann, so kann sie auch die Membran einer Tröte vor und zurück schnellen 
lassen. Das verbraucht noch nicht einmal 1% Rechenzeit nebenher, von 
denen das Hauptprogramm überhaupt nichts merkt.

In einem Programm mehrere Dinge quasi gleichzeitig zu machen, läuft 
immer in irgendeiner Form auf einen Timer und eine ISR hinaus.

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>Ich füge die Header-Datei "fail_jingle.h", in der die Funktion
>"fail_sound()" definiert ist, in den Anhang ein.

MööööP! Schon wieder falsch. In *.h Dateien gehört kein Programmcode, 
sondern nur defines, Deklarationen und ggf. Makros.
Programmcode gehört immer in *.c Dateien.

> Funktioniert ganz gut
>mit einem Lautsprecher...auf die Weise kann man sogar ein Klavier

Naja, für einen Anfänger ist das soweit OK. Aber das kann man einfacher 
und besser, weil parallel zum normalen Programmablauf, mit einem Timer 
und der Output Compare-Funktion machen.
Und allgemein was zum Thema "viele Sachen gleivhzeitig bearbeiten" 
findest du im Artikel Multitasking.

>drücken. Ich hab es jetzt nicht nachgerechnet, aber die maximale
>Wartezeit, bis der Tastendruck registriert wird, ist durchaus
>akzeptabel.

~1s. Naja.
Schau mal in den Artikel Multitasking, denk drüber nach und 
präsentier uns dann ein deutlich verbessertes, aufgeräumtes Programm. Du 
schaffst das!

MFG
Falk

von Falk B. (falk)


Lesenswert?

Ach ja, noch was. Lies was über Festkommaartihmetik und du wirst 
staunen, wie sehr dein Verbrauch an Flash-Speicher zurückgeht.

MFG
Falk

von Don Panso (Gast)


Lesenswert?

Mensch, ihr seid ja echt fix! Da komm ich gar nicht hinterher :-D

Ein wiederholtes Dankeschön fürs am Ball bleiben.

Karl heinz Buchegger schrieb:
> weil man das alles
> durch den Einsatz eines Timers und Interrupts auch ganz einfach
> 'parallelisieren' kann

Falk Brunner schrieb:
> Und allgemein was zum Thema "viele Sachen gleivhzeitig bearbeiten"
> findest du im Artikel Multitasking.

Ich habe mich schon immer mal gefragt, wie man gleichzeitig Sachen 
bearbeiten kann, aber nie die Zeit gefunden mich ausgiebig damit zu 
beschäftigen. Daher sind meine bisherigen Programme immer sequentiell 
abgelaufen (bis auf einmal, wo ich einen Timer nebenher als Stoppuhr 
laufen gelassen habe).
Das ist jetzt alles viel Stoff...wird wohl ein bisschen Zeit in Anspruch 
nehmen, mich da einzulesen.

Falk Brunner schrieb:
> Du
> schaffst das!

Danke, die Motivation kann ich gebrauchen. :-D
Wenn ihr Lust habt könnt ihr hier demnächst (das kann ein Zeitraum von 
mehreren Tagen sein; steht auch ein langes Wochenende vor der Tür, wo 
ich endlich mal etwas Freizeit habe) das überarbeitete Programm 
anschauen. Ich halte mich auf jeden Fall ran! Jetzt lerne ich erst mal 
Multitasking!

Mfg,
    D. Panso

P.S.:

Falk Brunner schrieb:
>>Ich füge die Header-Datei "fail_jingle.h", in der die Funktion
>>"fail_sound()" definiert ist, in den Anhang ein.
>
> MööööP! Schon wieder falsch.

Mist schon wieder steh ich im Fettnäpfchen!

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> Ich habe mich schon immer mal gefragt, wie man gleichzeitig Sachen
> bearbeiten kann, aber nie die Zeit gefunden mich ausgiebig damit zu
> beschäftigen.

Wenn du einen Schweinsbraten im Rohr hast, bleibst du dann vor dem Herd 
stehen und wartest bis der fertig ist?

Natürlich nicht.
Du hast einen Haufen Aufgaben zu erledigen.
zb Schweinsbraten kochen
   Hausaufgaben kontrollieren
   Geschirr abwaschen

Anstatt jetzt jede Aufgabe für sich zu erledigen und (eventuell) 
abzuwarten bis sie fertig ist, wird bei jeder Aufgabe immer nur ein 
kleiner Teil erledigt und dann gehts weiter zur nächsten

  ins Rohr schauen ob Braten fertig
  eine Rechnung der Hausaufgabe kontrollieren
  ein Teller abwaschen
  ins Rohr schauen ob Braten fertig
  eine Rechnung kontrollieren
  ein Teller abwaschen
  ins Rohr Schauen ....

und so gehts reihum immer durch. In manchen Fällen muss man noch vorab 
testen, ob es überhaupt etwas zu tun gibt und nur dann eine Aktion 
machen, wenn das der Fall ist

  while( 1 )

    if Braten im Rohr fertig ?
       aus dem Rohr nehmen

    if Kind hat wieder eine Rechnung fertig
       Rechnung kontrollieren

    if Teller am schmutzigen Teller stapel
       Teller abwaschen

aber das Prinzip ist nach wie vor das gleiche: Du bleibst nicht beim 
Rohr stehen, du bleibst nicht bei Töchterchen/Sohn stehen, du bleibst 
nicht an der Abwasch, sondern machst einen kleinen Teil der Aufgabe 
(wenn er machbar ist) und gehst dann weiter zur nächsten Aufgabe.

Ob man das jetzt wie im Artikel über einzelne Funktionen macht, oder ob 
zb ein Timer einen Takt vorgibt, in dem Dinge zu erledigen sind (zb eine 
LED einschalten oder eine Membran in die andere Position zu verfahren), 
ist ein Implementierungsdetail. Wenn man genau Zeiten einzuhalten hat 
(wie zb bei der Erzeugung von Frequenzen) ist ein Timer die bessere 
Wahl. Das ändert aber nichts am Prinzip.

von Falk B. (falk)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Wenn du einen Schweinsbraten im Rohr hast, bleibst du dann vor dem Herd
>stehen und wartest bis der fertig ist?

Und wenn er Moslem is(s)t ? ;-)

Schönes Beispiel, wenn gleich die Erfahrung zeigt, dass besonders 
MENSCHEN, eher schlecht im Multitasking sind.
Die sollten lieber NUR EINE Sache auf einmal machen, sonst steigen die 
Reibungs(Umschalt)verlust mal fix auf 50% und mehr.
Ein Mikrocontroller hat das Problem nahezu nicht.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Falk Brunner schrieb:
> @  Karl heinz Buchegger (kbuchegg) (Moderator)
>
>>Wenn du einen Schweinsbraten im Rohr hast, bleibst du dann vor dem Herd
>>stehen und wartest bis der fertig ist?
>
> Und wenn er Moslem is(s)t ? ;-)
>
> Schönes Beispiel, wenn gleich die Erfahrung zeigt, dass besonders
> MENSCHEN, eher schlecht im Multitasking sind.

Sag das mal den Frauen.
Die rühmen sich doch damit, dass sie von Natur aus Multitasking können.

Ich hab aber eher die Erfahrung gemacht:
Sie können zwar viele Dinge 'gleichzeitig', aber nichts richtig.

von Falk B. (falk)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Ich hab aber eher die Erfahrung gemacht:
>Sie können zwar viele Dinge 'gleichzeitig', aber nichts richtig.

Das hast DU gesagt . . . ;-)

von Don Panso (Gast)


Lesenswert?

@Karl heinz Buchegger

Gutes, anschauliches Beispiel. Ich mach jetzt erst mal Feierabend und 
villeicht schieb ich einen Braten in die Röhre (im kulinarischen Sinne).

Schönen Tag noch!

von Don Panso (Gast)


Angehängte Dateien:

Lesenswert?

Ein wiederholtes hallo allerseits!

Ich habe meine Synapsen spielen lassen und nun folgendes am Programm 
geändert:

-Zum einen ist jetzt eine ADC-Initialisierung vorhanden, die ein 
Dummy-Readout vornimmt

-Sämtliche ADC-Routinen sind jetzt als Funktion vorhanden

-es gibt keine header-Datei für den Alarmton mehr

-ich habe mich an der Festkommaarithmetik versucht...der Speicherbedarf 
ist tatsächlich runtergegangen

-die Abfrage des Tasters geschieht jetzt auch während der Alarmton 
spielt

Die Spannungsmessung und die Anzeige der physikalischen Werte auf dem 
Display aktualisiert sich bei Einhaltung der Grenzwerte alle 500ms. Eine 
schnellere Aktualisierungsdauer ist nicht nötig.
Weichen Werte ab, so wird statt der 500ms-Pause der Alarmton abgespielt. 
Dadurch verlängert sich zwar die Pause, in der keine Messung mehr 
vorgenommen wird, auf die Dauer des Alarmtons (der weit mehr als 500ms 
dauert), aaaaaaber das ist vertretbar. Um ein nahezu nahtloses rödeln 
des Alarmtons zu verhindern habe ich die Variable "uint8_t ton_pause = 
500;" eingebracht. Durch eine Abfrage des Wertes dieser Variable und 
einer 1ms-Pause, falls die Variable den Wert nicht besitzt, verzögert 
sich so das erneute Abspielen des Alarmtons.

Das Kapitel Multitasking habe ich durchgelesen, dennoch weiss ich nicht, 
wie ich das in mein Programm einbauen kann. Was ist nämlich, wenn man 
ganz bestimmte Frequenzen unbedingt einhalten will?
Was ich meine ist: in dem Beispiel im Artikel Multitasking gibt es eine 
LED, die, wenn der Taster nicht gedrückt wird, mit einer Frequenz von 
5Hz blinken soll.
Das "parallele" arbeiten wurde so erreicht, dass man die LED 
einschaltet, dann 1ms wartet und schließlich testet, ob die UART etwas 
zu empfangen hat und ob der Taster gedrückt wird. Hat die UART nix zu 
empfangen, dauert es insgesamt also ca. 1ms, bis "der Prozess" wieder in 
der Funktion mit der LED ist. Dort prüft man nun, ob eine Variable den 
Wert 99 erreicht hat.
Ist dies der Fall, geht die LED aus und es dauert 100*1ms, bis die LED 
wieder an geht (sofern die UART nichts zu empfangen hat). Was ist aber, 
wenn die UART etwas zu empfangen hat? Dieses Empfangen braucht doch 
Zeit...es würde also 100*(1ms + tUart) dauern, bis die LED wieder 
umschaltet, was wiederrum die Frequenz verdirbt, oder verstehe ich da 
was falsch? Bei einem Lautsprecher käme also ein anderer Ton raus...

Nun ja, jedenfalls habe ich das Programm geändert und ich bilde mir ein, 
die meisten eurer Vorschläge mit einbezogen zu haben (bis auf 
Tasten-Entprellung...da bin ich mir nicht sicher, ob das wirklich 
notwendig ist). Ich habe noch keine Möglichkeit, das Ganze zu testen, 
weil ich an das STK500 etc. erst am Montag wieder dran komme. Deswegen 
sind villeicht noch ein paar Bugs drin. Kompillieren lässt es sich aber 
schon mal, das heisst aber nicht, dass die Anwendung klappt..

Also, wenn ihr euch die Arbeit machen wollt, das Programm nochmal 
durchzuschauen, hätte ich nichts dagegen ;-)

Einen schönen Tag noch!

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> Das Kapitel Multitasking habe ich durchgelesen, dennoch weiss ich nicht,
> wie ich das in mein Programm einbauen kann. Was ist nämlich, wenn man
> ganz bestimmte Frequenzen unbedingt einhalten will?

Wenn man Timing einhalten muss, empfiehlt es sich immer auf einen Timer 
zu setzen.
Einen Timer kann man so programmieren, dass er alle X Taktzyklen eine 
Interrupt Service Routine aufruft und dabei den momentanten Ablauf im 
Hauptprogramm (kurz!) unterbricht.

Mit einem Timer samt zugehöriger ISR ist es überhaupt kein Problem einen 
Lautsprecher so anzusteuern, dass das Setzen einer Variablen in der 
Hauptschliefe auf 1 ausreicht, so das der Lautsprecher zu quäken 
anfängt. Setzt man die (globale) Variable wieder zurück auf 0, so hört 
das Gequäke auf.

Denselben Timer kann man oft auch noch mitbenutzen um seinem Programm 
einen Zeittakt zu verpassen, so dass auch noch andere Dinge in 
bestimmten Zeitrastern erfolgen können.

Wenn du Timer links liegen lässt, schenkst du mindestens 70% des 
Potentials deines µC von vorne herein her. Es lohnt sich also sich mit 
dieser Baugruppe im µC zu beschäftigen.

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
    druckwertspannung = ((adcwert_druck*493)/102400);
funktioniert sicher nicht so wie du dir das vorstellst

http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen

von Don Panso (Gast)


Lesenswert?

Hi Karl!

Hmmm, dann lese ich mir nochmal durch wie das mit den Timern und 
Interrupts funktioniert. Wird wieder ne Weile dauern...

Karl heinz Buchegger schrieb:
> Das hier    druckwertspannung = ((adcwert_druck*493)/102400);
> funktioniert sicher nicht so wie du dir das vorstellst

ach das musste man dann so schreiben, oder?

 druckwertspannung = ((adcwert_druck*493.0)/102400.0);

Womit das dann für diesen Teil mit der Festkommaarithmethik erledigt 
wäre... :-)

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@  Don Panso (Gast)

>Ich habe meine Synapsen spielen lassen und nun folgendes am Programm
>geändert:

Es wird deutlich besser, ein paar Knackpunkte fehlen aber noch.

>-ich habe mich an der Festkommaarithmetik versucht...der Speicherbedarf
>ist tatsächlich runtergegangen

Es sind aber noch double Variablen drin. Also immer noch viel unnötiger 
Speicherbedarf.

>-die Abfrage des Tasters geschieht jetzt auch während der Alarmton
>spielt

Schön, aber du hast immer noch große Wartezeiten drin, das geht besser.

>Die Spannungsmessung und die Anzeige der physikalischen Werte auf dem
>Display aktualisiert sich bei Einhaltung der Grenzwerte alle 500ms. Eine
>schnellere Aktualisierungsdauer ist nicht nötig.

Gute Idee, aber noch unzureichend umgesetzt.

>Weichen Werte ab, so wird statt der 500ms-Pause der Alarmton abgespielt.

Wenn du die 500ms Pause jetzt noch sinnvoll verkleinerst, bist du fast 
am Ziel.

>500;" eingebracht. Durch eine Abfrage des Wertes dieser Variable und
>einer 1ms-Pause, falls die Variable den Wert nicht besitzt, verzögert
>sich so das erneute Abspielen des Alarmtons.

>Das Kapitel Multitasking habe ich durchgelesen, dennoch weiss ich nicht,
>wie ich das in mein Programm einbauen kann. Was ist nämlich, wenn man
>ganz bestimmte Frequenzen unbedingt einhalten will?

Dann nimmt man einen Timer und die Output Compare Funktion.

>wenn die UART etwas zu empfangen hat? Dieses Empfangen braucht doch
>Zeit...es würde also 100*(1ms + tUart) dauern, bis die LED wieder
>umschaltet,

Nein, keinesfalls!

> was wiederrum die Frequenz verdirbt, oder verstehe ich da
>was falsch?

Ja. Alle Prozesse sind pro Millisekunde! einmal dran. Das EMPFANGEN 
eines Bytes per UART kostet keine Zeit, das macht der UART allein. Das 
Verarbeiten dauert natürlich etwas Zeit, aber wenn man es richtig macht 
nur sehr wenig, in der Größenordnung von 1ms.

> Bei einem Lautsprecher käme also ein anderer Ton raus...

Ja. Aber in deiner Anwendung kommt es nicht auf 100,0% Tonhöhe an, 99% 
sind auch OK. Nur ausgehen darf der Ton nicht, logisch.

>Nun ja, jedenfalls habe ich das Programm geändert und ich bilde mir ein,
>die meisten eurer Vorschläge mit einbezogen zu haben

Du hast den ersten Schritt getan, das ist gut. Es fehlen aber noch 
einige.

> (bis auf
>Tasten-Entprellung...da bin ich mir nicht sicher, ob das wirklich
>notwendig ist).

Ist hier nicht nötig.

> Ich habe noch keine Möglichkeit, das Ganze zu testen,
>weil ich an das STK500 etc. erst am Montag wieder dran komme. Deswegen
>sind villeicht noch ein paar Bugs drin. Kompillieren lässt es sich aber
>schon mal, das heisst aber nicht, dass die Anwendung klappt..

Richtig.

>Also, wenn ihr euch die Arbeit machen wollt, das Programm nochmal
>durchzuschauen, hätte ich nichts dagegen ;-)

Done.

Ich hab mir mal die Arbeit gemacht, und dein Programm etwas gestrafft. 
So sollte es am Ende aussehen, wenn man weiß was man tut. Ich hoffe du 
erkennst dann, wie man das mit dem Multitasking real umsetzt und vor 
allem auch WARUM!

Das Programm ist kompiliert vollständig, bei dir musst du jedoch die 
drei defines unter //Workaround auskommentieren, da ich deine lcd.h 
nicht hatte.

Njoy.

MFG
Falk

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>Hmmm, dann lese ich mir nochmal durch wie das mit den Timern und
>Interrupts funktioniert. Wird wieder ne Weile dauern...

Das mach mal später. Vorerst brauchst du das nicht, es geht hier auch 
gut ohne.

>Womit das dann für diesen Teil mit der Festkommaarithmethik erledigt
>wäre... :-)
1
 druckwertspannung = (((uint32_t)adcwert_druck*493)/102400);
2
// oder
3
 druckwertspannung = ((adcwert_druck*493)/102400L);


Siehe letzter Abschnitt des Kapitels

http://www.mikrocontroller.net/articles/Festkommaarithmetik#Die_L.C3.B6sung

von Don Panso (Gast)


Lesenswert?

Woa, Falk!

Falk Brunner schrieb:
> Ich hab mir mal die Arbeit gemacht, und dein Programm etwas gestrafft.

Mensch, dass hab ich nicht verlangt. Aber wenn es jetzt schon hier ist, 
dann nutze ich das auch ;-)

Sei herzlichst bedankt!

Es ist natürlich immer besser sich etwas selbst zu erarbeiten, deswegen 
nehme jetzt dein Programm und pflück das Zeile für Zeile auseinander, um 
das auch zu verstehen und was für die Zukunft zu lernen. Das wird mir 
sicherlich später noch weiter helfen.
Nochmals danke, auch an die Anderen, die hier gepostet haben! Danke, 
dass ihr eure Zeit geopfert habt. Ich wusste, es lohnt sich hier im 
Forum mal anzufragen.
So, heute wird das zwar nichts mehr...aber sobald ich Zeit habe setze 
ich mich da dran und am Montag teste ich das mit allen Komponenten. Dann 
lasse ich es euch auch wissen, wie gut das funktioniert (falls es euch 
dann noch interessiert ;-) ).

Danke nochmal an alle!

Beste Grüße,
      Don Panso

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> ach das musste man dann so schreiben, oder?
>
>  druckwertspannung = ((adcwert_druck*493.0)/102400.0);
>
> Womit das dann für diesen Teil mit der Festkommaarithmethik erledigt
> wäre... :-)

Nicht unbedingt.
Wenn du endlich mal anfangen würdest, Formeln zusammenzufassen und 
umzustellen ....

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

OK, hier noch mal mit ein paar kleinen optischen und inhaltlichen 
Korrekturen.

MFG
Falk

von Don Panso (Gast)


Angehängte Dateien:

Lesenswert?

Hallooooooo, da bin ich wieder!

Falk, ich bin dein letztes Programm durchgegangen und habe mir erlaubt, 
einige Änderungen vorzunehmen. Zum einen habe ich die lcd-Funktionen an 
meine lcd.h angepasst (ich packe die mit dem Programm in den Anhang, 
falls du das nochmal durchgucken möchtest; die lcd.h habe ich von 
P.Fleury downgeloaded). Ausserdem habe ich:

-ADC-Einstellungen an meine Gegebenheiten angepasst (externes AREF vom 
STK500 nutzen; Prescaler 16)

-in der Funktion "my_print_LCD()" das Überprüfen auf ein Minus-Zeichen 
neutralisiert, da wir sowieso mit uint arbeiten und die Funktion bei 
einem fehlenden Minus-Zeichen ein überflussiges Leerzeichen raushauen 
würde

-die Parameter für die Funktion "my_print_LCD()" geändert. Der 
Funktionsaufruf sieht jetzt so aus: "my_print_LCD(str_buffer, 7, 9, 
1);". In den Variablen "uint32_t druck" und "uint32_t flow" kann maximal 
eine dreistellige Zahl stehen (wenn 4.93V als Messsignal anliegen). Das 
habe ich gemacht, da der Platz auf dem Display begrenzt ist und die 
Funktion "my_print_LCD()" führende Nullen als ein Leerzeichen auf dem 
Display ausgeben würde.

-der Alarm hört jetzt nicht nur auf Tastendruck auf, sondern auch, wenn 
sich die Werte wieder innerhalb der Grenzen befinden


Ich hoffe du nimmst mir die Änderungen nicht übel und sofern diese nicht 
totaler Blödsinn sind und mir jemand mit einem actionreifen Hechtsprung 
zuvorkommt werde ich diese Version des Programmes morgen in der Praxis 
mal ausprobieren.

So denn Leute, einen schönen Sonntag noch!

P.S.: Reine Verständnisfrage an Falk: die Aktualisierungsdauer von 
AD-Wandlung und Anzeige hast du eingestellt, indem du die Variable 
"uint8_t loop_cnt" unendlich lang hoch zählen lässt. Das Rückstellen auf 
'0' geschieht ja quasi durch einen overflow, da eine 8-bit-Variable ab 
dem Wert 256 zu wenig bits hat. Hat das nicht negative Folgen? In einer 
weit zurückliegenden Vorlesung habe ich mal gehört, dass z.B. Strings 
bei einem overflow nachfolgende Adressen verändern. Bei integern 
passiert nichts?

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>Falk, ich bin dein letztes Programm durchgegangen und habe mir erlaubt,
>einige Änderungen vorzunehmen.

Mach ur, es war ja schliesslich dein Programm ;-)

>-die Parameter für die Funktion "my_print_LCD()" geändert. Der

Naja, die Zahlen waren nur aus der Hüfte geschossen, sowas kann man bein 
Testen leicht und schnell anpassen.

>-der Alarm hört jetzt nicht nur auf Tastendruck auf, sondern auch, wenn
>sich die Werte wieder innerhalb der Grenzen befinden

Ob das so eine gute Idee ist?

>P.S.: Reine Verständnisfrage an Falk: die Aktualisierungsdauer von

>weit zurückliegenden Vorlesung habe ich mal gehört, dass z.B. Strings
>bei einem overflow nachfolgende Adressen verändern.

Das ist aber ein anderer Overflow. Wenn bei einem String das 
Terminierungszeichen 0x0 üerschrieben wird, dann gibt es Ärger, wenn 
andere Routinen darauf zugreifen, weils sie dann entweder einen riesigen 
String ausgeben, weil sie endlos nach dem Ende suchen, oder wenn sie den 
Strin und nachfolgenden Speicher überschreiben.

> Bei integern passiert nichts?

Erstmal nichts. Denn egal ob Üverflow oder nicht, es wird KEIN anderer 
Speicher beeinflußt. Allerding können Arithmetische Rechnungen 
fehlschlagen wegen eines Overflows, vor allem unbemerkt in 
Zwischenergebnissen in Formeln. Hier ist das aber gänzlich unkritisch.

MfG
Falk

von Don Panso (Gast)


Lesenswert?

Moin, moin!

Falk Brunner schrieb:
>>Falk, ich bin dein letztes Programm durchgegangen und habe mir erlaubt,
>>einige Änderungen vorzunehmen.
>
> Mach ur, es war ja schliesslich dein Programm ;-)

Ja, es WAR mein Programm. Auf deine Änderungen wäre ich im Leben nicht 
gekommen. Oder villeicht erst nach Stunden härtester Denkarbeit. Es ist 
gut ein Programm zu sehen, dass von jemandem stammt, der sich auskennt. 
Da lernt man was für die Zukunft und man gewinnt unwahrscheinlich an 
Erfahrung dazu.

Falk Brunner schrieb:
>>-der Alarm hört jetzt nicht nur auf Tastendruck auf, sondern auch, wenn
>>sich die Werte wieder innerhalb der Grenzen befinden
>
> Ob das so eine gute Idee ist?

Warum? Das kannst du nicht wissen, aber es handelt sich um ein Prozess, 
bei dem es keine nachhaltigen Folgen hat, wenn die Werte mal kurz 
abweichen. Nehmen wir an, der Volumenstrom weicht für eine Sekunde ab. 
Dann hört der Nutzer den Alarmton einmal und wird aufmerksam. Ich denke, 
es ist nicht so toll, wenn er dann extra noch den Taster drücken muss, 
weil der Wert mal kurz abgewichen ist, zumal der gleichzeitig noch 
andere Dinge zu tun hat...aber, um ehrlich zu sein: geredet habe ich 
darüber mit dem späteren Nutzer noch nicht. Das sollte ich villeicht mal 
machen, um zu sehen wie seine Präferenzen diesbezüglich sind. Wie sind 
deine Erfahrungen?

Nun denn, ich geh jetzt erst mal Kaffee trinken und dann wird getestet!

Grüße,
    D. Panso

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> darüber mit dem späteren Nutzer noch nicht. Das sollte ich villeicht mal
> machen, um zu sehen wie seine Präferenzen diesbezüglich sind. Wie sind
> deine Erfahrungen?

Das es davon abhängt mit wem du redest.
Wenn du mit dem Chef redest, dann ist der daran interessiert seine 
'Maschinen' zu schonen: Jeder Alarm muss gemeldet werden und solange das 
'Problem' nicht behoben ist, geht die Sirene auch nocht aus.
Wenn du mit dem Maschinenbediener redest: Wenn mir 5 Maschinen 
gleichzeitig die hucke voll hupen, artet das in Stress aus. Am liebsten 
wär mir ein optisches Signal mit der Möglichkeit manuell die Sirene 
zuschalten zu können.

von Falk B. (falk)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Wenn du mit dem Maschinenbediener redest: Wenn mir 5 Maschinen
>gleichzeitig die hucke voll hupen, artet das in Stress aus.

Sicher, aber wenn es was WICHTIGES ist, MUSS es auffallen und nerven. 
Sinnvollerweise solle natürlich was Unwichtiges a) nicht dauernd 
anschlagen und b) nicht so nerven.

@  Don Panso (Gast)

>gekommen. Oder villeicht erst nach Stunden härtester Denkarbeit. Es ist
>gut ein Programm zu sehen, dass von jemandem stammt, der sich auskennt.
>Da lernt man was für die Zukunft und man gewinnt unwahrscheinlich an
>Erfahrung dazu.

Das ist der Sinn der Sache ;-)

>Warum? Das kannst du nicht wissen, aber es handelt sich um ein Prozess,
>bei dem es keine nachhaltigen Folgen hat, wenn die Werte mal kurz
>abweichen. Nehmen wir an, der Volumenstrom weicht für eine Sekunde ab.
>Dann hört der Nutzer den Alarmton einmal und wird aufmerksam. Ich denke,
>es ist nicht so toll, wenn er dann extra noch den Taster drücken muss,
>weil der Wert mal kurz abgewichen ist, zumal der gleichzeitig noch
>andere Dinge zu tun hat...

Dann sollte man noch sowas wie eine Entprellung einbauen. Sprich, das 
Hupen geht erst los, wenn der Alarm für ein paar Sekunden aktiv ist. Das 
Erspart die kurzen Hupsignale, wenns mal nur bisschen an der Grenze 
zappelt.

>Nun denn, ich geh jetzt erst mal Kaffee trinken und dann wird getestet!

Wir sind gespannt.

MFg
Falk

von Karl H. (kbuchegg)


Lesenswert?

Falk Brunner schrieb:

> Dann sollte man noch sowas wie eine Entprellung einbauen. Sprich, das
> Hupen geht erst los, wenn der Alarm für ein paar Sekunden aktiv ist. Das
> Erspart die kurzen Hupsignale, wenns mal nur bisschen an der Grenze
> zappelt.

Und dank vernünftiger Programmstruktur ist das jetzt noch nicht mal eine 
Hexerei :-)

Aber erst mal soll er seinen nicht funktionierenden 'Alarm aus Knopf' in 
Gang bringen.

von Don Panso (Gast)


Lesenswert?

Ok, ich hab mal getestet mit folgendem Ergebnis:

Karl heinz Buchegger schrieb:
> Aber erst mal soll er seinen nicht funktionierenden 'Alarm aus Knopf' in
> Gang bringen.

:-D du hast recht Karl. Das ist mir nicht aufgefallen. Momentan muss man 
den Taster die ganze Zeit gedrückt halten, damit der Alarm einen nicht 
permanent wegpustet. Da habe ich nicht aufgepasst...hätte ich mal früher 
hier reingeschaut. Das wird geändert, aber erst mal Mittagessen ;-)
Bis auf die Sache mit dem Taster funktioniert aber ansonsten alles 
einwandfrei.

Mahlzeit!

      D. Panso

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:
> Ok, ich hab mal getestet mit folgendem Ergebnis:
>
> Karl heinz Buchegger schrieb:
>> Aber erst mal soll er seinen nicht funktionierenden 'Alarm aus Knopf' in
>> Gang bringen.
>
> :-D du hast recht Karl. Das ist mir nicht aufgefallen. Momentan muss man
> den Taster die ganze Zeit gedrückt halten, damit der Alarm einen nicht
> permanent wegpustet. Da habe ich nicht aufgepasst...hätte ich mal früher
> hier reingeschaut. Das wird geändert, aber erst mal Mittagessen ;-)
> Bis auf die Sache mit dem Taster funktioniert aber ansonsten alles
> einwandfrei.

Mach dir 2 Variablen
die eine zeigt an, ob eine Alarmsituation vorliegt
die andere ob der Alarm gemeldet werden soll

Zuviel 'Funktionalität' in eine Variable zu packen führt oft zu solchen 
'Problemen'. Momentan ist deine 'alarm' Variable beides in 
Personalunion.
Wenn du das Melden vom Auftreten des Alarms trennst, kannst du gleich 
die 'alarm' Variable zu einem Zähler umfunktionieren, die mitzählt wie 
oft die Alarmsituation in Folge vorlag und nur dann wenn, Hausnummer, 
500 mal hintereinander eine Alarmsituation war, die Heulboje in Gang 
bringen (die dann vom Benutzer mittels 'alarmAllowed' wieder abgewürgt 
werden kann)

von Blackmore (Gast)


Lesenswert?

Ich habe diesen Thread mit Interesse verfolgt...

Ich komme aus einem Kraftwerk, wo wir diverse PLS-Systeme haben...

Aus Sicherheitstechnischer Sicht wäre es sinnvoll, wenn der Alarm beim 
Überschreiten/Unterschreiten an geht, und erst wieder ausgeht, wenn der 
Benutzer reagiert hat, Knopf gedrückt zum Bleistift. Außerdem wird der 
Alarm angezeigt (Das Ausrufezeichen, was ich irgendwo oben gelesen habe)

Aber wenn nun der Werte um die Alarmgrenze rumschwankt, kommt man aus 
dem Drücken nicht mehr raus. Interessant wäre hierzu eine Hysterese.

Wert darf sich innerhalb 20 und 30 befinden - Wert geht auf 30,2 - Alarm 
geht an, Ausrufezeichen kommt - Knopf wird gedrückt, Hupe geht aus, 
Ausrufezeichen bleibt - jedoch, erst wenn der Wert die 29 erreicht hat, 
geht auch das Fragezeichen weg.
Auch, wenn der der Wert dann von 30,2 auf 29,5 (Fragezeichenist noch da) 
und dann wieder auf 30,1 geht, kommt die hupe wieder.

Was passiert, wenn der erste wert schon im Alarm ist, und der zweite 
Wert sollte nun einen Alarm bringen - kommt der dann auch???

Gruß Blackmore

von Don Panso (Gast)


Angehängte Dateien:

Lesenswert?

So, Leute!

Es ist vollbracht. Nach einer weiteren Änderung funktioniert nun alles 
so wie es soll. Dazu habe ich, wie Karl es vorgeschlagen hat, eine 
zweite Variable "uint8_t alarm_allowed = 1" eingefügt, die auf den 
Taster reagiert und bei Tastendruck zu '0' wird. Die Variable "uint8_t 
alarm = 0" wird zu '1' gesetzt sollten die Messwerte von den Grenzen 
abweichen. Der Alarm wird nur abgespielt, wenn beide Variablen gleich 
'1' sind und rückgesetzt, wenn die Messwerte wieder innerhalb der 
Grenzen sind.
Ich habe es mit dem späteren Nutzer abgesprochen und er meinte diese 
Lösung sei gut. Sollte ein Wert nur kurz abweichen, ertönt auch der 
Alarmton nur kurz, so dass man aufmerksam wird und weiter verfolgt, ob 
sich villeicht mehr tut. Deswegen habe ich deine Idee, Karl, mit dem 
Warten auf längere Abweichung der Werte nicht umgesetzt. Nimm mir das 
bitte nicht übel.

Ansonsten folge ich mal der Netiquette (ja, ich habe es durchgelesen) 
und mache einen Abschlussbericht.

Folgendes Projekt wurde erfolgreich umgesetzt:

-Messung zweier verschiedener Spannungen mit dem ADC eines ATmega16 auf 
einem STK500

-Umrechnung der Werte in die dazugehörigen physikalischen Größen und 
Anzeige dieser auf einem LC-Display

-bei Abweichen der Größen von festgelegten Grenzen ertönt ein Alarmton, 
den man per Taster abstellen kann. Sind die Größen wieder innerhalb der 
Grenzen, wird der Alarm ebenfalls wieder abgestellt.

-Speicherplatzbedarf wurde durch Festkommaarithmetik gesenkt und 
Multitasking wurde angewendet

Ausserdem habe ich noch fix eingefügt (noch nicht getestet):
-Pause zwischen den Alarmtönen, so dass der nicht nahtlos vor sich 
hindudelt

Ein herzliches Dankeschön an alle, die hier Vorschläge gemacht und dazu 
beigetragen haben, das dieses Programm auf ein professionelleres Niveau 
gehoben wird und es nun auch wirklich das tut, was es soll. Speziell 
auch ein Dankeschön an Falk, der sich die Mühe gemacht hat, das Programm 
selbst zu bearbeiten und deutlich zu verbessern. Ich schmücke mich 
ungern mit fremden Lorbeeren, aber wenn mir die schon coolant angeboten 
werden... ;-)
Ich möchte an der Stelle anmerken, dass ich das Programm nicht einfach 
blind übernommen habe, sondern ich bilde mir ein, Falks sehr gute 
Herangehensweise Verstanden zu haben, so dass ich schließlich sogar 
selbst Veränderungen durchführen konnte. Sicherlich werden mir die 
neugewonnenen Erfahrungen in Zukunft nochmal helfen.
Sollten später nochmal bei anderen Dingen Probleme auftreten, werde ich 
mich wieder an die hilfreichen Leute in diesem Forum wenden, aber 
diesmal mit einem durchdachteren Thread-Titel ;-)

So genug mit dem Kitsch :-) Ich stelle die vorerst endgültige Fassung 
des Programms in den Anhang, für den Fall, dass das nochmal jemand 
betrachten möchte. Diesem Thread werde ich noch ein Weilchen folgen. 
Weitere Vorschläge werden also registriert. Kann ja auch sein, dass ich 
doch totalen Mist gebaut habe und mich jemand warnen will.

Ach und Blackmore: herzlichen Dank auch für dein Interesse. Das Programm 
funktioniert jetzt wie gewünscht, deswegen belasse ich das vorerst so. 
Ich werde deine Vorschläge aber, wenn die Zeit es zulässt, in einer 
späteren Version berücksichtigen.

Danke nochmal an alle. Und frohes Schaffen noch!

Beste Grüße,
        Don Panso

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> sich villeicht mehr tut. Deswegen habe ich deine Idee, Karl, mit dem
> Warten auf längere Abweichung der Werte nicht umgesetzt. Nimm mir das
> bitte nicht übel.

Sowieso nicht.
Dein (hoffentlich zahlender) Kunde hat das letzte Wort.

Was du aus dem Projekt mitnehmen solltest, ist der grundsätzliche 
Programmaufbau:

* keine oder wenn, dann nur sehr kurze delays
* immer nur ein kleines Stückchen Arbeit machen lassen
* das dafür reihum wieder und immer wieder
* 1000 mal 1 Millisekunde gewartet ergibt in Summe auch wieder
  1 Sekunde Wartezeit


Das ist der prinzipielle Programmaufbau, mit dem du wahrscheinlich mehr 
als 95% aller µC typischen Problemstellungen bewältigen kannst. Selbst 
dann, wenn es anfänglich so aussieht als ob kein 'Multitasking' 
notwendig ist, lohnt sich dieser Aufbau trotzdem: Er macht nicht viel 
Ärger, ist einfach und für den Fall der Fälle birgt er 
Entwicklungspotential.

Das andere, was du mitnehmen sollst:
Floating Point braucht man eher selten, Formeln ruhig am Papier 
zusammenfassen, ausrechnen und umstellen, dann kann man vieles mit 
Ganzzahlarithmetik erschlagen, auch wenn es am Anfang nicht so aussieht.

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>Es ist vollbracht.

Wenn das mal nicht vorschnell ist . . .

>so wie es soll. Dazu habe ich, wie Karl es vorgeschlagen hat,

Nöö, du hast Kuddelmuddel programmiert. Karl hat was von einem ZÄHLER 
erzählt.
Ausserdem hast du dein Grenzwerte für den Druck verändert. Absicht oder 
Fehler?
Ich dachte negativer Druck ist sowieso nicht praxisrelevant.

>abweichen. Der Alarm wird nur abgespielt, wenn beide Variablen gleich
>'1' sind und rückgesetzt, wenn die Messwerte wieder innerhalb der
>Grenzen sind.

>Ich habe es mit dem späteren Nutzer abgesprochen und er meinte diese
>Lösung sei gut. Sollte ein Wert nur kurz abweichen, ertönt auch der
>Alarmton nur kurz, so dass man aufmerksam wird und weiter verfolgt, ob
>sich villeicht mehr tut.

Schön, aber dazu braucht man keine zweite Variable, diese Funktion war 
vorher auch schon da.

>-bei Abweichen der Größen von festgelegten Grenzen ertönt ein Alarmton,
>den man per Taster abstellen kann. Sind die Größen wieder innerhalb der
>Grenzen, wird der Alarm ebenfalls wieder abgestellt.

Hast du das mal WIRKLICH KOMPLETT getestet?
Denn was bei dir nämlich passiert ist, dass wenn deine Werte ausserhalb 
der zulässigen Grenzen sind, dein Bediener genervt den Knopf drückt, 
dabei den Alarm abschaltet, aber solange die Wert immer noch ausserhalb 
des Sollbereichs sind KEIN Alarm mehr ertönt!! D.h. deine Anlage läuft 
OHNE Alarm dauerhaft ausserhalb der Parameter! Der wird erst wieder 
scharf geschaltet, wenn die Werte im Normalbereich sind. Ich kann mir 
nicht vorstellen, dass das gewünscht oder akzeptabel ist. Und das hat 
auch nichts mit Entprellung zu tun!

>-Speicherplatzbedarf wurde durch Festkommaarithmetik gesenkt

Wieviel? Wieviel braucht dein erstes Programm, wieviel das Neune?

> und Multitasking wurde angewendet

;-)

>Ausserdem habe ich noch fix eingefügt (noch nicht getestet):
>-Pause zwischen den Alarmtönen, so dass der nicht nahtlos vor sich
>hindudelt

Hört auf mit so einem Gemurkse! Man postet keinen Code, der nicht 
getestet ist! Das ist Müll!!!

>So genug mit dem Kitsch :-) Ich stelle die vorerst endgültige Fassung
>des Programms in den Anhang, für den Fall, dass das nochmal jemand
>betrachten möchte.

Done.

MfG
Falk

von Don Panso (Gast)


Lesenswert?

Hallo, kurze Meldung nochmal!

Karl heinz Buchegger schrieb:
> Dein (hoffentlich zahlender) Kunde hat das letzte Wort.

Dafür kriege ich kein Geld. Das ist alles Teil eines Bachelorprojekts 
:-)

Don Panso schrieb:
> Ausserdem habe ich noch fix eingefügt (noch nicht getestet):
> -Pause zwischen den Alarmtönen, so dass der nicht nahtlos vor sich
> hindudelt

Da war ich Dämel zu vorschnell. Das klappt so natürlich nicht! Das wird 
geändert.


Karl heinz Buchegger schrieb:
> Was du aus dem Projekt mitnehmen solltest, ist der grundsätzliche
> Programmaufbau...

Karl heinz Buchegger schrieb:
> Das andere, was du mitnehmen sollst:
> Floating Point braucht man eher selten, Formeln ruhig am Papier
> zusammenfassen...

Ist gebongt ;-)

Später stell ich hier villeicht noch eine perfekte, einwandfrei 
funktionierende Version des Programms rein.

So denn, Adieu!

von Blackmore (Gast)


Lesenswert?

Es gibt kein perfektes Programm, irgendwer hat immer noch irgendwas 
auszusetzen...

Aber ein Listing eines Programmes, was die geforderten Dinge tut wäre 
schon interessant...

von Karl H. (kbuchegg)


Lesenswert?

Wenns dich noch interessiert: Noch eine kleine 'Manöverkritik' zum Thema 
"Do's und Don't do's in C"

* Gib Pins die eine spezielle Bedeutung haben, einen Namen.
  Das erleichtert das Verständnis dessen, was im Code vor sich geht,
  macht so manchen Kommentar überflüssig (und das sind die allerbesten
  Kommentare: die die keiner braucht und die daher rausfliegen)
  und erleichtert auch Hardware-Umbauten.

Beispiel:
1
void fail_sound(void){
2
3
    static uint16_t hilf = 200;
4
    
5
    if (hilf > 100 && hilf <= 200)  {
6
        /* Frequenz ca. 391Hz */
7
        PORTC |= (1 << PC6);
8
        _delay_ms(1.28);
9
        PORTC &= ~(1 << PC6);
10
        _delay_ms(1.28);
11
    } else if (hilf > 0 && hilf <= 100) {
12
        /* Frequenz ca. 132Hz */  
13
        PORTC |= (1 << PC6);
14
        _delay_ms(3.8);
15
        PORTC &= ~(1 << PC6);
16
        _delay_ms(3.8);
17
    } else hilf=500;
18
    hilf--;
19
}

Da mitten drinn ist die Hardwarebeschaltung versteckt. Aus dem 
Zusammenhang wird zwar irgendwann ersichtlich, dass am Pin PC6 wohl ein 
Lautsprecher hängen wird, aber warum nicht Nägel mit Köpfen machen
1
#define SUMMER_PORT     PORTC
2
#define SUMMER_DDR      DDRC
3
#define SUMMER_PIN      PC6
4
5
...
6
7
void fail_sound(void){
8
9
    static uint16_t hilf = 200;
10
    
11
    if (hilf > 100 && hilf <= 200)  {
12
        /* Frequenz ca. 391Hz */
13
        SUMMER_PORT |= (1 << SUMMER_PIN);
14
        _delay_ms(1.28);
15
        SUMMER_PORT &= ~(1 << SUMMER_PIN);
16
        _delay_ms(1.28);
17
    }
18
    else if (hilf > 0 && hilf <= 100) {
19
        /* Frequenz ca. 132Hz */  
20
        SUMMER_PORT |= (1 << SUMMER_PIN);
21
        _delay_ms(3.8);
22
        SUMMER_PORT &= ~(1 << SUMMER_PIN);
23
        _delay_ms(3.8);
24
    }
25
    else
26
      hilf = 500;
27
28
    hilf--;
29
}
30
31
....
32
33
int main()
34
{
35
  ....
36
37
  SUMMER_DDR |= (1<<SUMMER_PIN);  // war: DDRC = 0xFF;
38
39
  ....
40
41
}

jetzt hast du die komplette 'Konfiguration' für den Summer an einer 
Stelle beisammen. Gibt es Änderungen, musst du nur an die #define ran 
und dort die korrekten Werte eintragen. Der Rest des Programms passt 
sich von alleine an.

Port, DDR und Pin für den Taster wären die nächsten Kandidaten.
Grundsätzlich: Wenn du im Code die Bezeichnungen PORTx, PINx etc. 
benutzen musst, dann solltest du darüber nachdenken, dir da spezielle 
#define dafür zu machen.

* keine magischen Konstanten mitten im Code
1
           if( (druck > 3) ||
2
                (druck < 0) ||
3
                (flow > 105) ||
4
                (flow < 95) ) {

Wenn dein Kunde andere Grenzwerte will, musst du den kompletten Code 
durchforsten, wo diese Grenzwerte eingetragen sind. Ganz schlimm wird es 
dann, wenn dieselbe magische Konstante (in derselben Bedeutung) an 
mehreren Stellen vorkommt. Aber selbst dann, wenn nicht, lohnt sich auch 
hier ein #define
1
#define DRUCK_MIN_WERT       0
2
#define DRUCK_MAX_WERT       3
3
#define FLOW_MIN_WERT        95
4
#define FLOW_MAX_WERT        105
5
6
...
7
8
           if( druck < DRUCK_MIN_WERT  || druck > DRUCK_MAX_WERT ||
9
               flow  < FLOW_MIN_WERT   || flow  > FLOW_MAX_WERT )

das gibt dir dann auch einen guten Platz, an dem du dokumentiern kannst, 
wie sich die Werte eigentlich berechnen. Denn ein Flow Wert von 95 sagt 
dir in einem halben Jahr gar nichts mehr.
Ideal ist es, wenn du die Werte aus für den Benutzer interessierenden 
Werten automatisch berechnen lassen kannst. Dann brauchst du bei einer 
Änderung nicht lange nachdenken, sondern setzt den Wert einfach so ein, 
wie ihn dir dein Kunde mitteilt und der Compiler rechnet diesen Wert aus 
dem Benutzersystem in dein internes Zahlensystem um. Dann hast du das 
Beste aus 2 Welten: zum einen dokumentierst du die Umrechnung, zum 
anderen hast du bei einer Änderung wenig Arbeit.

* vermeide Variablennamen wie temp, hilf oder anderen nichtssagenden 
Begriffen. Der Zähler in fail_sound hat eine spezielle Bedeutung. Der 
hat sich schon einen besseren Namen als 'hilf' verdient. Genauso das 
'flag' in my_print_LCD. Flag ist ein Gattungsbegriff für eine bestimmte 
Funktionalität die eine Variable haben kann. In diesem Fall zeigt sie 
an, ob eine 0 eine führende 0 sein kann. Warum nennst du die dann nicht 
einfach 'trailingZero' oder so ähnlich. Dann brauchst du den Kommentar 
nicht mehr (und wie bereits gesagt: Ein Kommentar der wegfällt ist ein 
guter Kommentar)

von Blackmore (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> * keine magischen Konstanten mitten im Code
>            if( (druck > 3) ||
>                 (druck < 0) ||
>                 (flow > 105) ||
>                 (flow < 95) ) {
>
> Wenn dein Kunde andere Grenzwerte will, musst du den kompletten Code
> durchforsten, wo diese Grenzwerte eingetragen sind. Ganz schlimm wird es
> dann, wenn dieselbe magische Konstante (in derselben Bedeutung) an
> mehreren Stellen vorkommt. Aber selbst dann, wenn nicht, lohnt sich auch
> hier ein #define
> #define DRUCK_MIN_WERT       0
> #define DRUCK_MAX_WERT       3
> #define FLOW_MIN_WERT        95
> #define FLOW_MAX_WERT        105

Nicht nur das... später hinaus willst Du vielleicht die Grenzwerte vom 
Kunden selbst via Menü bestimmen lassen, und dann müsstest DU im 
gesamten Programmcode, ähm...

So musst Du nur gucken, steht im EPROM ein selbst bestimmter Wert, also 
überschreibe ich den Standartwert mit dem neuen, und schon gibt es neue 
Grenzwerte...

Gruß Blacky

von Don Panso (Gast)


Lesenswert?

Falk Brunner schrieb:
>>Es ist vollbracht.
>
> Wenn das mal nicht vorschnell ist . . .

Leider wahr :-(

Falk Brunner schrieb:
> Nöö, du hast Kuddelmuddel programmiert. Karl hat was von einem ZÄHLER
> erzählt.

Dazu sage ich:

Don Panso schrieb:
> Deswegen habe ich deine Idee, Karl, mit dem
> Warten auf längere Abweichung der Werte nicht umgesetzt. Nimm mir das
> bitte nicht übel.

Falk Brunner schrieb:
> Ausserdem hast du dein Grenzwerte für den Druck verändert. Absicht oder
> Fehler?

Gut aufgepasst! Das war Absicht. Da ich die Vorrichtung, die den 
Differenzdruck erzeugt noch nicht habe, misst der Differenzdruckmesser 
erstmal nichts. Um negative Werte zu verhindern habe ich noch ein wenig 
an der Formel für die Umrechnung in den physikalischen Wert gedreht. Das 
wird natürlich später wieder geändert.

Falk Brunner schrieb:
> Hast du das mal WIRKLICH KOMPLETT getestet?
> Denn was bei dir nämlich passiert ist, dass wenn deine Werte ausserhalb
> der zulässigen Grenzen sind...

Ja, dass war auch so angedacht wie du es beschreibst.

Falk Brunner schrieb:
> Wieviel? Wieviel braucht dein erstes Programm, wieviel das Neune?

Poste ich später...

Falk Brunner schrieb:
> Hört auf mit so einem Gemurkse! Man postet keinen Code, der nicht
> getestet ist! Das ist Müll!!!

Sorry, Lektion gelernt.

Blackmore schrieb:
> Es gibt kein perfektes Programm...

War auch nicht ganz ernst gemeint...

Blackmore schrieb:
> Aber ein Listing eines Programmes, was die geforderten Dinge tut wäre
> schon interessant...

Kommt auch noch :-)

Karl heinz Buchegger schrieb:
> Noch eine kleine 'Manöverkritik'

Kritik dankbar angenommen.

Uff, so jetzt wieder frisch an die Arbeit...

von Blackmore (Gast)


Lesenswert?

Don Panso schrieb:
> Blackmore schrieb:
>> Es gibt kein perfektes Programm...
>
> War auch nicht ganz ernst gemeint...

War auch nicht böse gemeint...

Aber ich sehe es bei mir... PHP programmiert, alles perfekt, dann kommt 
der Auftraggeber und will noch irgendeinen sh***... und ich armer Tropf 
darf jetzt den gesamten Code durchforsten, nur weil der irgendwo ein 
Punkt grundsätzlich haben waill...

Aber ich muss eigentlich ruhig sein, hab seit einer Woche mein 
Atmel-Zeug hier und nicht mal den µC aufs Steckboard draufgesteckt, 
geschweige denn mal Strom drauf gegeben...

Aber um nochmal auf mein Posting oben zurück zu kommen - Usereingabe von 
Grenzwerten...

Ein kommendes Projekt von mir sieht auch eine Steuerung eines Lüfters 
vor, mit Luftfeuchte und Temperatur. Der Nutzer, der es nutzen will, 
kann mir keine Grenzwerte sagen - muss man im laufenden Betrieb sehen, 
wie sich das ganze verhält... Aber jedesmal 80km fahren, nur um die 
Grenzwerte zu ändern... bäh... also dann lieber 5 Taster mehr 
anstöpseln, und die Einstellung den User machen lassen - da siegt meine 
eigene Faulheit...

Gruß Blacky

von Don Panso (Gast)


Lesenswert?

Hey Blacky!

Blackmore schrieb:
> Usereingabe von Grenzwerten...

Ich verstehe deinen Einwand. Sicherlich wäre das eine ganz nette 
Funktion. Dennoch ist sie in meiner Anwendung nicht notwendig, denn sind 
die Grenzwerte einmal festgelegt, dann bleiben die auch. Was ich mache, 
ist ein sogenanntes SMPS aufzubauen. Mit dem misst man die 
Partikelanzahlkonzentration in der Luft in Abhängigkeit von der Größe 
der Partikel. Für das Messprinzip ist es absolut notwendig, dass die 
Luftvolumenströme, einer mit Hilfe des Volumenstromsensors und der 
andere mit Hilfe des Differenzdrucks über ein Bauteil im Luftstrom 
gemessen, durch das Gerät konstant bleiben. Das habe ich bereits 
erreicht.
Diese Sache hier mit der Überwachung der Werte mit Hilfe des 
Mikrocontrollers ist eigentlich reine Spielerei und für das Messprinzip 
nicht relevant. Wir müssen jetzt nur noch schauen, wie der 
Differenzdruck über einem Bauteil beim erwünschten Volumenstrom ist, 
dann stehen auch dort die Grenzwerte absolut fest. Wenn alles gut geht 
dürfte sich in der Richtung auch nichts ändern.
Klar ist das mit der Usereingabe auch ein nettes Feature, aber hier 
nicht wirklich notwendig...Sorry, aber da siegt meine Faulheit ;-)

Viel Erfolg noch mit deinem Projekt. Das was in diesem Thread vor sich 
geht ist sicherlich hilfreich für dich. Ich beeile mich und korrigiere 
das Programm so gut es von meiner Seite aus geht...

Grüße,
     Don Panso

von Karl H. (kbuchegg)


Lesenswert?

Don Panso schrieb:

> Ich verstehe deinen Einwand. Sicherlich wäre das eine ganz nette
> Funktion. Dennoch ist sie in meiner Anwendung nicht notwendig, denn sind
> die Grenzwerte einmal festgelegt, dann bleiben die auch.

Du musst noch viel lernen, ehe du in die betriebliche Praxis entlassen 
werden darfst :-)

Eines der ehernen Gesetze in der kundenorientierten Programmierung 
lautet:
Betrachte alle dir vom Kunden genannten Konstanten als variabel. Denn 
genau das sind sie auch. :-)

(Das zweitwichtigste lautet:
Sagt dir dein Kunde 'Das brauchen wir nicht, das kommt bei uns nicht 
vor!', dann spitz die Ohren. Genau das sind dann die Fälle, auf denen 
bei der Abnahme herumgeritten wird.

von Blackmore (Gast)


Lesenswert?

Schöner hätt ich es nicht schreiben können...

von Don Panso (Gast)


Lesenswert?

:-D @Karl & Blacky: ihr zwei habt da offensichtlich Erfahrung. Da kann 
ich natürlich nichts gegen sagen. Wie aber bereits erwähnt mache ich 
hier mein Bachelorprojekt...da ist alles halb so wild. Die drücken auch 
mal ein Auge zu und ich bin immer noch der Meinung, dass sich die 
Grenzwerte nicht ändern werden :-P
Ich werde eure Erfahrungsberichte dennoch im Hinterkopf behalten für den 
Fall eines zukünftigen Kundenkontaktes.

Ich habe mich mal daran verucht, dass Programm noch ein wenig mehr zu 
verändern...mit nicht ganz erwünschten Folgen. Ich weiss schon wodran es 
liegt. Es braucht aber Zeit, das Problem zu lösen. Testen kann ich das 
erst morgen und solange werde ich es nicht posten, um mir erneute 
Schelte zu ersparen :'-(

Also dann, schönen Feierabend Jungs!

von Blackmore (Gast)


Lesenswert?

Vielen Dank für das Vertrauen, welches Du in mich setzt...

Jedoch muss ich zu meiner Entschuldigung sagen: Freitag hab ich meinen 
ERSTEN Atmel Mikroprozessor in den Händen gehalten, nicht mal 
programmiert hab ich die Dinger...

Asche auf mein Haupt...

von Don Panso (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Leute!

Ich melde mich hier aus dem verregneten Westen des Landes. Ich habe nun 
eine Version des Programms getestet, die alles tut, was ich will 
(muahahahaha) :-| . Diese Stelle ich nun in den Anhang. Ich denke, diese 
Version werde ich nun endgueltig benutzen. Der "Abschlussbericht" steht 
ja oben.

@ Karl
Um passendere Variablennamen habe ich mir jetzt noch keinen Kopf 
gemacht. Zu einem späteren Zeitpunkt werde ich das noch ändern.

Falk Brunner schrieb:
>>-Speicherplatzbedarf wurde durch Festkommaarithmetik gesenkt
>
> Wieviel? Wieviel braucht dein erstes Programm, wieviel das Neune?

Altes Programm (siehe erster Post):
Größe, der hex-file: 10,4KB

Neuste Version:
Größe, der hex-file: 4,22KB

Schon ein ziemlicher Unterschied...

Blackmore schrieb:
> Vielen Dank für das Vertrauen, welches Du in mich setzt...

Ach, jeder fängt mal klein an. Sieh mich an. Ich kann dir nur den Rat 
geben, das Tutorium auf dieser Seite mal anzuschauen und ein paar 
Beispiele auszuprobieren. Zum Testen vom Mikrocontrollern eignet sich 
das STK500 recht gut. Ich habe damit nur positive Erfahrungen gemacht. 
Einfach in den Sockel stecken und programmieren. Ist mit ca. 75Euronen 
auch noch knapp erschwinglich. Des weiteren helfen die Datenblätter der 
ATmegas auch sehr gut. Dort gibt es dann auch Beispiele, wie man z.B. 
eine Messung mit dem ADC durchführt usw.
Und wenn nichts mehr hilft, dann guck mal in diesem Forum nach, ob nicht 
jemand das selbe Problem hat wie du. Wenn du nichts findest, eröffne 
selbst ein Thread und es wird dir schon jemand helfen (schau dir diesen 
Thread an). Und das wichtigste: nicht ohnmächtig werden ;-) (bin 
zufällig auf ein Kommentar von dir in einem anderen Thread gestossen).

So denn, falls ihr hier noch folgt...wenn es noch Kritik gibt: ich stehe 
zur Verfügung. Danke für eure Geduld!

Bis dann!
        Don Panso

von Blackmore (Gast)


Lesenswert?

Jetzt hab ich mir auch mal Deinen Code durchgelesen, und verstanden habe 
ich nichts -kommt aber eher davon, das ich gar kein C kann...

Aber, jetzt habe ich noch Fragen, an alle, die hier mitlesen:
1
int main(void) {
2
3
    uint32_t druckspannung;
4
    uint32_t druck;
5
    uint32_t flowspannung;
6
    uint32_t flow;
7
  uint8_t alarm_allowed = 1;
8
    uint8_t alarm = 0;
9
    char str_buffer[12];
10
    uint8_t i;
11
    uint8_t loop_cnt=0;
12
13
    /* IOs konfigurieren */
14
  
15
    TASTER_DDR = 0x00;
16
    TASTER_PORT |= (1<<TASTER_PIN);      // Pull Up für Taster
17
    LAUTSPRECHER_DDR = 0xFF;
18
  
19
    /*Display-Initialisierung*/
20
21
    lcd_init(LCD_DISP_ON);
22
    lcd_clrscr();
23
    lcd_command(_BV(LCD_CGRAM));    /* set CG RAM start address 0;*/
24
25
    /* Zeichen #0 mit Delta-Symbol neu definieren */
26
    for(i=0; i<8; i++) {          
27
        lcd_data(pgm_read_byte(&deltaChar[i]));    
28
    }
29
30
    lcd_home();
31
    /* Statischen Text schreiben, 0 ist das selbstdefinerte Delta-Symbol*/  
32
    lcd_putc(0);
33
    lcd_puts("p:      mbar");
34
    lcd_gotoxy(0,1);
35
    lcd_puts("Flow:      l/min");
36
37
    /* ADC konfigurieren */ 
38
    ADC_Init();
39
40
    /* endlose Hauptschleife */

das  uint32_t druckspannung; und Co deklariert mir verschiedene 
Variablen???

Sollte ich wirklich die Hardware nach den Variablen initialisieren?

und das auch noch in der main?

Wie gesagt, ich habe noch keinen Plan von dem Ganzen, deswegen frage 
ich...

Gruß Blacky

von Don Panso (Gast)


Lesenswert?

Hey Blacky...

Öhm, ich weiss nicht, ob das eine spezielle Regel für C ist, aber in 
allen Programmen, die ich bisher gesehen habe, werden die Variablen am 
Anfang der main deklariert...

War das deine Frage, oder habe ich etwas falsch verstanden?

von Ber (Gast)


Lesenswert?

He,
diese Variablen sind lokal definiert und deshalb auch nur in der Main 
verwendbar, werden sie außerhalb des Mains (und etwaigen Funktionen) 
deklariert sind es globale Variablen.
Ich hoffe ich habe deine Frage beantwortet (sofern ich sie richtig 
verstanden hab)

mfg
Ber

von Blackmore (Gast)


Lesenswert?

Wie gesagt, ich kenne C nicht...

ich würde vielleicht am Anfang der main() einen Sprung zu einer 
init-sequenz schreiben, in der init-sequenz werden mir alle inits 
eingebastelt, die ich brauche, evtl. als include???

dadurch bekomme ich diese statischen dinge, die ich nur einmal machen 
muss, und mir im Programm eigentlich nur unübersichtlichkeit bringe 
weg...

Es sei denn, ich mach nen Denkfehler, und sowas DARF man gar nicht 
machen...

von Blackmore (Gast)


Lesenswert?

@ Ber

ok, Erklärung verstanden... jetzt nur noch die Reihenfolge: macht es 
Sinn, zuerst die Software und dann die Hardware zu deklarieren???
also zuerst die Variablen, und dann die Ports und LCD und und udn???

von Falk B. (falk)


Lesenswert?

@  Blackmore (Gast)

>das  uint32_t druckspannung; und Co deklariert mir verschiedene
>Variablen???

Ja.

>Sollte ich wirklich die Hardware nach den Variablen initialisieren?

Warum nicht?

>und das auch noch in der main?

Das ist der Normalfall.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Blackmore schrieb:

> ok, Erklärung verstanden... jetzt nur noch die Reihenfolge: macht es
> Sinn, zuerst die Software und dann die Hardware zu deklarieren???
> also zuerst die Variablen, und dann die Ports und LCD und und udn???

Du schmeisst da ein wenig die Dinge durcheinander.

Das hier
1
int main(void) {
2
3
    uint32_t druckspannung;
4
    uint32_t druck;

sagt lediglich aus:
* Es gibt eine Variable namens 'druckspannung' und die soll ein
  uint32_t sein.

Damit ist an sich noch nichts weiter vereinbart, als das diese Variable 
jetzt 'zur Welt kommt'. Mehr nicht.

Die Hardware selbst wird nicht deklariert. Die ist schon da.
Aber sie wird am Programmanfang konfiguriert und in einen verwendbaren 
Zustand gebracht.

Mit ein wenig Augenzwinkern kann man es so sehen:
Am Anfang wird die Umgebung in der sich das Programm bewegt festgelegt.
Diese Umgebung besteht aus Hardware und Variablen. Die Hardware gibt es 
bereits, die ist von Anbeginn der Zeit vorhanden und fix. Die Variablen 
gibt es noch nicht. Wenn main() zu laufen beginnt, erzeugt es seine 
Variablen die es benötigt und erst damit ist dann seine Umgebung 
vollständig.

Und nachdem dann die Umgebung vollständig ist, gehts los indem die 
Hardware konfiguriert wird.

von Ber (Gast)


Lesenswert?

He,
im Prinzip ist es ganz egal was du zuerst deklarierst, aber die meisten 
Programmierer setzen zuerst ihre Variablen auf und beschreiben erst dann 
die Hardware.
Deklarieren einer Variablen bedeuted im Prinzip nur dass eine Variable 
mit dem vergegebenm Namen und dem Typ "geboren" wird, sonst geschieht 
nichts weiter, somit ist auch die Reihenfolge egal was zuerst gemacht 
wird.

mfg
Ber

von Ber (Gast)


Lesenswert?

Hmmm, ich glaube fast ich tippe zu langsam...
Eigentlich hat Karl Heinz es eh schon auf den Punkt gebracht

mfg
Ber

von Blackmore (Gast)


Lesenswert?

Ok,

danke für die Erklärung...

Ich stand halt auf dem Standpunkt, die Hardware ist schon vorhanden, nur 
noch nicht vollständig eingestellt...

An der Software bastel ich noch, es ändern sich dadurch auch meine 
Variablen...

Deswegen wollte ich die Hardware vollständig einrichten, Ports richtig 
rum definieren, etc,  und dann die Software mit ihren ganzen Variablen, 
etc pp machen...

Da es letztlich egal scheint, wierum man das macht, denke ich, werde ich 
für mich persönlich erst die Hardware aufbauen, in der Software richtig 
einstellen, und dann alles, was rein Software ist machen...

So habe ich, für mich persönlich eine feste Richtung:

Hardware planen, aufbauen, einstellen in Software, Software ienstellen 
(Variablen, etc), Software aufbauen d.h. programmieren...

Mal sehen, ob ich das dann einhalten kann, ich hoffe doch, das ich nicht 
schon bei der zweiten Zeile Code alles anders mache...

Danke Euch... man liest sich bestimmt wieder...

Gruß Blackmore

von Karl H. (kbuchegg)


Lesenswert?

Im Anfange schuf Gott Ports, Timer, ADC und Speicher. Und der Speicher 
ward ohne Form und leer. Und Finsternis lag auf der Fläche der 
SRAM-Bytes.
Und Gott sprach: "Es werde Memory Management"
Und es ward Memory Management!
Nun schwanden vor dem einsetzen Stackpointer, des schwarzen Dunkels 
greuliche Unordnung. Der erste uint32_t enstand!
Und Gott sah den uint32_t und er sah das es gut war.
Und Gott sprach: Es initialisiere sich der Port, als das er als Eingang 
benutzt werden kann. Auch initialisiere sich ein anderer Port um als 
Ausgabefenster für das LCD zu dienen. (An dieser Stelle stutzte Gott ein 
wenig, denn er hatte das LCD noch nicht erfunden, aber das machte 
nichts, es war einfach da.)
Und die Ports initialisierten sich. Und Gott sah, dass es gut war.

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>    * final_program_endgueltig.c (6,1 KB, 8 Downloads) | Codeansicht

Du solltest mit dem Wort "endgültig" etwas sparsamer sein. 
Sinnvollerweise nutzt man Versionsnummern, zwei oder dreistellig.

>Version werde ich nun endgueltig benutzen. Der "Abschlussbericht" steht
>ja oben.

Warum hast du das wieder mit den Pausen zwischen den Alarmtönen 
geändert? Ging wohl nicht auf Anhieb? Was nicht verwunderlich ist, hilf 
ist eine 8-Bit Variable, die kann man nicht auf 500 setzen ;-)


>Altes Programm (siehe erster Post):
>Größe, der hex-file: 10,4KB

>Neuste Version:
>Größe, der hex-file: 4,22KB

Naja, Faktor 2,5, nicht schlecht, oder? Wobei das Hex-File nciht exakt 
die Größe angiebt, die kann man aber sehr leicht im AVR-Studio ablesen, 
in der Ausgabe beim Compilieren. Pi mal Daumen sind das knapp 2kB Flash.

MfG
Falk

von Don Panso (Gast)


Lesenswert?

Falk Brunner schrieb:
>>    * final_program_endgueltig.c (6,1 KB, 8 Downloads) | Codeansicht
>
> Du solltest mit dem Wort "endgültig" etwas sparsamer sein.
> Sinnvollerweise nutzt man Versionsnummern, zwei oder dreistellig.

Jup stimmt. Beim nächsten mal wird das beachtet.

Falk Brunner schrieb:
> Warum hast du das wieder mit den Pausen zwischen den Alarmtönen
> geändert? Ging wohl nicht auf Anhieb? Was nicht verwunderlich ist, hilf
> ist eine 8-Bit Variable, die kann man nicht auf 500 setzen ;-)

Joa, aber wenn du nochmal in der alten Version von 
"final_program_endgueltig.c" genauer hinschaust, erkennst du, das die 
Variable 16-bit hatte ;-)
Das mit dem pausieren des Alarmtons habe ich erst mal aufgegeben. Da 
setze ich mich villeicht später noch mal ran...ich hab zwar auch schon 
eine Idee, wie ich das realisieren kann, aber wie gesagt: später.
Das das mit der Pause einfügen, wie ich es in der Alten Version versucht 
habe, nicht funktioniert, hatte ich ja drei Posts später zugegeben...

Don Panso schrieb:
>> Ausserdem habe ich noch fix eingefügt (noch nicht getestet):
>> -Pause zwischen den Alarmtönen, so dass der nicht nahtlos vor sich
>> hindudelt
>
> Da war ich Dämel zu vorschnell. Das klappt so natürlich nicht! Das wird
> geändert.

(Da hatte ich deinen Post direkt danach noch nicht gelesen). Das was ich 
da fabriziert hatte war wirklicher Murks und funktionierte natürlich gar 
nicht. Das hatte ich erst beim testen gemerkt, was ich, wie du schon 
sagtest, vor dem posten hätte machen sollen.
Gestern Abend sah die Funktion "fail_sound()" noch so aus (hab ich nicht 
gepostet):

void fail_sound(void){

    static uint16_t hilf = 200;

    if (hilf > 100 && hilf <= 200)  {
        /* Frequenz ca. 391Hz */
        LAUTSPRECHER_PORT |= (1 << LAUTSPRECHER_PIN);
        _delay_ms(1.28);
        LAUTSPRECHER_PORT &= ~(1 << LAUTSPRECHER_PIN);
        _delay_ms(1.28);
    } else if (hilf > 0 && hilf <= 100) {
        /* Frequenz ca. 132Hz */
        LAUTSPRECHER_PORT |= (1 << LAUTSPRECHER_PIN);
        _delay_ms(3.8);
        LAUTSPRECHER_PORT &= ~(1 << LAUTSPRECHER_PIN);
        _delay_ms(3.8);
  } else if (hilf > 200 && hilf <= 400) {
      _delay_ms(5);
  }
  else hilf=400;
    hilf--;
}

So in der Art sah das aus (weiss ich um ehrlich zu sein nicht mehr 
genau). Ein Test ergab, das die gewünschte Pause vorhanden war. Das 
Problem:

Der AD-Wandler wird während des Tons angeschmissen. Der braucht länger 
als vorgesehen ist, womit während dem Ton eine Art tocken erzeugt wird. 
Sprich: was ich haben will:
Dödöööö pause Dödöööö pause Dödöööö

Was ich mit dem hier in diesem Post kopierten Code hatte:
Dödötocköö pause Dötockdöööö pause tockDödöööö

Was ich jetzt momentan habe:
DödööööDödööööDödöööö

(Ich hoffe die Lautmalerei ist verständlich :-D)

Mit dem jetzigen Code wird die Messung der Spannungswerte und das 
Anzeigen auf dem Display zwar auch während dem Ton vollzogen, dennoch 
ist das tocken komischerweise nicht so auffällig...
Ich habe das schon eine Idee, wie ich das Problem lösen kann, dennoch 
lasse ich mir noch ein bisschen Zeit...mal gucken ob ich mich heute noch 
dransetze.

Falk Brunner schrieb:
> Naja, Faktor 2,5, nicht schlecht, oder? Wobei das Hex-File nciht exakt
> die Größe angiebt, die kann man aber sehr leicht im AVR-Studio ablesen,
> in der Ausgabe beim Compilieren.

Wirklich ordentlich runter gegangen.
Ich kompiliere mit WinAvr und überspiele das Programm mit 
AVR-Studio...ich halte mal ein Auge offen, wo ich den tatsächlichen 
Speicherbedarf finden kann :-)

Grützi,
   Panso

von Don Panso (Gast)


Lesenswert?

P.S.: wie macht man das, das Code extra mit dem weissen Hintergrund 
belegt wird? Das ist übersichtlicher...

von Blackmore (Gast)


Lesenswert?

mit [ code ] und [ /code ] ohne die Leerzeichen...

von Don Panso (Gast)


Lesenswert?

@Blacky

Ahh, ok thx.
Sehe gerade, das das auch über dem Eingabefenster für Posts unter 
"Formatierung" steht :-D Augen auf im Strassenverkehr.

von Karl H. (kbuchegg)


Lesenswert?

Blackmore schrieb:
> mit [ code ] und [ /code ] ohne die Leerzeichen...

Fast. Die richtigen Codes sind
1
[C]
2
3
hier der C Code
4
5
[/C]

von Blackmore (Gast)


Lesenswert?

1
[code]geht auch, wie ich es hiermit beweise...

von Karl H. (kbuchegg)


Lesenswert?

OK. Gefragt war nur nach dem weißen Hintergrund.
1
[C]
2
int main()
3
{
4
  uint8_t  i;
5
6
  while( 1 ) {
7
    for( i = 0; i < 32; ++i )
8
      PORTB = 0xFF;
9
  }
10
}

versus
1
[code]
2
int main()
3
{
4
  uint8_t  i;
5
6
  while( 1 ) {
7
    for( i = 0; i < 32; ++i )
8
      PORTB = 0xFF;
9
  }
10
}

von Falk B. (falk)


Lesenswert?

@Don Panso (Gast)

>Der AD-Wandler wird während des Tons angeschmissen. Der braucht länger
>als vorgesehen ist, womit während dem Ton eine Art tocken erzeugt wird.

Das hat mit dem AD-Wandler und der Dauer der Messung gar nichts zu tun, 
sondern mit deiner immern noch nicht vorhandenen Entprellung des 
Alarmsignals. Aber du bist ja immer schlauer. Wenn dein Alarm nämlich 
entprellt ist, wird er zwischendurch nicht kurz abgeschaltet. Das 
erzeugt nämlich das Stottern des Alarms.

Und was lernen wir daraus? Eine Entprellung ist nicht nur für 
Tasten, sondern auch für Messergebnisse oft sinnvoll und notwenig.

MfG
Falk

von Blackmore (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
>       OK. Gefragt war nur nach dem weißen Hintergrund.
> [C]
> int main()
> {
>   uint8_t  i;
>
>   while( 1 ) {
>     for( i = 0; i < 32; ++i )
>       PORTB = 0xFF;
>   }
> }
>
> versus
> [code]
> int main()
> {
>   uint8_t  i;
>
>   while( 1 ) {
>     for( i = 0; i < 32; ++i )
>       PORTB = 0xFF;
>   }
> }

Siehst Du...
aber gut zu wissen, das nur mit C Syntaxhighlighting vorhanden ist, DAS 
wusste ich nicht...

Gruß Blackmore

von Don Panso (Gast)


Lesenswert?

Falk Brunner schrieb:
> Aber du bist ja immer schlauer.

Pffff, das habe ich nicht behauptet. Ich habe mir lediglich nur meine 
eigenen Gedanken zu einem bestehenden Problem gemacht. Anders konnte ich 
mir das nämlich nicht erklären...


Meinst du das hier mit Entprellung???

Falk Brunner schrieb:
> Dann sollte man noch sowas wie eine Entprellung einbauen. Sprich, das
> Hupen geht erst los, wenn der Alarm für ein paar Sekunden aktiv ist. Das
> Erspart die kurzen Hupsignale, wenns mal nur bisschen an der Grenze
> zappelt

??? Selbst wenn die Werte permanent ausserhalb der Grenzen sind und 
nicht an der Grenze zappeln, tockt der Alarm...

Meinst du mit "wenn der Alarm für ein paar Sekunden aktiv ist", dass man 
den Ausgang des Mikrocontrollers erst ein paar mal an und aus gehen 
lässt und dann erst den Lautsprecher dazu schaltet oder wie?
Kannst du mir das bitte genauer erklären? Ich verstehe das irgendwie 
nicht :-(

Tatsache ist auch, dass in dem allerallerersten Programm, dass ich 
gepostet habe der Alarm auch ohne Entprellung nicht getockt hat. Bei dem 
Programm war noch nichts mit Multitasking...kann das villeicht auch 
daran liegen?

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@  Don Panso (Gast)

>Meinst du das hier mit Entprellung???

Ja.


>??? Selbst wenn die Werte permanent ausserhalb der Grenzen sind und
>nicht an der Grenze zappeln, tockt der Alarm...

hast du das SICHER geprüft? Einfach mal die IF-Abfrage auskommentieren 
und alarm dauerhaft auf 1 setzen?

>Meinst du mit "wenn der Alarm für ein paar Sekunden aktiv ist", dass man
>den Ausgang des Mikrocontrollers erst ein paar mal an und aus gehen
>lässt und dann erst den Lautsprecher dazu schaltet oder wie?

Nein!

>Kannst du mir das bitte genauer erklären? Ich verstehe das irgendwie
>nicht :-(

So wie es Karl Heinz erklärt hat. Die Variable alarm wird erst auf 1 
gesetzt, nachdem ein Zähler einen bestimmten Wert erreicht hat. Und der 
wird nur dann hochgezählt, wenn die Messwerte abweichen. Siehe unten
1
            /* Messgrößen auf Grenzwerte prüfen und bei Abweichung Alarm aktivieren, mit Entprellung */
2
            if( (druck > DRUCK_MAX_WERT) || (druck < DRUCK_MIN_WERT) ||
3
                (flow > FLOW_MAX_WERT) || (flow < FLOW_MIN_WERT) ) {
4
        
5
                if (alarm_cnt < 255) alarm_cnt++;
6
                if (alarm_cnt > 20 ) alarm = 1;  
7
8
            } else { 
9
                if (alarm_cnt > 0) alarm_cnt--;
10
                if (alarm_cnt < 10 ) alarm = 0;
11
                alarm_allowed = 1;
12
            }

>Tatsache ist auch, dass in dem allerallerersten Programm, dass ich
>gepostet habe der Alarm auch ohne Entprellung nicht getockt hat.
> Bei dem Programm war noch nichts mit Multitasking...kann das villeicht
> auch daran liegen?

Ja, kann es. Das Auslesen des ADC geht eher schnell, aber die Berechnung 
dauert etwas. Wenn auch nur Millisekunden, das hört man. Hmmm. Dann 
müsste man halt wohl oder übel wieder auf das alte System umstellen. 
Oder einen Schritt weiter gehen, und den Timer sowie die Output Compare 
Funktion nutzen, dann sollte es auch stotterfrei laufen.

Ok, es gibt einen Zwischenschritt. Nur Output Compare. Siehe Anhang.

MfG
Falk

P S Und stell deinen Editor auf Soft Tabs, sprich Leerzeichen statt 
echtem Tabulatorzeichen. Sonst wird deine Formatierung immer zerfressen 
angezeigt, weil es keinen einheitlichen Tabulatorabstand gibt.

von Don Panso (Gast)


Lesenswert?

Falk Brunner schrieb:
> hast du das SICHER geprüft? Einfach mal die IF-Abfrage auskommentieren
> und alarm dauerhaft auf 1 setzen?

Da brauch ich nichts in der Software ändern. Ich puste einfach anhaltend 
in den Differenzdruckmesser oder Stelle mittels des Lüfters den 
Volumenstrom ab.


Falk Brunner schrieb:
> Das Auslesen des ADC geht eher schnell, aber die Berechnung
> dauert etwas.

Auch wenn ich nicht "AD-Wandler etc." geschrieben habe, ist es das, was 
ich gemeint habe. Nach der AD-Wandlung kommt zwangsweise Berechnung und 
diverse Display-Routinen. Deswegen auch das anfängliche Zögern mit dem 
Multitasking und dem Beispiel mit der LED...
Aber DAS hört sich jetzt vorschlau an. Ich habe mich zuvor mit diversen 
Fettnäpfchen nicht gerade mit Ruhm bekleckert, also komm ich mal wieder 
ein bisschen runter.

Ein erneutes Dankeschön, für deine Mühen uns eine Überarbeitung des 
Programms zur Verfügung zu Stellen. Ich schaue es mir mal an und 
versuche es zu verstehen ;-)

Falk Brunner schrieb:
> Und stell deinen Editor auf Soft Tabs

Hmm, ich habe mal einen Vortrag über den C-Styleguide gehalten...seitdem 
mache ich das eigentlich mit 4 Leerzeichen etc. Weiss nicht, was da 
schief läuft. Mal gucken, ob sich was ändern lässt.

Schönen Abend noch!
         Don Panso

von Don Panso (Gast)


Lesenswert?

Ok ich seh schon, da muss ich mich noch ein bisschen mit dem Timer des 
ATmega16 auseinandersetzen. Dann wühl ich mal im Datenblatt. Das dauert 
etwas...dann teste ich auch morgen mal...

@Falk:
Hey, warum hast du den Lautsprecherpin geändert? ;-)

von Don Panso (Gast)


Lesenswert?

Don Panso schrieb:
> Hey, warum hast du den Lautsprecherpin geändert?

Achso, dass hat wohl mit dem Timer zu tun?

Wie gesagt, muss mich da erst mal einlesen...

von Don Panso (Gast)


Lesenswert?

Don Panso schrieb:
>> Hey, warum hast du den Lautsprecherpin geändert?
>
> Achso, dass hat wohl mit dem Timer zu tun?

Ok, es hat mit dem Timer zu tun. Das Problem: auf PORTD befinden sich 
bereits alle Anschlüsse für das LCD. Hmmm, ich könnte das in der lcd.h 
ändern und sämtliche Verbindungen umstecken...aber ich habe noch im 
Laufe des Nachmittags eine vermeintliche Lösung erarbeitet, die ich 
morgen erst testen möchte, bevor ich die wieder mit übertriebenem Tamtam 
poste.

Ich melde mich dann morgen noch mal...

von Don Panso (Gast)


Angehängte Dateien:

Lesenswert?

So, Freunde der Nacht

Ich habe das Programm gestern umgeschrieben. Sorry Falk, aber deine 
Version mit dem Timer habe ich noch nicht getestet...wegen der Sache mit 
dem LCD etc...
Jedenfalls habe ich es heute getestet und es funktioniert, sogar mit 
einer kleinen Pause zwischen den Alarmtönen und das tocken ist 
verschwunden...
Schaut mal rein, wenn ihr noch Lust habt :-)

Grüße,
    Don Panso

von Don Panso (Gast)


Lesenswert?

Sorry, hab nicht so viel Zeit, die Änderungen zu Erklären...muss jetzt 
weg bis heute Abend...

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>Sorry, hab nicht so viel Zeit, die Änderungen zu Erklären...muss jetzt
>weg bis heute Abend...

Herzlichen Glühstrumpf, du hast auf möglichst komplizierte Weise die 
alte, erste Version wieder hergestellt. :-0

Wie gesagt, in diesem speziellen Fall kann man das machen, das Programm 
ist ausreichend schnell unf funktionsfähig. Aber mit dieser 
Programmierweise wirst du später nicht weit kommen, deshalb der Schwenk 
auf Multitasking.

MfG
Falk

von Don Panso (Gast)


Lesenswert?

So, wieder zurück in den heimischen Gefilden.

Falk Brunner schrieb:
> Herzlichen Glühstrumpf, du hast auf möglichst komplizierte Weise die
> alte, erste Version wieder hergestellt. :-0

Falk Brunner schrieb:
> Aber mit dieser
> Programmierweise wirst du später nicht weit kommen, deshalb der Schwenk
> auf Multitasking.

Danke für die Glühstrümpfe. Inwiefern fehlt hier denn das Multitasking? 
Der Ton ist in kleine Stücke zerlegt worden, in denen zwischendurch der 
Taster abgefragt wird. Die Pause danach ist ebenfalls in kleine Stücke 
zerlegt worden, zwischen denen der Taster abgefragt wird. Lediglig das 
Wandeln, Umrechnen und Anzeigen auf dem Display geschieht, während der 
Ton gerade nicht spielt, um das tocken zu vermeiden.

Die Pause, die zwischen zwei Wandlungs-Umrechnungs-Anzeige-Zyklen 
besteht, wenn alle Messwerte innerhalb der Grenzen sind (256 * 5ms = 
1,28s) ist in etwa genau so lang, wie der Alarmton und Tonpause zusammen
(100*2*1,28ms + 100*2*3,8ms + 56*5ms = 1,296s), besser angleichbar über 
das delay in der Funktion "fail_sound()".
Die maximale Reaktionszeit, um den Taster zu erkennen ist DEUTLICHST 
reduziert worden gegenüber der von dir angesprochenen alten, ersten 
Version. Die Aktualisierungsdauer von Wandlung etc. ist akzeptabel. 
Inwiefern ist also die alte, erste Version also wieder hergestellt 
worden?

Hmmm, ok, im Prinzip war das eigenltich Sinn dieses Threads.
Das was die alte, erste Version tun sollte ist immer noch vorhanden, 
jedoch ist die Schnelligkeit und Speicherbelastung ist im positiven Sinn 
verändert worden.

Falk Brunner schrieb:
> Wie gesagt, in diesem speziellen Fall kann man das machen
>. . .
>Aber mit dieser Programmierweise wirst du später nicht weit kommen,

Wir werden sehen, was die Zukunft bringt. Tatsache ist, dass 
Multitasking kompliziert ist und sich nicht immer leicht auf gegebene 
Probleme anwenden lässt.
Tatsache ist auch, dass das Programm JETZT ENDLICH tut, was ich will. 
Sogar durch Tests bestätigt.

Also, zum dritten Male melde ich nun Erfolg. Abschlussbericht siehe oben 
etc. etc.

Danke für eure Geduld und Entschuldigung für die ständigen 
Erfolgsmeldungen, die dann doch auf ihre Art und Weise nur heisse Luft 
waren. Drücken wir die Daumen, dass dem diesmal nicht so ist.

Konstruktive Kritik ist immer noch willkommen.

Mit freundlichen Grüßen,
                      Don Panso

von Falk B. (falk)


Lesenswert?

@  Don Panso (Gast)

>Danke für die Glühstrümpfe. Inwiefern fehlt hier denn das Multitasking?

OK, Kommando zurück, es ist doch nicht wie Version 1.0. Da war ich wohl 
etwas vorschnell mit meinem Urteil.

Nein, diese Version ist ziemlich gut, denn der Ton wird mit dem Alarm 
synchronisiert. Das erklärt das Fehlen des Stotterns.

>Die maximale Reaktionszeit, um den Taster zu erkennen ist DEUTLICHST
>reduziert worden gegenüber der von dir angesprochenen alten, ersten
>Version.

Ja. ;-)

>Wir werden sehen, was die Zukunft bringt. Tatsache ist, dass
>Multitasking kompliziert ist

Ein wenig.

> und sich nicht immer leicht auf gegebene
>Probleme anwenden lässt.

Eine Frage der Erfahrung.

>Tatsache ist auch, dass das Programm JETZT ENDLICH tut, was ich will.
>Sogar durch Tests bestätigt.

Schön ;-)

>Also, zum dritten Male melde ich nun Erfolg.

Der Kaiser wäre stolz auf dich . . . ;-)

MfG
Falk

von Don Panso (Gast)


Lesenswert?

Falk Brunner schrieb:
> OK, Kommando zurück,

Uff, Gott sei Dank...

Falk Brunner schrieb:
> denn der Ton wird mit dem Alarm synchronisiert

Das war die Idee dahinter ;-)

Falk Brunner schrieb:
> diese Version ist ziemlich gut

Danke. Es war ein langer weg bis hierhin. Mich graut es immer noch, wenn 
ich den ganzen Thread von oben nach unten runterscrolle...
Letzte Woche war das Programm noch ein häufchen Elend. Schaut euch an, 
wo wir heute stehen. All das war nur wegen eurer Hilfe möglich. Danke an 
euch!

Falk Brunner schrieb:
>> Tatsache ist, dass
>>Multitasking kompliziert ist
>
> Ein wenig.

Schon ein bisschen.

Falk Brunner schrieb:
> Eine Frage der Erfahrung.

Ganz genau. Die kommt dann noch mit möglichen folgenden Projekten.

Falk Brunner schrieb:
>>Also, zum dritten Male melde ich nun Erfolg.
>
> Der Kaiser wäre stolz auf dich . . . ;-)

:-D


So, Leute. Ich behaupte es ist alles gesagt. Das Ergebnis dieses Threads 
kann sich sehen lassen. Es hat sich definitiv gelohnt hier zu posten. 
Danke zum x-ten Mal an alle für die Unterstützung ohne die das Programm 
heute noch vor sich hin lahmen würde.
Sollten aber noch Vorschläge, Anregungen, Kritik etc. bestehen: ich 
schau hier ab und zu noch mal rein. Nachfolgendes wird also, 
wahrscheinlich nicht nur von mir, beachtet.

Machtet jut, schwingt de Hut.
                           Don Panso

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.