Forum: Mikrocontroller und Digitale Elektronik Probleme mit der Verbindung PWM + ADC


von Maximilian (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich bräuchte mal kurz eure Hilfe, weil iwie komm ich hier nicht weiter.

Ich habe mir aus den Tutorials ein Programm versucht zusammen zu 
basteln, dass folgendes macht:
Ich habe am PC0 (ADC) einen FSR-Sensor (funktioniert ähnlich wien Poti 
nur ändert er den Widerstand auf Druck).
Bei PB1 (0C1A) habe ich ein paar LED's angeschlossen übern Transistor.

Das Programm soll, wenn Druck auf dem FSR-Sensor ist, die LED's 
aufleuchten lassen und per PWM dimmen. Liegt kein Druck auf dem Sensor 
soll auch nix passieren. Ich habe beides einzeln hinbekommen, also Druck 
auf den Sensor --> LED's fangen an zu leuchten und ich habe das 
Programm, wo ein LED Fading statt findet. Wenn ich die beiden zusammen 
wurschtel macht er nur ein wirres LED Fading, egal ob Druck oder nicht.
Leider check ich nicht so ganz warum und es würde mich sehr freuen, wenn 
mich einer von euch in die richtige Richtung schubsen könnte :)

Danke schonmal

Ach ja, µC ist ein ATMega48

von BOOOL (Gast)


Lesenswert?

42

von Maximilian (Gast)


Lesenswert?

TCCR1B &= ~0x7;  <-- Meinst du das damit?

von Karl H. (kbuchegg)


Lesenswert?

Wie soll das zusammengehen?

1
uint16_t pwmtable_8B[8]  PROGMEM = {0, 4,  8, 16, 32, 64,  128, 255};
Du hast 8 PWM Stufen definiert

1
    for(tmp=0; tmp<=255; tmp++){              //255 Stufen bei 8-bit, rauf zählen
2
      OCR1A = pgm_read_word(pwmtable_8B+tmp);
3
      my_delay(delay);
4
    }
versuchst aber 256 auszugeben.


Schreib das so doch so
1
uint16_t pwmtable_8B[8]  PROGMEM = {0, 4,  8, 16, 32, 64,  128, 255};
2
3
#define ARRAY_SIZE(x)    (sizeof(x)/sizeof(*x))
...
1
    for(tmp=0; tmp < ARRAY_SIZE(pwmtable_8B); tmp++) {
2
      OCR1A = pgm_read_word( &pwmtable_8B[tmp] );
3
      my_delay(delay);
4
    }

Lass den Compiler für dich arbeiten! Der kann solche fixe Zahlen, die 
aber korrekt sein müssen, viel besser verwalten als du.

von Udo S. (urschmitt)


Lesenswert?

Erkläre uns mal bitte was deine Funktion  pwm_8_8() macht, und wie lange 
sie dazu braucht?

von Maximilian (Gast)


Lesenswert?

Danke für die schnellen Antworten.

Dass mit den 255 Stufen ist natürlich ein Übertragungsfehler gewesen, 
welchen ich übersehen hatte, jetzt läuft die PWM auch sauber rauf und 
runter.

Wenn ich das so mache, wie Karl Heinz gesagt hat, dann macht der µC nach 
dem Start 3 mal die PWM und dann leuchten die LED's auf höchster Stufe 
kontinuierlich.

Also mein Verdacht ist, dass ich erstens nicht aus der Fadingschleife 
raus gehe, bzw. diese nicht nach einem PWM-Durchlauf beende.

Und was ich überhaupt nicht verstehe, warum der µC gar nicht auf den 
Sensor reagiert?

von Maximilian (Gast)


Lesenswert?

Halt, dass es 3 mal die PWM fährt hab ich rausgefunden grad, sorry :)

von Karl H. (kbuchegg)


Lesenswert?

Maximilian schrieb:


> Also mein Verdacht ist, dass ich erstens nicht aus der Fadingschleife
> raus gehe, bzw. diese nicht nach einem PWM-Durchlauf beende.

Quatsch.

Du musst systematischer testen.
Was mir an deinem Code schon mal nicht gefällt ist, dass du an den Pins 
rumfummelst. Den Pin mit der LED schaltest du am ANFANG einmal auf 
Ausgang. Und dann lässt du ihn auch in Ruhe. Die Helligkeit stellst du 
nicht mittels irgendwelchen Portausgaben ein, sondern immer nur in dem 
du das OCR Register umstellst. Du verlierst sonst unweigerlich den 
Überblick.

