Forum: Mikrocontroller und Digitale Elektronik Letzte Aktion erkennen


von Sven (Gast)


Lesenswert?

Hallo zusammen,

ich habe folgendes Vorhaben:
Ein Mikrocontroller hängt an einem Funkmodul und an einem Poti (zur 
A/D-Wandlung).
Nun soll sowohl über das Poti als auch über den Empfang eines bestimmten 
Funkbefehls eine PWM an einem Ausgang des uC ausgegeben werden.
Wird als letzte Aktion das Poti bedient, soll der Wert des Potis 
entsprechend den Tastgrad am PWM-Ausgang verändern.
Wird als letzte Aktion jedoch ein Funkbefehl empfangen, soll 
entsprechend des Funkbefehls der Tastgrad am PWM-Ausgang verändert 
werden.

Leider habe ich nach langem Probieren keine passende Lösung für das 
Problem gefunden.
Die A/D-Wandlung des Potis und der Funkmodul-Treiber (Datenempfang) 
funktionieren bereits.

Hier mein leidlicher Pseudocode:
1
char flag = 0;      // soll den Zustand der Device speichern, welche zuletzt verwendet wird
2
                    // "0" bedeutet, dass zuletzt das Poti bedient wurde; "1" bedeutet, dass zuletzt ein Funkbefehl empfangen wurde
