Hi... Seit meinem ersten Beitrag hier (hier zu finden: Beitrag "Hilfe bei ATmega 16" ), habe ich schon einiges dazu gelernt bzw. verstehen können. So funktioniert in dem Projekt aus o.g. Link inzwischen die Empfängerauswertung aller Kanäle, Ansteuerung der Servos per Soft Drive(Servo läuft ganz langsam an die Enposition, trotz des es mit einem Kippschalter bedient wird), Akkuspannungs- bzw. Akkuunterspannungserkennung via ADC, Motoransteuerung mittels H-Brücke und PWM und noch paar kleine Spielereien mehr... Natürlich dank der vielen Hilfen hier:) Motoransteuerung mittels Controller bzw. H-Brücke klappt ja. Nun soll besagter Motor einen kolbentauchtank in einem Modelluboot steuern. War eigentlich auch kein Problem das zu realisieren. Schiebepoti Mitte an der Ferbedienung --> Motor stop Schiebepoti nach unten bzw. oben Motor in entsprechende Richtung an (dabei noch unterscheidung wie weit Poti geschoben --> mittels PWM konnte ich dann ja noch die Drehzahl regeln, jeweils auch in beide Richtungen.) Wenn Tank voll bzw. leer --> schalten Endschalter Motor ab und es kann dann nur erstmal in die andere Richtung der Motor angesteuert werden. Soweit so Gut. Nun möchte ich folgendes realisieren: Das Schiebepoti soll nun proportional zum Tauchtank funktionieren, d.h. z.B poti ganz unten --> Tank leer oder Poti mitte --> Tank halb voll usw. Dazu befindet sich im tank ein Hall Sensor und 2 Magneten. Hall Sensor ist hier der auf Seite 5 beschriebene, also der Bipolare. http://www.reichelt.de/?;ACTION=7;LA=6;OPEN=0;INDEX=0;FILENAME=B400%252FTLE4905L_TLE4935L_TLE4945L_TLE4935-2L%2523SIE.pdf;SID=32zWLsRawQASAAAD4s-4Q60c11f46858999dab241819a9820fcfb Bekomme mit meinem Oszi auch das entsprechende Impulsdiagramm am Ausgang des Hall IC. Nun möchte ich die Flankenwechsel mit dem Int0 zählen und auswerten, bzw. mit der aktuellen Position des Potis vergleichen, damit der Tank an diese Position fährt. Dabei komme ich aber auf keinen so rechten Ansatz. Probleme die ich dabei habe sind z.b.: - es liegen ja nur Flanken an die ich zählen kann, wenn der Motor schon läuft (Wollte die Auswertung bzw. den vergleich in der ISR machen, aber wenn kein Interrupt kommt, läft der Motor ja nie... ) - Vergleich aktueller Flankenwert mit Schiebepoti (Wenn ich nur die steigenden Flanken zähle, sind es 205 von Tank leer bis Tank voll) - ist es besser nur die steigenden Flanken zu zählen? oder auch die fallenden?(könnte ja somit halbe Umdrehungen zählen --> Auflösung genauer) Meinem Empfängerimpuls kann ich mit 125 Schritten Genauigkeit erkennen (1-2ms mit 8µs Abtastung) - Wäre das somit auch meine maximale Auflöung für die Ansteuerung des Tanks? Ich erwarte keine fertigen Codeschnipsel, darum poste ich auch selbst keine. Lediglich ein paar Denkanstöße wären schön, wie ich den Einstieg finde. Vielen Dank fürs Erste.
Bei 2 freien Timer könnte Timer A die Zeitbasis für die Abfragen liegern und Timer B über einen I/O-Pin von extern getaktet werden. Damit erzeugt das eigentliche Zählen keine IRQ-Last. In der Timer A ISR wird dann der Zählwert von B abgefragt un rückgesetzt. Wie bei jeder Messung unterliegt auch diese der Unschärferelation, d.h für die Fehler bei der Frequenzmessung bzw. deren zeitliche Verortung gilt
und du musst festlegen, was du wie (un)genau brauchst. Johann
Das ist doch ein relativ einfacher Regelkreis: Du weisst, welchen Zustand der Tank zuletzt hatte und du weisst, wie lang der letzte Impuls vom Sender ist. Wenn sich also die Impulslänge ändet, musst der Motor X Schritte in die entsprechende Richtung drehen. Dann merkst du dir, die neue Impulslänge und vergleichst sie mit der aktuellen. Dass die beiden Werte nicht wirklich vergleichbare Skalierungen haben ist unglücklich, sollte aber durch ein wenige Rechnerei zu beheben sein. Die Auflösung des Tanks zu verdoppeln sehe ich als nicht so sinnvoll an, da dein Sollwert ja sowieso schon eine kleinere Auflösung hat. Sinnvoller wäre aus meiner Sicht ein oder zwei Endlagenschalter.
> Sinnvoller wäre aus meiner Sicht ein oder zwei Endlagenschalter.
Hi...
erstmal danke für die Antworten, bin auch inzwischen selbst schon etwas
weiter gekommen.
Endlagenschalter besitzt der Tank sowieso, man kann ja nie wissen;)
Werde, wenn das Grundprinizp funktioniert, vielleicht versuchen das
Enpfängersignal noch etwas höher aufzulösen. Da es aber etwas Arbeit
ist(zumindest für mich, weil ich dann mit jedem Impuls in einen Überlauf
rein komme und nicht wie jetzt nur in der Kanalpause --> und somit ja
"relativ" einfach die Pause erkennen kann)
@ Johann:
Leider kein andere Timer mehr frei...max wenn ich vieleicht mein Servo
über eine Soft PWM realisiere...damit habe ich mich allerdings noch
nicht beschäftigt und daher keine Ahnung über Aufwand, Sinn bzw.
Realisierung...Trotzdem danke für den Tip:)
Hi... also, läuft erstmal soweit... Sollvariable wird aus aktueller Kanallänge gebildet. Istvariable in der ISR hoch- bzw. runtergezählt. Da der Getriebemotor aber gut gelagert ist, hatte ich um ist == soll leichte Probleme den Motor zum Stillstand zu bringen. Da der Motor noch leicht nachlief nach dem Motor Stop Befehl. Somit gab es wieder einen Interrupt und ist != soll. Habe es erstmal so gelöst, dass der Motor kurz vor ist==soll stopt, quasie ein kleines Intervall für ist==soll. Nun meine Idee: Hab leider keinen Timer mehr an meinem Atmega16 frei. Der Hall IC gibt mir ja einen Rechteckimpuls aus. Könnte ich diesen nicht auf einen normalen Portpin geben und so quasi auch zählen?(Pin auf Masse oder nicht). Es geht dabei maximal um eine Frequenz von 3-4Hz die der Hall IC bei maximaler Drehzahl erzeugt. Damit hätte ich wieder einen timer frei und könnte somit den Tauchtank im Bereich ist==soll mit PWM ansteuern um in diesem Bereich genauer regeln zu können. Meint Ihr, dass wäre möglich bzw. ein brauchbarer Ansatz?
Mapa Mann schrieb: > Nun meine Idee: > > Hab leider keinen Timer mehr an meinem Atmega16 frei. Wofür benutzt du deine Timer zur Zeit? Was sich in vielen Programmen bewährt hat: Einen Timer exklusiv für eine 'Systemuhr' abzustellen. Aufgabe des Timers ist es einfach nur eine Stelle zu haben, an der man regelmässig notwendige Dinge erledigen kann. Die Timer ISR wird so in etwa im Millisekunden-Takt oder auch 10 Millisekunden oder was für deine Applikation praktisch ist, aufgerufen und in dieser ISR werden dann all die Dinge erledigt, die einfach nur periodisch gemacht werden müssen. Die Erkennung eines 3 oder 4Hz Signals würde da zb locker drunterfallen. Die 5 Instruktionen um den Pegelwechsel zu detektieren und einen Zähler rauf/runter zu zählen, hat man in dieser ISR immer noch. So voll kann die ISR gar nicht sein. Auf diese Art kann man sich dann mit einem Hardwaretimer fast beliebig viele 'virtuelle Timer-Zähler' bauen, die dann auch noch auf beliebige Port Pins gelegt werden können.
Karl heinz Buchegger schrieb:
> Wofür benutzt du deine Timer zur Zeit?
Hallo,
Timer 1 zur Ansteuerung meies Soft Drive für Servos
Timer 2 liest meine Empfängersignale ein
Timer 0 bis eben Flankenerkennung vom Hall IC
Dein Ansatz ist sicher super, nur leider fehlt mir gerade der Überblick
das alles abzuschätzen bzw. in der ISR zu trennen bzw. Unterzubringen:(
Wie kann ich mehrere Dinge in der ISR trennen?
Es gibt ja nur "eine" für den entsprechenden timer.
Hmm... wieso ist der Edit Button nach ner weile eigentlich weg? Hab mir mal paar Gedanken dazu gemacht: Könnte ja den Timmer z.B. immer überlaufen lassen um mir so einen Interrupt zu generieren. Dann in der ISR die Dinge erledigen die ich möchte. Pins toggln oder Ports abfragen ob high oder low. Meinst du das so in etwa?
Mapa Mann schrieb: > Dein Ansatz ist sicher super, nur leider fehlt mir gerade der Überblick > das alles abzuschätzen bzw. in der ISR zu trennen bzw. Unterzubringen:( > Wie kann ich mehrere Dinge in der ISR trennen? > Es gibt ja nur "eine" für den entsprechenden timer. Macht ja nichts. Du kannst ja in einer ISR einfach mehrere Funktionsblöcke hintereinander ausführen lassen.
1 | ISR( ... ) |
2 | {
|
3 | kümmere dich um dieses |
4 | |
5 | kümmere dich um jenes |
6 | |
7 | ach ja, und jetzt shcaust du auch noch am Pin nach, ob sich |
8 | der Zustand geändert hat. Wenn ja -> Zähler erhöhen |
9 | }
|
Das große Problem ist eher, die unterschiedlichen Zeitanforderungen der einzelnen, in der ISR zu erledigenden Dinge, unter einen gemeinsamen Hut zu bringen. Wenn 'kümmere dich um dieses' alle 5ms passieren soll, 'kümmere dich um jenes' aber alle 3ms, und der 'Pin-Zähler' alle 2ms, dann musst du die ISR so einstellen, dass sie zb alle 1ms aufgerufen wird. Bei jedem 5.ten Aufruf wird 'kümmere dich um dieses' gemacht, bei jedem 3ten 'kümmere dich um jenes' und bei jedem 2ten Aufruf wird der Pin untersucht.
1 | uint8_t diesesCnt; |
2 | uint8_t jenesCnt; |
3 | uint8_t PinCnt; |
4 | |
5 | ISR( ... ) |
6 | {
|
7 | diesesCnt++; |
8 | if( diesesCnt == 5 ) { |
9 | kümmere dich um dieses |
10 | diesesCnt = 0; |
11 | }
|
12 | |
13 | jenesCnt++; |
14 | if( jenesCnt == 3 ) { |
15 | kümmere dich um jenes |
16 | diesesCnt = 0; |
17 | }
|
18 | |
19 | pinCnt++; |
20 | if( pinCnt == 2 ) { |
21 | ach ja, und jetzt shcaust du auch noch am Pin nach, ob sich |
22 | der Zustand geändert hat. Wenn ja -> Zähler erhöhen |
23 | |
24 | pinCnt = 0; |
25 | }
|
26 | }
|
Jetzt hast du in einer ISR 3 unterschiedliche Aktionen untergebracht, die mit unterschiedlichen Timings regelmässig abgearbeitet werden. Du hast aus dem einen vorhandenen Hardwaretimer, der alle 1ms eine Funktion aufruft, 3 virtuelle Timer gemacht, die alle 5, 3 und 2ms ihre Aktion ausführen.
Hallo, also, hab nun versucht das Prinzip des "Virtuellen Timers" umzusetzten und es klappt wunderbar. Danke nochmal an Karl Heinz. Das Problem, das der Motor nicht still stehen will um den Wert ist==soll habe ich aber nach wie vor. Setze ich mit hingegen einen festen soll Wert (zu Testzwecken) steht der Motor sofort bei ist==soll. Generiere ich mir jedoch den Sollwert wieder aus meinem RC Signal geht das "Gewackel" wieder los. Dabei hab ich nun schon wieder die Auflösung des Signals grober gewählt(Abtastung mit 16µs), damit eventuelle kleine Tolleranzen nicht so ins Gewicht fallen. Hat aber nix gebacht, der Motor will einfach nicht still stehen. Hier die ISR (Aufruf im ms takt): ISR(TIMER0_COMP_vect) { if (!(PIND & (1<<PIND2))) { ihall_cnt=0; // Pegel auf Low PORTC &= ~( 1 << PC4 ); //Led an PC4 aus } else { ihall_cnt=1; // Pegel auf high PORTC |= (1 << PC4); // Led an PC4 an } if (ihall_cnt!=ihall_cnt_tmp) //fals Pegel geändert { if(ihall<isoll) { ihall++; } else { ihall--; } } ihall_cnt_tmp=ihall_cnt; //Speichern des aktuellen Pegels in tmp variable isoll = ( iSumSig[4]-67)*4); //berechnung aktueller soll wert } Ist die Berechnung von isoll aus dem Arraywert so korrekt oder muss ich dabei noch etwas anderes beachten?
Mapa Mann schrieb: > Setze ich mit hingegen einen festen soll Wert (zu Testzwecken) steht der > Motor sofort bei ist==soll. Generiere ich mir jedoch den Sollwert wieder > aus meinem RC Signal geht das "Gewackel" wieder los. Hast du schon nachgesehen, ob nicht das 'ist' das Problem darstellt. Sprich: Ob dieses wackelt. > if(ihall<isoll) > { > ihall++; > } > else > { > ihall--; > } > } So wirst du ihall aber nie auf einen einzigen Wert einpendeln lassen können. Wenn ihall kleiner isoll ist, erhöhst du ihall. Irgendwann wird es größer als isoll. Woraufhin du es gleich wieder um 1 verminderst. -> ihall pendelt immer um -1 um isoll herum. In einem ISR Aufruf ist es noch isoll, im nächsten wieder um 1 weniger um dann für den nächsten wieder auf isoll zu gehen etc. Selbst wenn sich isoll in der Zwischenzeit gar nicht geändert hat. > isoll = ( iSumSig[4]-67)*4); //berechnung aktueller soll wert > > } > > Ist die Berechnung von isoll aus dem Arraywert so korrekt oder muss ich > dabei noch etwas anderes beachten? Das weiß ich nicht. Ich weiß ja nicht, was in sSumSig[4] so für Werte drinnen stehen.
Hi, der Vergleich ob größer oder kleiner wird doch nur aufgerufen wenn if (ihall_cnt!=ihall_cnt_tmp) ist, ansonsten zählt da nix hoch oder runter. Zumal ja alles klappt, wenn ich isoll z.B. auf 100 setze.Dann steht der Motor sofort. Ansteuerung des Motors erfolgt ja in einer Extra Funktion, daher vielleicht nicht so ganz klar hier. Aber werd mir das trotzdem nochmal genauer anschauen, danke für den Tip. In iSumSig[4] steht die jeweilige Kanallänge des Rc Signals drin. 1100ms bis 1900ms abgetastet mit 16µs, also Werte zwischen 69 und 119. (denke ich zumindest)
Hallo, ich habe mir das nicht alles angesehen, aber kann if (ihall_cnt!=ihall_cnt_tmp) überhaupt gleich werden (Rundungsfehler in den Berechnungen, Typkonvertierungen usw.)? Gruß aus Berlin Michael
Michael U. schrieb: > Hallo, > > ich habe mir das nicht alles angesehen, aber kann > if (ihall_cnt!=ihall_cnt_tmp) > > überhaupt gleich werden (Rundungsfehler in den Berechnungen, > Typkonvertierungen usw.)? > > Gruß aus Berlin > Michael Hi, ihall_cnt kann nur 0 oder 1 sein und soll nur feststellen ob sich seit dem letzen aufruf der ISR der Pegel vom Hall Sensor geändert hat.
Mapa Mann schrieb: > Hi, > > der Vergleich ob größer oder kleiner wird doch nur aufgerufen wenn > > if (ihall_cnt!=ihall_cnt_tmp) ist, ansonsten zählt da nix hoch oder > runter. Gut. Dann wird ihall eben nicht bei jedem ISR Aufruf nachgeführt, sondern bei jedem Pegelwechsel am Hallsensor. Einpegeln auf isoll wird er sich trotzdem nicht. > der Vergleich ob größer oder kleiner wird doch nur aufgerufen wenn "nicht kleiner" ist nicht automatisch "größer". "gleich" qualifiziert ebenfalls als "nicht kleiner". Wo liegt das Problem in ...
1 | if( ihall < isoll ) |
2 | ihall++; |
3 | else if( ihall > isoll ) |
4 | ihall--; |
... Das ist doch kein Hexenwerk und egal was passiert hast du die Garantie dass ihall auf isoll nachgeführt wird und dort auch bleibt und nicht rumzappelt. Auch wenn dieses Detail bei dir jetzt anscheinend keine große Rolle spielt, sauberer ist es trotzdem. > 1100ms bis 1900ms abgetastet mit 16µs, also Werte zwischen 69 und 119. > (denke ich zumindest) Das würde ich erst mal kontrollieren.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.