> Und was ich überhaupt nicht verstehe, warum der µC gar nicht auf den
> Sensor reagiert?

Dann musst du das eben erst mal testen, welche ADC Werte du bekommst.

Konfigurier dir eine PWM.

Dann stellst du erst mal fest, ob ein OCR Wert von 0 einer 
ausgeschalteten oder einer eingeschalteten LED entspricht.

Danach konfigurierst du dir (im selben Programm) den ADC und gibst den 
ADC Wert direkt auf die PWM, ohne Schnickschnack.

Und erst dann, wenn das funktioniert, machst du von dort aus weiter.


Ein Komplettprogramm aus Einzelteilen zusammenzuwürfeln funktioniert 
meistens nicht. Du musst das wie ein neues Programm betracheten. Du 
kannst dir aus einem anderen, älteren Projekt Codeteile mittels 
Copy&Paste einfügen, das ist schon ok. Aber du musst das wie "Im Prinzip 
schreib ich das neu, nur hab ich den Code schon" betrachten. So nach dem 
Muster "Och da mach ich eine Mischung aus diesen beiden Programmen", das 
wird meistens nix.

von Maximilian (Gast)


Lesenswert?

Jo haste Recht, bin wohl bissi zu planlos an die ganze Sache ran 
gegangen. Jetzt bastel ichs nochmal neu und hoffe, dass es dann besser 
klappt.

Aber danke soweit schonmal gell :)

von Maximilian (Gast)


Lesenswert?

Ok funktioniert soweit, danke nochmal.
Jetzt habe ich noch eine kleine Frage:
Und zwar möchte ich, dass solange der Sensor gedrückt wird die LED voll 
leuchtet und sobald der Benutzer runter geht, die PWM beginnt. Leider 
funktioniert es bei mir nur so, dass ich drücke und dann gleich die PWM 
beginnt. Habe das mit einer if (druck > bestimmter Wert) Abfrage 
gemacht:

if (Druck > bestimmter Wert1)
{
PORTB |= _BV(1);
}

if else (Druck < bestimmter Wert1) && (Druck > bestimmter Wert2))
{
for (i=0; i<1; i++) pwm_8_8(step_time/2);
}

else
{
PORTB &= 255-_BV(1); //  0 auf Bit 1 Ausgeben, Rest so lassen
}

}

Aber es mag nicht so wie ich will leider...

von Maximilian (Gast)


Lesenswert?

p.s.: die zweite Klammer bei der "else if" abfrage ist beim übertragen 
nur verschwunden, im prog schon drin

von Karl H. (kbuchegg)


Lesenswert?

> if (Druck > bestimmter Wert1)
> {
> PORTB |= _BV(1);
> }

Nochmal: Wenn die PWM den Pin unter ihrer Fuchtel hat, dann hat sie den 
auch unter ihrer Fuchtel. Da kannst du an den Portpin zuweisen, bis du 
schwarz wirst, das bewirkt gar nichts.
Wenn du die LED aufleuchten lassen willst, dann musst du ans OCR 
Register einen Wert zuweisen, der 'voll aufgedreht' bedeutet.

Daher ja auch die Reihenfolge
1
int main()
2
{
3
  Portpin auf Ausgang
4
5
  PWM konfigurieren
6
7
  PWM einschalten
8
9
  --- ab hier hat die PWM die Kontrolle über den Portpin ---
10
11
  while( 1 ) {
12
13
    Messen
14
15
    if( Messwert > Grenzwert )
16
      OCR1A = Wert für "Led volle Helligkeit"
17
18
    else if( Messwert < anderer Grenzwert )
19
      OCR1A = Wert für "LED dunkel"
20
21
    else
22
      PWM einmal durchdimmen
23
  }
24
}

nochmal im Klartext: vergiss den Portpin. Du hast keine Kontrolle mehr 
über den Portpin. Die Kontrolle hast du an den PWM-Mechanismus des 
Timers abgegeben. Also musst du auch mit diesem Mechanismus arbeiten. Du 
musst nur einen entsprechenden Wert ans OCR Register zuweisen und der 
Timer sorgt dann dafür, dass die LED auch mit dieser Helligkeit 
leuchtet.