3
loop()
4
{
5
   unsigned int PWM_Dutycycle = 0;
6
7
   if(flag == 0)    // wenn zuletzt das Poti bedient wurde    
8
   {
9
       PWM_Dutycycle = Poti_AD_Value();  //...dann übernehme für den PWM-Ausgang den AD-gewandelten Wert des Potis...
10
       
11
       if(Funkbefehl_empfangen())                    // wenn ein Funkbefehl empfangen wurde
12
       {
13
          flag = 1;       // setze den PWM-Ausgang gemäß Befehl des Funkempfangs..
14
          PWM_Dutycycle = Funk_AD_Value();
15
          break;       //...und beende die If-Anweisung  (HIER IST VERMUTLICH DAS PROBLEM!)
16
       }
17
18
   if(flag == 1)
19
   {
20
       PWM_Dutycycle = Funk_AD_Value();
21
22
       if(Potibefehl_empfangen())
23
       {
24
          flag = 0;
25
          PWM_Dutycycle = Poti_AD_Value();
26
          break;
27
       }
28
   }
29
}

Ich hoffe, es kommt rüber, was ich machen möchte. Das Problem ist aber, 
dass ich aus der jeweiligen If-Anweisung nicht "rauskomme",
da das "break" ja nur die If-Anweisung verlässt, in der das break steht.

Was mache ich falsch?

Könnt ihr mir helfen?



Vielen Dank schon mal!

Gruß

: Verschoben durch User
von Sven (Gast)


Lesenswert?

Nachtrag: Habe in der "if(flag == 0) die schließende Klammer vergessen.
Ist hier aber nur ein Schreibfehler...

von Ingo L. (corrtexx)


Lesenswert?

Du gehst die Sache falsch an. Du übernimmst erstmal immer den Wert vom 
Funkmodul. Wenn sich der Wert von ADC von einer zur anderen Wandlung 
(hier bitte mal ein Timing einbauen, du ratterst das Programm nach SPS 
Manier völlig unkoordiniert durch) signifikant ändert, dann den neuen 
Wert vom ADC nehmen.

[Pseudocode]
100ms Interrupt
ADC_neu = ADC_Lesen
ADC_neu != ADC_alt => Tasgrad vom Poti nehmen
ADC_alt = ADC_neu

Neuen Wert vom Funkmodul bekommen?
Ja => Wert übernehmen
Nein => Keine Aktion

[/Pseudocode]

von Ralf G. (ralg)


Lesenswert?

Sven schrieb:
> Das Problem ist aber,
> dass ich aus der jeweiligen If-Anweisung nicht "rauskomme",
> da das "break" ja nur die If-Anweisung verlässt, in der das break steht.
Das stimmt nicht!
>
> Was mache ich falsch?

http://www.c-howto.de/tutorial-schleifen-break.html

von Sven (Gast)


Lesenswert?

Würde es eventuell so reichen? Die "flag"-Variable könnte man sich dann 
eigentlich sparen...habe hier gerade leider keine Möglichkeit es 
auszuprobieren.
1
char flag = 0;      // soll den Zustand der Device speichern, welche zuletzt verwendet wird
2
                    // "0" bedeutet, dass zuletzt das Poti bedient wurde; "1" bedeutet, dass zuletzt ein Funkbefehl empfangen wurde
3
loop()
4
{
5
   unsigned int PWM_Dutycycle = 0;
6
7
   if(flag == 0)    // wenn zuletzt das Poti bedient wurde    
8
   {
9
     
10
     if(Funkbefehl_empfangen())                    // wenn ein Funkbefehl empfangen wurde
11
       {
12
          flag = 1;       // setze den PWM-Ausgang gemäß Befehl des Funkempfangs..
13
          PWM_Dutycycle = Funk_AD_Value();
14
          break;       //...und beende die If-Anweisung  (HIER IST VERMUTLICH DAS PROBLEM!)
15
       } 
16
17
      PWM_Dutycycle = Poti_AD_Value();  //...dann übernehme für den PWM-Ausgang den AD-gewandelten Wert des Potis...
18
       
19
       
20
    }
21
}

Gruß

von Ingo L. (corrtexx)


Lesenswert?

Und wer setzt "flag" zurück auf 0? So funktioniert das genau 1x.

von Sven (Gast)


Lesenswert?

Ich versuche es mal ohne "Flag", sofern das ginge:
1
loop()
2
{
3
   unsigned int PWM_Dutycycle = 0;
4
5
   if(Potibefehl_empfangen())    // wenn zuletzt das Poti bedient wurde    
6
   {
7
     
8
     if(Funkbefehl_empfangen())                    // wenn ein Funkbefehl empfangen wurde
9
       {
10
          PWM_Dutycycle = Funk_AD_Value();
11
          break;       //...und beende die If-Anweisung  (HIER IST VERMUTLICH DAS PROBLEM!)
12
       } 
13
14
       PWM_Dutycycle = Poti_AD_Value();  //...dann übernehme für den PWM-Ausgang den AD-gewandelten Wert des Potis...
15
    }
16
}

Nun habe ich das Flag mal weggelassen...müsste nun noch die Pausenzeit, 
die du genannt hast, einfügen.

Ginge das so?

Gruß und Danke schonmal für deine Hilfe!

von Ingo L. (corrtexx)


Lesenswert?

1
if(Funkbefehl_empfangen())
2
{
3
 PWM_Dutycycle = Funk_AD_Value();
4
}else{
5
 if (ADC_neu != ADC_alt) PWM_Dutycycle = Funk_AD_Value();
6
 ADC_alt = ADC_neu;
7
}

von Sven (Gast)


Lesenswert?

Hallo Ingo!

Danke, ich verstehe nur noch nicht die If-Anweisung im Else-Zweig.
Vielleicht ist die Namensgebung meiner Funktion "Funkbefehl_empfangen()" 
irreführend. Besser wäre wohl "Funkdaten_empfangen()". Diese Funktion 
liefert schon den entsprechenden AD-Wert.
Außerdem: Wo wird nun der Wert bei einer eventuellen Poti-Änderung 
(Potidaten_empfangen()  ) übernommen?  Oder meinst du damit das 
"ADC_neu" und "ADC_alt"?

von Sven (Gast)


Lesenswert?

Müsste der Code nicht anders lauten?
Denn er liest ja bei einer AD-Änderung des Potis (AD_neu != AD_alt) 
wieder den Wert des Funkmoduls ein?!

Bei einer Äquivalenzprüfung würde ich den Code verstehen ((AD_neu == 
AD_alt))

von Sven (Gast)


Lesenswert?

1
if(Funkbefehl_empfangen())
2
{
3
    PWM_Dutycycle = Funk_AD_Value();    // wenn Funkbefehl empfangen wird, übernehme den Wert, den er per Funk erhalten hat
4
}
5
6
else
7
{
8
    if (Poti_ADC_neu != Poti_ADC_alt)  // wenn am Poti gedreht wurde..
9
    {
10
        PWM_Dutycycle = Poti_AD_Value();   // sollte er doch den Poti-Value übernehmen
11
    }
12
    Poti_ADC_alt = Poti_ADC_neu;
13
}


Und was ist Poti_ADC_neu und Poti_ADC_alt?

von Ralf G. (ralg)


Lesenswert?

Sven schrieb:
> Und was ist Poti_ADC_neu und Poti_ADC_alt?

Hä? Du hast das doch hingeschrieben! Wieso weißt du das dann nicht?

von Sven (Gast)


Lesenswert?

>Hä? Du hast das doch hingeschrieben! Wieso weißt du das dann nicht?
Ich habe den Code von Ingo übernommen. Mein Ursprungs-Code steht weiter 
oben.

von Ralf G. (ralg)


Lesenswert?

Sven schrieb:
> Ich habe den Code von Ingo übernommen.

Ich weiß schon, dass du nur zusammenkopierst! ;-)

Nur hast du aus 'ADC_alt' einfach 'Poti_ADC_alt' gemacht. Das Ergebnis 
ist natürlich das gleiche. Aber möglicherweise verwirrt dich jetzt 
dein selbstgewählter Name, denn deine Beschreibung der Funktionsweise 
ist möglicherweise entweder zu kompliziert ausgedrückt oder entspricht 
möglicherweise nicht der gewollten Funktion.

