Forum: Mikrocontroller und Digitale Elektronik Dimmfunktion Touchpanel mittels ADC Wandler


von Alex P. (alex2203)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

ich hoffe ich mach mich nun nicht zum DAU und genau so eine Frage 
existiert bereits.

Ich habe folgendes Problem:

Ich möchte einen Dimmer, welcher unter den Fliesen in der Dusche 
angebracht ist, bauen. Das Dimmen soll mittels kapazitivem Tastsensor 
und PWM Modulation ermöglicht werden.

Ich möchte es folgendermaßen realisieren: Lampe AUS -> kurzer 
Tastendruck (Lampe an) ->kurzer Tastendruck (Lampe aus) bzw. langer 
Tastendruck (Lampe dimmt auf OCR Wert 255 und dann wieder auf OCR Wert 
0)-> kurzer Tastendruck (Lampe aus) usw. Die Switcherei Lampe aus etc. 
realisiere ich mittels State Machine. Achja, ich nutze einen ATTiny25, 
habe also nur endlich Ports und Timer zur Verfügung.

Mittels Schalter bekomme ich das Ganze über eine hier gefundene Funktion 
hin, indem er erkennt, dass nach so und so vielen ms der Taster noch 
immer auf GND gezogen ist (gedrückt ist). Nur wie mache ich dies mit 
einem ADC Wert? Gedrückt habe ich den Wert 16 im Testaufbau, ungedrückt 
5.
Steh da echt aufm Schlauch, auch wenn ich denke, dass es gar nicht so 
schwer sein dürfte. Es fehlt mir lediglich eine Idee (vllt. in Form 
eines Stück C Codes).

Wäre echt Klasse wenn mir jemand helfen könnte.

Hier der Codeausschnitt auf ATMega16 angepasst. Das Original ist (wie so 
oft) von Peter Dannegger. Danke Peter auf diesem Wege.

von Karl H. (kbuchegg)


Lesenswert?

Alexander Pl schrieb:

> Mittels Schalter bekomme ich das Ganze über eine hier gefundene Funktion
> hin, indem er erkennt, dass nach so und so vielen ms der Taster noch
> immer auf GND gezogen ist (gedrückt ist). Nur wie mache ich dies mit
> einem ADC Wert? Gedrückt habe ich den Wert 16 im Testaufbau, ungedrückt
> 5.
> Steh da echt aufm Schlauch, auch wenn ich denke, dass es gar nicht so
> schwer sein dürfte. Es fehlt mir lediglich eine Idee (vllt. in Form
> eines Stück C Codes).

Die Idee ist eigentlich so gut wie immer dieselbe.

Wenn in einer Applikation das Wort 'Zeit' fällt, dann ist fast immer ein 
Timer beteiligt.
Zb. ein Timer, der in regelmässigen Zeitabständen (vielleicht 1 ms?) 
eine ISR aufruft. In der ISR wird mitgezählt, wie oft der ADC Wert 
hintereinander grösser als sagen wir mal 10 ist (da 16 deutlich über 
10 liegt, während 5 deutlich unter 10 liegt). Ist diese Anzahl (und 
damit die Zeit in der die Taste gedrückt war) über deinem Grenzwert 
(sagen wir mal 1000), dann war die Taste länger als 1000ms gedrückt, 
sonst eben kürzer. Das eine ist ein langer Tastendruck, das andere ein 
kurzer. Hast du allerdings zb nur 5 mal hintereinander einen ADC Wert 
größer 10, dann war das wohl ein Fehler, denn kein Mensch kann einen 
Sensorfläche für 5 ms betätigen.


> Wäre echt Klasse wenn mir jemand helfen könnte.

Reicht dir das als Idee?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> In der ISR wird mitgezählt, wie oft der ADC Wert
> hintereinander grösser als sagen wir mal 10 ist (da 16 deutlich über
> 10 liegt, während 5 deutlich unter 10 liegt).

Das bedeutet natürlich nicht, dass in der ISR jetzt ständig (in einer 
Schleife) der ADC ausgewertet wird.
1 Aufruf der Timer-ISR == 1 mal auswerten des ADC

Wie meistens entsteht die 'Zeitspanne' dadurch, dass man weiss in 
welchen zeitlichen Abständen die ISR aufgerufen wird und dann zählt man 
einfach die Anzahl der Aufrufe der ISR. In deinem Fall beinhaltet diese 
Zählung dann eben noch eine Nebenbedingung, die durch den ADC ins Spiel 
kommt.

: Bearbeitet durch User
von Alex P. (alex2203)


Lesenswert?

Hallo Karl Heinz,

