Hallo,
Wir haben ein mikrocontroller der mit einer waage verbunden ist. Auf die
Waage stellen wir ein becher und mittels einer pumpe wird Wasser in den
becher gepumpt und wir sollen dann ausgeben wie viel Wasser in den
becher gepumpt wird.
Das funktioniert nun soweit alles, allerdings sollen wir nun noch ne
Abbruchbedingung reinpflanzen die besagt:
Wenn sich das gewicht auf der waage über ~1 Sekunde nicht verändert,
dann soll der pumpvorgang abgebrochen werden.
Wir sollen also zu einem zeitpunkt das Gewicht messen und dann ~1
Sekunde später nochmal messen und falls die differenz zwischen den zwei
Gewichten ungefähr 0 ist (dh. das gewicht hat sich nicht verändert),
dann sollen wir abbrechen. Der Controller arbeitet mit 25Mhz.
Hier die ursprüngliche version:
1
do{
2
gewicht=durchschnittsWiegen(becherGewicht);// aktuelles gewicht wird gemessen
3
piobaseA->PIO_PDR=(1<<PIOTIOA3);//EINSCHALTEN DER PUMPE
4
printNumber(gewicht);// aktuelles gewicht auf serielle schnittstelle ausgeben
Peter W. schrieb:> Der Controller arbeitet mit 25Mhz.
das heißt aber nicht das er durch jede Schleife 25Mio Mal pro Sekunde
kommt,
du brauchst eine richtige Zeitbasis!
Hmm ja 25Mio mal ist wohl zu viel. Rein theoretisch würden aber doch
25Mio Taktzyklen benötigt werden und eine 1 Sekunde wäre um? Klar ich
hab dann noch die ganzen anderen Befehle die noch Taktzyklen verbraten.
Aber selbst mit 10Mio funktionierts nicht.
Was ist daran
1
gewichtdelta>-2&&gewichtdelta<2
falsch? Gibt halt auch unter umständen messungenauigkeiten, deswegen
muss ich da ne gewisse toleranz einbauen. Ich will damit ausdrücken,
wenn gewichtDelta zwischen -2 und 2 liegt, soll die bedingung greifen.
Hmm ja kann vllt an der Klammersetzung gelegen haben. Aber irgendwie
muss das ja so funktionieren, sonst hätten die uns das nicht so erklärt.
Also von Zeitbasis/Systick hab ich noch nie gehört.
Meint ihr des wird mit der richtigen klammersetzung so ungefähr
funktionieren? Kanns jetzt nicht testen, weil ich den mikrocontroller
hier nicht hab (nur im labor).
Hab nochmal ne andere version:
1
do{
2
zaehler+=1;
3
if(zaehler==2000000&&zustand==0){// nach ~1Sek wird ein gewicht gespeichert
4
zustand=1;
5
gewichtAlt=durchschnittsWiegen(becherGewicht);
6
}elseif(zaehler==4000000&&zustand==1){// nochmal ~1Sek später wird das gewicht von vor
7
gewichtdelta=gewicht-gewichtAlt;// 1sek mit dem jetzigen verglichen
8
if((gewichtdelta>-2)&&(gewichtdelta<2)){
9
puts("Gewicht verändert sich nicht! Abbruch!\n");// falls sich die gewichte kaum unterscheiden dann abbruch
10
return;
11
}
12
zaehler=0;
13
zustand=0;
14
}
15
gewicht=durchschnittsWiegen(becherGewicht);// aktuelles gewicht wird gemessen
16
piobaseA->PIO_PDR=(1<<PIOTIOA3);//EINSCHALTEN DER PUMPE
17
printNumber(gewicht);// aktuelles gewicht auf serielle schnittstelle ausgeben
18
puts("\n");// leerzeichen nach gewichtsausgabe
19
}while(gewicht<menge&&durchschnittsWiegen(0)>TOLERANZ);// Solange pumpen wie das gewicht kleiner
20
// als die gewünschte menge ist
21
piobaseA->PIO_PER=(1<<PIOTIOA3);//AUSSCHALTEN DER PUMPE
Peter W. schrieb:> Hab nochmal ne andere version:
Finde ich noch etwas konfus. Falls ich die Aufgabe richtig verstanden
habe würde ich es wohl so versuchen:
Wobei ein Limit von 2.000.000 für den Zähler immer noch viel zu hoch
angesetzt sein dürfte. Je nachdem wie die aufgerufenen Funktionen
aussehen könnte ein Schleifendurchlauf auch leicht 1000 Taktzyklen
benötigen.
Am besten wäre es halt wirklich einen Timer oder Systemfunktionen für
delays o.ä. zu verwenden
Besucher schrieb:> Finde ich noch etwas konfus. Falls ich die Aufgabe richtig verstanden> habe würde ich es wohl so versuchen:
Hmm ok ja kann ich mal probieren. das wäre die 2. variante die uns
erklärt wurde. Mit Timer meinste wahrscheinlich, das man nen timer mit x
Hz einrichtet, der dann halt entsprechend alle 1/x sek überprüft ob sich
am gewicht was verändert hat mit nem Interrupt oder sowas in der
richtung?
> zaehler+=1;> if(zaehler == 25000000) {
das ist ein delay. Nicht schön, geht aber prinzipiell. Du müsstest es
zunächst mal kalibrieren. Z. B. mit einer led.
Ich würde es so machen:
Überlege dir zuerst, wie oft du wiegen und Anzeigen willst:
z.B. 1 mal pro Sekunde.
Dann richtest du einen Timer mit 1s ein.
Der bildet dann sozusagen den "Takt" für dein System.
Und immer, wenn der Timer einen Interrupt auslöst, wiegst du, zeigst das
Ergebnis an, "sicherst" den Wert und vergleichst den aktuellen Wert mit
dem Wert aus der letzten Messung.
Sind die Werte nahezu gleich, dann inkrementierst du einen Zähler.
Sind die Werte unterschiedlich, dann setzt du diesen Zähler auf '0'.
Errreicht der Zähler den Wert 5, dann schaltest du die Pumpe ab.
Hallo,
ich stelle mir gerade die Frage, wozu man das überhaupt braucht. Soll
damit geprüft werden, ob der Vorratsbehälter leer ist? Denn solange
Medium gefördert wird, ändert sich auch die Masse auf dem Wägeteller.
Eine Änderung tritt erst dann nicht mehr ein, wenn der Behälter
überläuft und das Wasser dann auch vom Wägeteller läuft. ;-)
Wenn es darum geht, ob noch Medium gefördert wird, würde ich die
Stromaufnahme der Pumpe messen. Sinnvollerweise würde ich den
Pumpvorgang aber auch abbrechen, wenn die Masse auf der Waage einen
bestimmten Schwellwert überschreitet, damit der Becher eben nicht
überläuft. Aufgrund des Leergewichtes des Bechers könnte man sogar auf
sein Volumen schließen, wenn die Becher immer vom gleichen Typ sind (zB
Bechergläser)
Viele Grüße,
Marcel
Ja nen timerinterrupt klingt schön, haben wir aber so noch nie gemacht
und ohne vorlage krieg ich das sicherlich auch nicht hin.
Besucher schrieb:> zaehler = 0;> gewichtAlt = 0;> pumpeEinschalten();>> do {> gewichtNeu = durchschnittsWiegen(becherGewicht);>> if( gewichtAlt != gewichtNeu ) {> gewichtAlt = gewichtNeu;> zaehler = 0;> }>> printNumber(gewichtNeu);> puts("\n");>> zaehler++;> } while( (gewichtNeu < gewichtSoll) && (zaehler < limit) );>> pumpeAusschalten();
Und bei dem weg fehlt ja noch irgendwie wie man auf gewichtAlt kommt. Da
müsste ich dann ja noch sowas reinmachen nehm ich an.
zaehler2+=1;
if(zaehler2 == 2000000) {
gewichtAlt = durchschnittsWiegen(becherGewicht);
zaehler2 = 0;
}
Und zwecks kalibrierung von dem delay:
Ich weiß das wenn ich nen Zähler immer wieder auf 500000 hochzähle, die
LEDs am mikrocontroller mit ungefähr 0,5 Hz blinken. Aber wie viel
taktzyklen nen gesamter schleifendurchlauf braucht ist wohl schwierig
rauszukriegen. Aber soll ja auch nur "so ungefähr" funktionieren.
Peter W. schrieb:> Ja nen timerinterrupt klingt schön, haben wir aber so noch nie gemacht> und ohne vorlage krieg ich das sicherlich auch nicht hin.
Dann kannst du es prinzipiell trotzdem so machen, wie ich beschrieben
habe.
Du "wartest" in deinem Programm einfach immer ca 1s und den Rest kannst
du dann so machen, wie beschrieben.
grundschüler schrieb:>> zaehler+=1;>> if(zaehler == 25000000) {
Besser:
while (zaehler < 25000000) {
erlaubt auch increments ungleich 1.
>> das ist ein delay. Nicht schön, geht aber prinzipiell. Du müsstest es> zunächst mal kalibrieren. Z. B. mit einer led.
Nicht schön ist genau richtig erkannt.
Informiere dich, welche Timerbausteine dein Controller hat,
nutze einen davon für eine gescheite Zeitangabe,
lese das Gewicht alle 333 ms, dann liegen mindestens zwei Werte vor,
und dann werte diese aus.
Gruss
Robert
Peter W. schrieb:> Ich weiß das wenn ich nen Zähler immer wieder auf 500000 hochzähle, die> LEDs am mikrocontroller mit ungefähr 0,5 Hz blinken.
also 1sec ~=250000, reicht doch an Genauigkeit
> gewichtAlt = durchschnittsWiegen(becherGewicht);
besser
gewichtAlt = gewicht;
dann wird jeweils das Ergebnis der letzten Messung als 'gewichtAlt'
gespeichert. Danach kommt sofort die neue Messung mit der das delta
gebildet werden kann.
noch besser, gewichtAlt direkt nach der Messung für den nächsten
Durchlauf speichern.
Peter W. schrieb:> Und bei dem weg fehlt ja noch irgendwie wie man auf gewichtAlt kommt.
Nein, eigentlich fehlt das nicht. GewichtAlt wird mit 0 initialisiert
(was man sich zwar auch sparen könnte, ist aber "sauberer" wenn man es
dazuschreibt). Innerhalb der Schleife wird dann als erstes gewichtNeu
ermittelt. Falls gewichtNeu einen anderen Wert als gewichtAlt hat dann
wird gewichtAlt entsprechend an gewichtNeu angepasst. Somit haben
gewichtAlt und gewichtNeu anschließend den gleichen Wert.
Falls die if-Bedingung andererseits nicht zutrifft bedeutet das ja das
gewichtNeu und gewichtAlt sowieso schon den gleichen Wert haben. In dem
Fall ist keine Anpassung von gewichtAlt nötig.
Wichtig ist hier eigentlich nur das der Zähler wieder auf 0 gesetzt wird
wenn sich gewichtNeu und gewichtAlt unterscheiden.
> Aber wie viel taktzyklen nen gesamter schleifendurchlauf braucht> ist wohl schwierig rauszukriegen.
Stimmt. Da gibt's zwar auch tools für (Profiler), aber wenn "ungefähr"
reicht dann ist es halt am einfachsten einige Werte durchzuprobieren.
Wenn es sich bei dem gegebenen Problem um eine Hausaufgabe handelt dann
wird dieser Weg, beim derzeitigen Stand des Unterrichts, sicher auch
vollkommen okay sein. Falls es sich jedoch um eine Bastelei von Dir
privat handelt dann würde ich mir noch zwei Wochen Zeit nehmen um mich
mit den Timern auseinanderzusetzen. Einfach um nachher ein gutes Gerät
zu haben (und natürlich ist die Motivation zum Lernen erfahrungsgemäß
weit höher wenn man den Stoff auch gleich selber praktisch nutzen kann).
Hans schrieb:> --> (gewichtdelta > -2) && (gewichtdelta < 2)
... und welches Problem sollen die Klammern lösen.
Gibt es irgendeinen Grund anzunehmen, dass die Priorität der Operatoren
in dem Programm anders ist, als im C Standard festgelegt?