Also zum Verständnis ist ein PAP sinnvoll bzw. ein deutlich 
eingekürzter Pseudocode. Dann erkennst du möglicherweise, dass in 
deinem Ursprungspost viele unnütze Programmteile stehen.

von S. R. (svenska)


Lesenswert?

Sven schrieb:
> Wird als letzte Aktion das Poti bedient, soll der Wert des Potis
> entsprechend den Tastgrad am PWM-Ausgang verändern.

Was bedeutet "wird als letzte Aktion bedient"?

Beim Funkmodul ist das einfach: Es kommt ein Befehl "ich habe empfangen" 
rein. Aber beim Poti?

Das kannst du jede Sekunde, jede Mikrosekunde, jede Millisekunde 
auslesen, und es wird dir immer sagen, welchen Wert es gerade hat.

Woran machst du fest, dass es "bedient" wurde?

von Ingo L. (corrtexx)


Lesenswert?

S. R. schrieb:
> Woran machst du fest, dass es "bedient" wurde?
Ich würde es daran fest machen ob sich der Wert geändert hat. Dann dann 
muss es jemand bedient haben...

Sven schrieb:
> Bei einer Äquivalenzprüfung würde ich den Code verstehen ((AD_neu ==
> AD_alt))
Okay
1
else
2
{
3
    Poti_ADC_neu = Poti_AD_Value();
4
    if (Poti_ADC_neu != Poti_ADC_alt)  // wenn am Poti gedreht wurde..
5
    {
6
        PWM_Dutycycle = Poti_AD_Value();   // sollte er doch den Poti-Value übernehmen
7
        Poti_ADC_alt = Poti_ADC_neu;
8
    }
9
}

von S. R. (svenska)


Lesenswert?

Ingo L. schrieb:
>> Woran machst du fest, dass es "bedient" wurde?
> Ich würde es daran fest machen ob sich der Wert geändert hat. Dann dann
> muss es jemand bedient haben...

Das wollte ich von Sven hören, nicht von dir.

von STK500-Besitzer (Gast)


Lesenswert?

1
 else
2
 {
3
     Poti_ADC_neu = Poti_AD_Value();
4
     if (Poti_ADC_neu != Poti_ADC_alt)  // wenn am Poti gedreht wurde..
5
     {
6
         PWM_Dutycycle = Poti_ADC_neu;   // sollte er doch den 
7
 Poti-Value übernehmen
8
         Poti_ADC_alt = Poti_ADC_neu;
9
     }
10
 }

Wenn man die Messfunktion zwei Mal verwendet, könnten unterschiedliche 
Werte herauskommmen. Außerdem erhöht die Verwendung der Variable die 
Geschwindigkeit, da nicht noch mal auf den ADC gewartet werden muss (ich 
gehe von Polling beim ADC aus).

von Tek (Gast)


Lesenswert?

Du solltest Dir vielleicht auch überlegen ob das ganze mit der Poti/Funk 
Einstellung noch zu bedienen ist.
Du schreibst zwar nicht was an der PWM hängt aber mal angenommen das ist 
eine LED bei der Du die Helligkeit einstellst.

- Jemand stellt mit dem Poti eine Helligkeit von 10% ein
- Per Funk wird nun auf 90% gestellt
- Wenn nun jemand nur ein wenig dunkler stellen möchte und am Poti dreht 
springt der wert sofort auf <10%

Ich würde das mit 2 Tasten für +/- machen, so kannst Du immer relativ 
zum aktuellen Wert stellen.

von STK500-Besitzer (Gast)


Lesenswert?

Tek schrieb:
> Ich würde das mit 2 Tasten für +/- machen, so kannst Du immer relativ
> zum aktuellen Wert stellen.

Oder Drehencoder

von Ingo L. (corrtexx)


Lesenswert?

STK500-Besitzer schrieb:
> Oder Drehencoder
Genau, würde ich auch nehmen

von Dietrich L. (dietrichl)


Lesenswert?

Ingo L. schrieb:
> S. R. schrieb:
>> Woran machst du fest, dass es "bedient" wurde?
> Ich würde es daran fest machen ob sich der Wert geändert hat. Dann dann
> muss es jemand bedient haben...

So einfach geht das aber nicht.
Man braucht in jedem Fall noch Hysterese dazu, denn das letzte Bit kann 
immer toggeln, wenn der Wert gerade "auf der Kippe" steht. Außerdem sind 
bestimmt Störungen auf dem Poti-Signal, die das Ergebnis noch weiter 
verschlechtern.

von Sven (Gast)


Lesenswert?