vielen Dank für deine schnelle Antwort. Das klingt sehr logisch und 
einfach wie du das beschreibst, nur hackt es leider in der Umsetzung.

Wie schaffe ich es, dass er dimmt ohne vorher auszuschalten.

Momentan habe ich es so programmiert, dass wenn er zwischen einem 
Zählwert von 1 und 5 liegt (er zählt alle 10ms) er Ein- bzw. Ausschalten 
soll. Ab einem Zählwert von 10 soll er bis die Taste losgelassen wird 
dimmen. Nun erreicht er die Ein/Ausschaltvoraussetzung natürlich 
wesentlich früher.

Im Ergebnis blinkt er und dimmt nicht.

von Simpel (Gast)


Lesenswert?

Moin,

Das Kurz_drücken wird erst beim Loslassen des Sensors ausgewertet. Wenn 
beim Loslassen die Zeit innerhalb der Grenze liegt, wird geschaltet, 
wenn die Zeit über der Obergrenze für das Kurz_drücken liegt, wird nicht 
mehr geschaltet.

Das Dimmen hingegen beginnt automatisch genau dort, wo die Zeit für das 
Kurz_drücken überschritten wird...

von Alex P. (alex2203)


Lesenswert?

Hallo Simpel,

hast du zufällig nen Codeausschnitt der dies bewerkstelligt?

Vielen Dank.

von Simpel (Gast)


Lesenswert?

Wenn du es bis zum Blinken geschafft hast, den µC zu programmieren, 
schaffst du den korrekten Ablauf auch... :-)

Prinzip:
Timer resetten und starten, sowie ein Hilfs-Flag setzen, wenn Sensor 
gedrückt.

Prüfen, wenn Flag gesetzt UND Sensor nicht gedrückt = Sensor wurde 
Losgelassen.
Wenn losgelassen, prüfen ob Zeit <= kurze Zeit. Wenn ja: Schalten.

Wenn nicht losgelassen UND Zeit > kurze Zeit, dann Dimmen, bis Sensor 
losgelassen...

von Simpel (Gast)


Lesenswert?

...fehlt noch am Ende: wenn Sensor losgelassen: Flag zurücksetzen...

von Simpel (Gast)


Lesenswert?

......

So jetzt nochmal... nach dem 3. Kaffee sollte es klappen... :-)

Prinzip:
wenn Sensor gedrückt UND Flag nicht gesetzt: Timer resetten und Flag 
setzen

Prüfen, wenn Flag gesetzt UND Sensor nicht gedrückt = Sensor wurde
Losgelassen.
Wenn losgelassen, prüfen ob Zeit <= kurze Zeit. Wenn ja: Schalten.

Wenn nicht losgelassen UND Zeit > kurze Zeit, dann Dimmen, bis Sensor
losgelassen...

Wenn losgelassen: Flag rücksetzen

von Alex P. (alex2203)


Lesenswert?

Danke Simpel,

ich werds morgen mal probieren. Müssen die Kinder halt ohne ihren Papa 
in den Zoo. ;)

Spaß beiseite... ich probiers morgen mal und meld mich dann obs geklappt 
hat

von Alex P. (alex2203)


Lesenswert?

Sehr gut! Es funktioniert. Vielen Dank für den kleinen Denkanstoß in die 
richtige Richtung.

Mit dem Forum und den Leuten hier macht programmieren richtig Spaß.

von simpel (Gast)


Lesenswert?

Siehste, "selbst ist der Mann"... im Selbermachen, Probieren, Fluchen 
und Analysieren liegt der Lerneffekt, nicht im 'copy and paste'. :)


Noch eine Prise Grundlagen-Theorie:

Ein Zustand (state) ist etwas zeitlich Andauerndes, z.B. ein stabiler 
Pegel. Den kann man jederzeit durch einfache Abfrage ermitteln.
Eine gedrückte, oder nichtgedrückte Taste besitzt einen zeitlich 
ausgedehnten Zustand (stabiler Pegel).

Ein Ereignis (event)' ist ein einzelner Zeit_Punkt, der eine Änderung 
eines Zustands (z.B. Pegelwechsel bzw. Flanke) anzeigt.
 Events zu erkennen, erfordert immer ein Hilfsflag, welches den vorigen 
(alten) Zustand gespeichert hat, um ihn mit dem aktuellen Wert 
dahingehend vergleichen zu können, ob dieser sich seit der letzten 
Abfrage verändert hat.  Der Vorgang 'Drücken, oder Loslassen einer 
Taste', ist so ein punkt-artiges Ereignis (Event), das man nur per 
Vergleich von "Zustand vorher/ Zustand jetzt" rekonstruieren kann.