von Maximilian (Gast)


Lesenswert?

Ahh ok :)
Dieser blöde Schlauch, dass der überall rum liegen muss.
Danke ;)

von Maximilian (Gast)


Lesenswert?

Ok, habs so umgebastelt, doch jetzt ist es so, dass wenn der obere 
Grenzwert überschritten wird, leuchten die leds, lass ich los fährt der 
µC auch die PWM, aber 2 mal hintereinander.
Danach springt er nur zufallsmäßig in die PWM nei, des hängt doch 
bestimmt mit dem Zähler zam oder? Kann ich den iwie modifizieren, dass 
der nach einer PWM stoppt und dann beim nächsten Aufruf wieder neu 
startet oder so?

p.S.: Bitte blöden Fragen verzeihen, bin noch bissi am hinein wurschteln 
:)

von Karl H. (kbuchegg)


Lesenswert?

Es ist wieder mal an der Zeit an etwas zu erinnern:

Wenn du qualifizierte Kommentare zu deinem Code willst, dann musst du 
den Code auch zeigen. Hier kann keiner wissen, wie und wodurch sich ein 
bestimmtes Verhalten in deinem Code ergibt, wenn man deinen Code nicht 
kennt.

Häng einfach dein C-File als Attachment an. Das ist für dich am 
einfachsten und für uns auch.

von Maximilian (Gast)


Angehängte Dateien:

Lesenswert?

Also ADC und PWM laufen alleine, nur das oben genannte Problem mag noch 
net so gern laufen

von Karl H. (kbuchegg)


Lesenswert?

Maximilian schrieb:

> Danach springt er nur zufallsmäßig in die PWM nei, des hängt doch
> bestimmt mit dem Zähler zam oder? Kann ich den iwie modifizieren, dass
> der nach einer PWM stoppt und dann beim nächsten Aufruf wieder neu
> startet oder so?

Dir scheint da etwas durcheinander zu kommen.

PWM  ist der Mechanismus, der es dir ermöglicht die LED auf jede 
beliebige Helligkeit zu setzen.

Das du den Mechanismus dazu benutzt, eine Aufleuchten und wieder 
Runterdimmen zu implementieren ist aber eine andere Sache. Das ist zwar 
nett, hat aber mit der PWM nur insofern zu tun, dass der Mechanismus die 
PWM benutzt um das zu realisieren.

Und wenn eine for-Schleife zu Ende ist, dann ist sie auch zu Ende.

von Karl H. (kbuchegg)


Lesenswert?

Maximilian schrieb:
> Also ADC und PWM laufen alleine, nur das oben genannte Problem mag noch
> net so gern laufen

OK. Ich seh mir das File jetzt nicht an. Ich hab extra noch 
dazugeschrieben: Häng das C-File so wie es ist als Attachment mit an. Du 
brauchst es weder umkopieren, du brauchst ihm auch keine andere 
Dateiendung zu geben. Du brauchst gar nichts tun, als das C-File (mit 
der Endung .c) so wie es ist als Attachment anzugeben. Das ist für dich 
supersimpel und hier im Forum löst das dann das Syntaxhighlighting für 
C-Files aus.

von Maximilian (Gast)


Angehängte Dateien:

Lesenswert?

Sorry

von Karl H. (kbuchegg)


Lesenswert?

1
  if (adcval > 30)
2
  {
3
    OCR1A = 0;  
4
  } 
5
  else if (adcval < 29)
6
  {
7
    OCR1A = 250;
8
  }
9
  else
10
  {
11
  for (i=0; i<1; i++) pwm_8_8(step_time/2);  
12
  }

du würdest dir leichter tun, wenn du dir endlich mal eine etwas 
vernünftige Form deines Codes angewöhnen würdest
1
    if (adcval > 30)
2
      OCR1A = 0;  
3
4
    else if (adcval < 29)
5
      OCR1A = 250;
6
7
    else
8
      pwm_8_8(step_time/2);

Eine Frage an dich:
Ohne jetzt kompliziert zu denken ... welchen Wert muss adcval haben, 
damit du jemals in die PWM Funktion reinkommst?


(UNd vergleich noch mal deinen Code mit dem Skelett von weiter oben. Wo 
hab ich die Initialisierung und Konfigurierung der PWM und wo hast du 
sie. Was muss daher gegeben sein, damit die LED überhaupt unter PWM 
Kontrolle steht?)