Hallo zusammen,

ich habe es nochmals mit meinem Code versucht, schließlich will ich ja 
nicht dastehen, als würde ich alles nur "zusammenkopieren"...
1
loop()
2
{
3
   unsigned int PWM_Dutycycle = 0;
4
5
   if(Potibefehl_empfangen())    // wenn zuletzt das Poti bedient wurde    
6
   {
7
     
8
     if(Funkbefehl_empfangen())                    // wenn ein Funkbefehl empfangen wurde
9
       {
10
          PWM_Dutycycle = Funk_AD_Value();
11
          break;       //...und beende die If-Anweisung  (HIER IST VERMUTLICH DAS PROBLEM!)
12
       } 
13
14
       PWM_Dutycycle = Poti_AD_Value();  //...dann übernehme für den PWM-Ausgang den AD-gewandelten Wert des Potis...
15
    }
16
}

Dieser Code funktioniert aber leider nicht, ich weiß nicht warum...

Ich kann leider eure netten Einwände nicht in meinen Code umsetzen, seht 
mir bitte nach.

Könnt ihr mir vielleicht bzgl meines obigen Codes nochmals unter die 
Arme greifen?

Danke!

von STK500-Besitzer (Gast)


Lesenswert?

Sven schrieb:
> Dieser Code funktioniert aber leider nicht, ich weiß nicht warum...

Mit "break" muss man eher selten arbeiten. Besser (weil verstänbdlicher) 
sid mMn else-Zweige.

der Ablauf sollte doch eher so sein:
1. hat sich der Poti-Wert seit dem letzten Schleifendurch geändert?
- ja: Übernimm den Potiwert als neuen PWM-Wert
- nein: wurde etwas per Funk empfangen?
  - übernimm den Funkwert als neuen PWM-Wert
- gehe zu 1.

ist das so schwer?
Einfaches Drauflostippen hat nichts mit Programmieren zu tun.

von Adam P. (adamap)


Lesenswert?

Sven schrieb:
> break;       //...und beende die If-Anweisung  (HIER IST VERMUTLICH DAS
> PROBLEM!)

Grundsätzlich kann man ein
1
break
 nicht auf
1
if()
 anwenden!
ein break lässt sich nur auf Schleifen anwenden.
Und so wie es aussieht ist loop() bei dir eine Funktion (Arduino?) und 
in dem Sinn keine Schleife, nur weil sie Zyklisch aufgerufen wird.

Dann versuch es mal einem einfachen return;
1
     if(Funkbefehl_empfangen())                    // wenn ein Funkbefehl empfangen wurde
2
       {
3
          PWM_Dutycycle = Funk_AD_Value();
4
          return;       //...und beende die If-Anweisung  (HIER IST VERMUTLICH DAS PROBLEM!)
5
       }

Aber deine Variable "PWM_Dutycycle" ist doch lokal, wo wird diese den 
ausgewertet? Denn beim nächsten Durchlauf bzw. direkt nach dem verlassen 
der Fkt. ist sie eh ungültig.

von Sven (Gast)


Lesenswert?

Ja genau, "loop()" ist die "Schleife" aus dem Arduino:

Ich versuchs jetzt nochmal anhand eurer Infos:
1
unsigned int PWM_Dutycycle = 0;
2
unsigned int old_Poti_value = 0;
3
unsigned int new_Poti_value = 0;
4
5
loop()
6
{
7
   if(new_Poti_value != old_Poti_value)
8
   {
9
       new_Poti_value = Poti_AD_value();
10
       PWM_Dutycycle = new_Poti_value();
11
       setPWM(PWM_Dutycycle);
12
       old_Poti_value = new_Poti_value;
13
   }
14
   else
15
   {
16
       if(Funkbefehl_empfangen())
17
       {
18
           PWM_Dutycycle = Funk_AD_value();
19
           setPWM(PWM_Dutycycle);
20
       }
21
}

So sollte es für mein Dafürhalten funktionieren.
Werde es zuhause mal ausprobieren.

Einwände eurerseits?

Grüße u. Danke Euch vielmals!

von STK500-Besitzer (Gast)


Lesenswert?

Sven schrieb:
> if(new_Poti_value != old_Poti_value)
>    {
>        new_Poti_value = Poti_AD_value();
>        PWM_Dutycycle = new_Poti_value();
>        setPWM(PWM_Dutycycle);
>        old_Poti_value = new_Poti_value;
>    }
>    else

Woher bekommst du den neuen Poti-Wert, wenn du ihn erst nach der Abfrage 
ermittelst?
1
 new_Poti_value = Poti_AD_value();
2
 if(new_Poti_value != old_Poti_value)
3
    {
4
        setPWM(new_Poti_value);
5
        old_Poti_value = new_Poti_value;
6
    }

von Ralf G. (ralg)


Lesenswert?

Sven schrieb:
> Dieser Code funktioniert aber leider nicht

Das zählt nicht als Fehlerbeschreibung.
Du musst erstmal rausfinden, was nicht funktioniert und den Fehler 
eingrenzen.
Es könnten, z.B., Messwerte falsch übertragen werden -> LED für Ausgabe 
missbrauchen, z.B. mit Blinkmustern.
Es könnten Verzweigungen falsch ausgeführt werden, weil die 
Abfragebedingungen nicht stimmen -> LED für Ausgabe missbrauchen, z.B. 
mit Blinkmustern.

Wenn du mal dein C-Buch zur Hand nimmst (ersatzweise wenigstens mal dem 
geposteten Link folgst), wirst du einen offensichtlichen Fehler finden, 
der möglicherweise den gröbsten Fehler schon beseitigt.

Weiterhin ist nach deiner Beschreibung das Ganze möglicherweise so 
nicht umsetzbar:
Tek schrieb:
> - Jemand stellt mit dem Poti eine Helligkeit von 10% ein
> - Per Funk wird nun auf 90% gestellt
> - Wenn nun jemand nur ein wenig dunkler stellen möchte und am Poti dreht
> springt der wert sofort auf <10%
Dietrich L. schrieb:
> Man braucht in jedem Fall noch Hysterese dazu,

von Erfahrener Programmierer (Gast)


Lesenswert?

Sven schrieb:
> So sollte es für mein Dafürhalten funktionieren.

Tut es nicht.

Du programmierst nicht, sondern Du probierst rum bis es mit etwas Glück 
funktioniert. Das ist Dein Grundproblem.

Schau mal Dein Code genau an. Du hast ganz am Anfang stehen:
1
unsigned int old_Poti_value = 0;
2
unsigned int new_Poti_value = 0;

Dann kommt als nächstes:
1
loop()
2
{

Also die Endlos-Schleife beginnt. Und nun?
1
if(new_Poti_value != old_Poti_value)

Diese Bedingung wird nie Wahr werden, weil in beiden Variablen "0" drinn 
steht!

Du musst lernen vorher zu überlegen, was Du willst, dann Deine Gedanken 
sortieren und niederschreiben, und dann alles mit Nachdenken prüfen, ob 
Du alles in der richtigen Reihenfolge hast!

Diese rum-probiererei und zusammen-kopiererei führt nicht zum Ziel!

von Ralf G. (ralg)


Lesenswert?

Erfahrener Programmierer schrieb:
> Diese rum-probiererei und zusammen-kopiererei führt nicht zum Ziel!

Doch, selbstverständlich!! Es wird schon bald einer den komletten und 
funktionsfähigen Code präsentieren.

von Sven (Gast)


Lesenswert?

Hallo,
Ja das stimmt, ich muss lernen, pragmatischer an die Sache ranzugehen.
Habe ich verstanden, dass die Bedingung nie wahr wird, da die Variablen 
keine anderen Werte als "0" haben.
Deshalb muss ich folglich vor der Bedingung den Wert abholen und der 
Variable zuweisen.

Überarbeitet:
1
unsigned int PWM_Dutycycle = 0;
2
unsigned int old_Poti_value = 0;
3
unsigned int new_Poti_value = 0;
4
5
loop()
6
{
7
   new_Poti_value = Poti_AD_value();
8
   
9
   if(new_Poti_value != old_Poti_value)
10
   {    
11
       PWM_Dutycycle = new_Poti_value();
12
       setPWM(PWM_Dutycycle);
13
       old_Poti_value = new_Poti_value;
14
   }
15
   else
16
   {
17
       if(Funkbefehl_empfangen())
18
       {
19
           PWM_Dutycycle = Funk_AD_value();
20
           setPWM(PWM_Dutycycle);
21
       }
22
   }
23
}

von Peter D. (peda)


Lesenswert?

Tek schrieb:
> - Wenn nun jemand nur ein wenig dunkler stellen möchte und am Poti dreht
> springt der wert sofort auf <10%

Daher ist es besser, einen Drehgeber zu benutzen.

von S. R. (svenska)


Lesenswert?

Sven schrieb:
> Überarbeitet:

Das wird dir der Compiler um die Ohren hauen, weil new_Poti_value eine 
Variable und keine Funktion ist.

Testest du den Code, den du hier postest, auch?

von Sven (Gast)


Lesenswert?

Ich habe hier keinen Compiler und nur einen Editor.
Natürlich müssen die "();" weg.

Beitrag #5089373 wurde vom Autor gelöscht.
von STK500-Besitzer (Gast)


Lesenswert?

Adam P. schrieb im Beitrag #5089373:
> da du unabhängig von
> empfangenen Werten noch den alten vom Poti speicherst.

Der wird verwendet, um eine Änderung der Potistellung zu erkennen.

Adam P. schrieb im Beitrag #5089373:
> Hab das Gefühl,
> das dürfte bei abwechselndem betätigen und evtl. Sprüngen über Funk -
> abgehackt aussehen

Richtig. Und wurde oben schon angesprochen.

Adam P. schrieb im Beitrag #5089373:
> WAS NUN...mit dem Poti kannst nicht mehr höher drehen nur noch runter.

Die PWM ist proportional zur Potistellung.
Wenn es sich also am unteren Ende befindet, per Funk 100% gesetzt werden 
und man das Poti dann bewegt, wird die PWM auf den "aktuellen" Poti-Wert 
gesetzt.

Soweit ist alles logisch. Sieht vielleicht doof aus, aber nicht wirklich 
ein Problem.
Deswegen wurde schon (mehrfach) der Drehencoder vorgeschlagen.

von Adam P. (adamap)


Lesenswert?

Ja ist mir nach dem Verfassen auch klar geworden,
weshalb ich den Post gelöscht hatte :-/ Sorry.

War darauf bezogen, wenn er nur den letzten Wert gespeichert hätte - 
aber alles gut. Mein Fehler.

von Sven (Gast)


Lesenswert?

Hallo zusammen.

Es mag einfach nicht so wie ich es möchte.
Ich habe nun im nachfolgenden Code die Möglichkeit, dass sich der 
Tastgrad der PWM beim Poti-Drehen verändert. Das ist ja auch schon mal 
gut.
Aber: wenn ich per Bluetooth einen Wert schicke (zwischen 0 und 255), 
wird dieser zwar genau für diesen Moment übernommen, er hält aber nicht 
den Wert, den er per Bluetooth empfangen hat.

Wie aber halte ich den Bluetooth-Wert solange, bis ein nächster 
Bluetooth-Wert bzw. eine Poti-Aktion erfolgt?

Hier mein Code:
1
#include <SoftwareSerial.h>
2
3
#define BT_Rx_Pin 2                                                   // Rx Pin (Arduino) für BT
4
#define BT_Tx_Pin 1                                                   // Tx Pin (Arduino) für BT
5
int PotiPin = 1;                                                      // Poti-Pin (Schleifer)
6
int PowerOutPin = 6;                                                 // PWM-Ausgang des Arduinos (an Basis des Transistors)
7
8
int old_Poti_value = 0;
9
int new_Poti_value = 0;
10
int old_BT_value = 0;
11
int new_BT_value = 0;
12
int PWM_Dutycycle = 0;
13
SoftwareSerial btSerial(BT_Rx_Pin, BT_Tx_Pin);
14
15
void setup() 
16
{
17
  pinMode(PowerOutPin, OUTPUT);                                       // PWM-Pin als Ausgang deklarieren
18
  btSerial.begin(9600);
19
  Serial.begin(9600);
20
  
21
  while (!btSerial);                                                  // warten, bis SerialPort verfügbar ist
22
}
23
24
void loop()
25
{
26
   new_Poti_value = analogRead(PotiPin);                              // Einlesen des aktuellen AD-Wertes des Potis
27
   new_BT_value = get_received_Bluetooth_Data();                      // Einlesen des evtl. gesendeten BT-Wertes (0-100)
28
   
29
   if(new_Poti_value != old_Poti_value)                               // Wenn der neue AD-Wert ungleich des alten ist...
30
   {    
31
       PWM_Dutycycle = (new_Poti_value/4);                            // ...setze PWM-Tastgrad entsprechend des AD-Werts..
32
       analogWrite(PowerOutPin, PWM_Dutycycle);                       // PWM mit entsprechendem Tastgrad an PowerPin ausgeben
33
       old_Poti_value = new_Poti_value;                               // neuer AD-Wert wird dem Alten zugewiesen
34
   }
35
   
36
   
37
   if(new_BT_value != old_BT_value)                               // Wenn der neue BT-Wert ungleich des alten ist...
38
   {
39
       PWM_Dutycycle = new_BT_value;                              // ...setze PWM-Tastgrad entsprechend des gesendeten BT-Wertes (0..255)
40
       Serial.println("BLUETOOTH PWM_Dutycycle: ");
41
       Serial.println(PWM_Dutycycle);
42
       analogWrite(PowerOutPin,PWM_Dutycycle);
43
       old_BT_value = new_BT_value;                               // neuer BT-Wert wird dem Alten zugewiesen
44
   }  
45
}
46
47
//-----------------------------------------------------------------------------------------------
48
int get_received_Bluetooth_Data()
49
{
50
  if (Serial.available())
51
  { 
52
    int received_BT_Data = Serial.parseInt();
53
    Serial.println("received BT data");
54
    Serial.println(received_BT_Data);
55
    return received_BT_Data;  
56
  }
57
}
58
//-----------------------------------------------------------------------------------------------

"Dominierend" ist der Wert des Potis, da der ja bei jeder Abfrage stetig 
am Analogpin anliegt. Beim Empfang bei Bluetooth sieht es aber anders 
aus: da kommt nur einmal ein Wert, der "gehalten" werden soll, bis die 
nächste Aktion erfolgt...

Wisst ihr wie ich meine?
Könnt ihr mir helfen?

Danke!

von S. R. (svenska)


Lesenswert?

Ich verweise nochmal auf meinen Beitrag von vor längerer Zeit:

S. R. schrieb:
> Was bedeutet "wird als letzte Aktion bedient"? [...]

Lies den gesamten Beitrag und denke darüber nach. Bedenke außerdem, dass 
ein Poti am ADC rauscht.

Solange du die dort gestellte Frage nicht für deinen Anwendungsfall 
ausreichend beantworten kannst, ist die gesamte sonstige Diskussion 
zwecklos.

von Sven (Gast)


Lesenswert?

>Was bedeutet "wird als letzte Aktion bedient"?

Das bedeutet, dass der Wert, der über Bluetooth übermittelt wurde 
solange den Tastgrad der PWM angibt, bis entweder ein anderer 
Bluetooth-Wert oder eine Aktion am Poti ausgeführt wird.

Das Rauschen habe ich versucht mit einer Hysterese (AD_Wert +/- 20) zu 
umgehen.
Mittlerweile empfange ich zwar am Arduino das richtige Signal, am 
Oszilloskop sehe ich aber, wie ständig zwischen dem Wert von Poti und 
dem von Bluetooth hin- und hergesprungen wird.

von S. R. (svenska)


Lesenswert?

Vielen Dank für die Bestätigung, dass du den Beitrag nicht gelesen hast.

Sven schrieb:
> bis entweder ein anderer
> Bluetooth-Wert oder eine Aktion am Poti ausgeführt wird.

Wie definierst du "eine Aktion am Poti ausgeführt"?

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Sven schrieb:
> Das Rauschen habe ich versucht mit einer Hysterese (AD_Wert +/- 20) zu
> umgehen.

Sehe ich hier:
Sven schrieb:
> if(new_Poti_value != old_Poti_value)
nicht wirklich.
Sobald sich am ADC-Wert auch nur das unterste Bit verändert (und Das tut 
Es ständig), hast Du die Bedingung erfüllt und der Poti-Wert wird 
übernommen.

Wie sieht es aus, wenn Du die Sache etwas Anders angehst?
Prüfe, ob das Poti 'auf Null' gedreht wurde.
Dann startest Du die Poti-Wert-Ermittlung, passt jedes Mal den PWM an, 
wartest 500ms, liest den Poti-Wert erneut ein ect.pp.
Wenn Du jetzt 6x den gleichen Poti-Wert ermittelst (3 Sekunden maximale 
Pause beim Poti-Spielen) - dabei ggf. ein/zwei untere Bits löschen/nicht 
mit prüfen, wird das Poti-Einlesen beendet, der neue Wert liegt an.

Beim nächsten BT-Wert wird Dieser wieder übernommen.

Wenn wieder von Hand gestellt werden soll, auf Linksanschlag (die Lampe 
geht aus) und per rechts/links drehen die Helligkeit einstellen.
Nach drei Sekunden ohne Änderung (6x 500ms delay) wird wieder geprüft, 
ob ein erneuter Einstellversuch unternommen werden soll oder vom 
BT-Empfänger was kam.


MfG

: Bearbeitet durch User
von Genervter (Gast)


Lesenswert?

1
const int  stickiness = 10;
2
3
boolean    usePoti = true;
4
int        anchor;
5
6
void loop()
7
{
8
  int poti = analogRead(...);
9
10
  usePoti = usePoti || abs(poti - anchor) >= stickiness;
11
12
  if (Serial.available())
13
  {
14
    usePoti = false;
15
    anchor = poti;
16
17
    PWM = Serial.parseInt();
18
  }
19
  else if (usePoti)
20
  {
21
    PWM = poti;
22
  }
23
24
}

von Genervter (Gast)


Lesenswert?

Genervter schrieb:
> usePoti = usePoti || abs(poti - anchor) >= stickiness;
                                         ~~~~

Ups,.. Solte nur ein '>' sein...

von Adam P. (adamap)


Lesenswert?

Sven schrieb:
1
//Wenn der neue AD-Wert ungleich des alten ist...
2
if(new_Poti_value != old_Poti_value)

Genervter schrieb:
> usePoti = usePoti || abs(poti - anchor) >= stickiness;

Oder du änderst die Zeile um und fügst eine Abweichung ein um nicht bei 
jeder Bit-Änderung zu denken, es sei was passiert.

1
#define DIFF    10    //musst mal testen und ausprobieren (mehr oder weniger)
2
3
if( abs(new_Poti_value - old_Poti_value) > DIFF)

Dann musst nicht den ganzen Code umschreiben.

: Bearbeitet durch User
von Sven (Gast)


Lesenswert?

Hallo zusammen,

ich habe es nun endlich geschafft (siehe Code).
Allerdings macht sich nun ein weiteres Problemchen bemerkbar. Ich habe 
einen IRL3039 am Ausgang des PWMs-Signals hängen.
Wenn ich per Bluetooth eine "0" sende, geht leider die angehängte Last 
nicht auf "0", obwohl sie bei Bewegung des Potis gen "0" direkt 
"ausgeht", was sie auch soll.
Woran kann das schon wieder liegen?

In Verwendung ist ein IRL3039, das Gate ist mit einem 270Ohm Widerstand 
und einem PullUp 10kOhm Widerstand gen Masse verbunden.

"0" am Poti bedeutet hier anscheinend nicht "0" via Bluetooth?!

Hier der nun aktuellste Code (mit dem dimmen und die 
Poti/Bluetooth-Interaktion wunderbar funktioniert):
1
#include <SoftwareSerial.h>
2
3
#define BT_Rx_Pin 2                                                   // Rx Pin (Arduino) für BT
4
#define BT_Tx_Pin 1                                                   // Tx Pin (Arduino) für BT
5
int PotiPin = 1;                                                      // Poti-Pin (Schleifer)
6
int PowerOutPin = 6;                                                 // PWM-Ausgang des Arduinos (an Basis des Transistors)
7
8
int old_Poti_value = 0;
9
int new_Poti_value = 0;
10
int PWM_Dutycycle = 0;
11
int in = 0;
12
13
SoftwareSerial btSerial(BT_Rx_Pin, BT_Tx_Pin);
14
15
void setup() 
16
{
17
  pinMode(PowerOutPin, OUTPUT);                                       // PWM-Pin als Ausgang deklarieren
18
  btSerial.begin(9600);
19
  Serial.begin(9600);
20
  
21
  while (!btSerial);                                                  // warten, bis SerialPort verfügbar ist
22
}
23
24
void loop()
25
{
26
   new_Poti_value = analogRead(PotiPin);                              // Einlesen des aktuellen AD-Wertes des Potis
27
   if (Serial.available() > 0) 
28
   {
29
       in = Serial.parseInt();                                        // lese empfangenen Integerwert von Bluetoothmodul ein
30
   }
31
   Serial.println("in: ");
32
   Serial.println(in);
33
34
   if((new_Poti_value > (old_Poti_value + 20)) | (new_Poti_value < (old_Poti_value - 20)))    // Hysterese - AD-Eingang (Rauschunterdrückung)
35
   {    
36
       PWM_Dutycycle = (new_Poti_value/4);                            // ...setze PWM-Tastgrad entsprechend des AD-Werts..
37
       analogWrite(PowerOutPin, PWM_Dutycycle);                       // PWM mit entsprechendem Tastgrad an PowerPin ausgeben
38
       old_Poti_value = new_Poti_value;                               // neuer AD-Wert wird dem Alten zugewiesen
39
       Serial.print("Poti: ");
40
       Serial.println(new_Poti_value);
41
   }
42
   
43
  
44
   if(in)
45
   {
46
       PWM_Dutycycle = in;                              // ...setze PWM-Tastgrad entsprechend des gesendeten BT-Wertes (0..255)
47
       Serial.println("BLUETOOTH PWM_Dutycycle: ");
48
       Serial.println(PWM_Dutycycle);
49
       analogWrite(PowerOutPin,PWM_Dutycycle);
50
       in=0;
51
   } 
52
   
53
   Serial.print("Duty_Cycle: ");
54
   Serial.println(PWM_Dutycycle);
55
 
56
}


Vielen Dank und Gruß

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Wenn ich Deinen Code recht verstehe, kannst Du aber nur Sprünge per Poti 
einstellen - eben die 20 Hysterese, Die erst überwunden sein müssen, 
damit der neue Wert übernommen wird.

Wenn Das für Dich aber ausreichend funktioniert, passt Das.

Du lässt Dir ja die empfangenen Werte (BT und Poti) ausgeben - kommt von 
BT auch eine Null?
Oder, geht das Poti eben NICHT auf Null, sondern dümpelt bei 3 rum? 
(wegen der >20er Sprünge?)
Könnte mir vorstellen, daß Deine Null ggf. Voll An darstellt und 255 
wäre dann voll aus?

MfG

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.