Nach der Auswertung wird der "Jetzt-Zustand" wieder dem Hilfsflag 
zugewiesen, damit es beim nächsten Aufruf der Routine den 
"Vorher-Zustand" repräsentiert. Weil heute morgen gestern ist... ;-)

von Alex P. (alex2203)


Lesenswert?

Danke simpel für diese ausführliche und informative Erklärung. Hoffe 
mein Lehrer liest mit, damit er sich die mal zu Herzen nimmt und in 
Zukunft so erklärt.

Das eine Problem ist behoben, das nächste steht schon vor der Tür:

Ich möchte nun gerne den OCR Wert nicht linear ändern sondern mittels 
Formel oder Ersatzweise Array(in dem jeder einzelne OCR Wert enthalten 
ist):

Die Idee für die Formel (welche ich als Teil des LED-Fading Tuts hier 
heruntergeladen habe 
https://www.mikrocontroller.net/wikifiles/e/e4/Pwm_table.zip) war:

OCR0=(unsigned char)(4*pow(1.068,tmp++));   //fürs Hochdimmen
OCR0=(unsigned char)(4*pow(1.068,tmp--));   //fürs Runterdimmen

Wobei tmp den Schritt und 4 den Grundwert wiederspiegelt.

Die andere Idee war dieses Array hier

const unsigned char pwmtable[64] PROGMEM =
{
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 25,
  28, 30, 33, 36, 39, 42, 46, 49, 53, 56, 60, 64, 68, 72, 77, 81, 86, 
90,
  95, 100, 105, 110, 116, 121, 127, 132, 138, 144, 150, 156, 163, 169,
  176, 182, 189, 196, 203, 210, 218, 225, 233, 240, 248, 255
};

stepweise abzufragen mittels  OCR0=pwmtable[tmp++]; //fürs Hochdimmen
OCR0=pwmtable[tmp--]; //fürs Runterdimmen


Normalerweise müssten doch beide Wege funktioneren, oder?
Komischerweise flackert (eher schon ein fast Blinken) die LED beim 
Hochdimmen beim Formelweg nicht, beim Herunterdimmen flackern beide sehr 
wohl. Über OCR0++/-- gehts ohne Flackern, aber natürlich ist die 
Helligkeitsänderung ja dann nicht gleichmäßig fürs Auge.

Ich hoffe ihr könnt mir nochmals helfen. Danke euch.

von Karl H. (kbuchegg)


Lesenswert?

Alexander Pl schrieb:

> Normalerweise müssten doch beide Wege funktioneren, oder?

Im Prinzip: ja.
Man müsste das mal nachrechnen, aber ich denke die Tabellenwerte sind 
genau so entstanden, dass man (zb mit Excel) die Formel auf alle Werte 
von 0 bis 63 angewendet hat.

> Komischerweise flackert (eher schon ein fast Blinken) die LED beim
> Hochdimmen beim Formelweg nicht, beim Herunterdimmen flackern beide sehr
> wohl. Über OCR0++/-- gehts ohne Flackern, aber natürlich ist die
> Helligkeitsänderung ja dann nicht gleichmäßig fürs Auge.

Welchen Timer Modus hast du genommen?
Man muss da ein wenig aufpassen. Ein Modus, bei dem der OCR Wert 
'Immediate' übernommen wird, ist nicht geeignet.

Ansonsten gilt wie immer: Bei Fragen zum Code, zeige deinen Code.

von Alex P. (alex2203)


Angehängte Dateien:

Lesenswert?

Danke für die Antwort Karl Heinz.

Nachdem die Aktualisierung immer bei Bottom erfolgt, anbei mein Code.

von Alex P. (alex2203)


Lesenswert?

Der Fehler ist behoben.
Das Problem war die Abfrage auf OCR0==255 bzw. 0; Nun frägt er auf den 
tmp Wert ab und es funktioniert 1A.

Trotzdem Danke an alle die sich die Mühe machten mir zu helfen.

Hier noch der verbesserte Codeausschnitt:

 if ((!Dimmerzyklus)&&(Dimp==0))
 {
  Dimmerzyklus=Dimmerzeit;
  OCR0=(unsigned char)(4*pow(1.068,tmp++));
  if(tmp==63) Dimp=1;
 }
 if ((!Dimmerzyklus)&&(Dimp==1))
 {
  Dimmerzyklus=Dimmerzeit;
  OCR0=(unsigned char)(4*pow(1.068,tmp--));
  if(tmp==0) Dimp=0;
 }

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.