von Maximilian (Gast)


Lesenswert?

Meinst du jetzt den Wert bei dem Programm, wann er rein springt oder 
welchen ich haben möchte, ich beantworte einfach beides, geht 
schneller:)

Also der Sensor sitzt unter einem Silikonkissen und durch rumprobieren 
habe ich festgestellt, dass wenn man 30 als Richtwert nimmt, die Arbeit 
für den späteren Benutzer am besten ist.

Wenn ich es jetzt laufen lassen, dann ist es komischerweise nicht 
Wertabhängig sondern so bissi zufallsmäßig, also man kann 10 mal mit dem 
selben Druck draufdrücken (überprüfe es an der Widerstandsänderung übers 
Multimeter) und es leuchtet kurz auf und beim 11 mal fährt er wie 
gewollt die PWM.

von Karl H. (kbuchegg)


Lesenswert?

Maximilian schrieb:

> Also der Sensor sitzt unter einem Silikonkissen und durch rumprobieren
> habe ich festgestellt, dass wenn man 30 als Richtwert nimmt, die Arbeit
> für den späteren Benutzer am besten ist.


Der Wert wird aber höcht wahrscheinlich nicht ständig 30 sein. Je 
nachdem wie gut dein ADC die Referenzspannung gebuffert hat, ist er auch 
mal 29 oder 31. Und wenn der Sensor ein bischen rauscht, dann ist er 
auch mal 28 oder 32

Deine Hysterese, in der du die LED nur 'blinken' lässt, ist verdammt 
klein. Du willst doch haben, dass sie nur dann voll aufleuchtet, wenn 
jemand auf den Sensor draufdrückt. D.h. da kommt dann plötzlich ein 
extrem großer Wert vom ADC! Extrem groß ist zwar größer als 30, aber 31 
ist es auch.

von Maximilian (Gast)


Lesenswert?

Ja das ist schon sehr richtig.
Also die 30 ist nur son Richtwert-grenzwert: so fest soll der Benutzer 
quasi mindestens Drücken, damit die LEDs aufleuchten.

Aber die 2 Sachen was mir einfach nicht einleuchten wollen (hab die 
halbe Nacht dran rumgetüftelt, leider kein pos. Ergebniss), die PWM 
startet nicht immer, des macht den Eindruck, als müsste man den 
richtigen Zeitpunkt "treffen" und wenn ich diesen getroffen habe, dann 
fährt sie 2 mal und nicht nur 1 mal.
Woran kann das denn liegen?

von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

Maximilian schrieb:
> Ja das ist schon sehr richtig.
> Also die 30 ist nur son Richtwert-grenzwert: so fest soll der Benutzer
> quasi mindestens Drücken, damit die LEDs aufleuchten.

> startet nicht immer, des macht den Eindruck, als müsste man den
> richtigen Zeitpunkt "treffen" und wenn ich diesen getroffen habe, dann
> fährt sie 2 mal und nicht nur 1 mal.
> Woran kann das denn liegen?

Weil dein Wert vom ADC eben nicht 29 oder 30 ist.
Mach halt deine Hysterese mal ein bischen größer und erlaub einen 
größeren Toleranzbereich, in dem durchgedimmt werden soll.

Alternativ: Häng eine UART an und lass dir die Werte vom ADC mal 
ausgeben, damit du selber mal siehst, dass die Werte eben nicht so schön 
sind, wie du dir das in Gedanken vorstellst. Die werden ein wenig 
schwanken. Und diese Schwankungen must du zumindest in den Grenzwerten 
berücksichtigen, damit dir die Funktionalität da nicht dauernd aus einem 
Bereich in den anderen wechselt.

Dein ADC liefert Werte von 0 bis 1023 für 0 bis 2.56V
D.h. eine Schwankung des ADC Wertes von 2 entspricht einer Änderung der 
Spannung von 5 MILLI-Volt! 5-tausendstel Volt. Ist dein Sensor wirklich 
so rauschfrei? Die reale Welt ist nicht so ideal, wie du dir das 
vorstellst.

von Maximilian (Gast)


Lesenswert?

Jo ich glaub ich schau mir des mal über ne UART an, vielleicht stell ich 
mich dann nimmer ganz so blöd an...

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.