Forum: Mikrocontroller und Digitale Elektronik PWM Ein- und Ausschalten und Interrupts verursacht Probleme


von nicht Gast (Gast)


Lesenswert?

Hallo, ich habe ein kleines Problem:

Mein Atmega8 soll ein PWM-Signal erzeugen, welches zur Laufzeit ein- und 
ausschaltbar sein soll. Das PWM läuft mit dem Timer1 (Toggle on Compare 
Match)...

Gleichzeitig habe ich eine AD-Wandlung in der ISR laufen. Wenn ich die 
Interrupts (sei() ) nicht aktiviert habe, habe ich keine Probleme. 
Sobald jeadoch sei() gemacht wird, kommt beim BEENDEN des PWMs eine Art 
"Glitch", die Signalform sieht beim letzten Puls ungefähr so aus:

__|''|__|''|__|''|__|'''''''''|____________________


Beendet wird das PWM bei mir zunächst dadurch, dass das Register ICR1 = 
0 gesetzt wird. Dadurch stoppt es auch. Zusätzlich setze ich den Pin, 
über den das PWM ausgegeben wird als als Eingang. Das Problem tritt in 
beiden Fällen auf. Auch ein vorheriges cli() bringt keine Verbesserung, 
das Problem besteht weiterhin. Nur wenn ich die Interrupts gar nicht 
erst aktiviere, tritt der Fehler nicht auf.

Wie wird eigentlich das PWM korrekterweise beendet, habe ich es 
überhaupt richtig gemacht?

Ich hoffe dass es so halbwegs verständlich ist was ich sagen wollte ;)

Weiss einer, was ich falsch mache?... Würde mich über jeden Ratschlag 
freuen, thx!

von Sascha W. (sascha-w)


Lesenswert?

zeig mal komplett wie du deinen Timer konfigurierst!
Um die PWM abzuschalten ist das einfachste den OCx-Pin vom Timer 
abzukoppeln, damit ist für den Pin wieder die Einstellung DDRx und PORTx 
wirksam.

Sascha

von nicht Gast (Gast)


Lesenswert?

hallo Sascha!

der Timer wird bei mir so konfiguriert:


TCCR1A |= 1<<WGM11 | 1<<COM1A1 | 1<<COM1A0;
TCCR1B |= 1<<WGM12 | 1<<WGM13  | 1<<CS10;

das mit dem abkoppeln OCx habe ich noch nicht probiert, dafür das 
Abschalten von CSx, hat auch funktioniert jedoch brachte das keine 
Besserung..

von STK500-Besitzer (Gast)


Lesenswert?

nicht Gast schrieb:
> Hallo, ich habe ein kleines Problem:
>
> Mein Atmega8 soll ein PWM-Signal erzeugen, welches zur Laufzeit ein- und
> ausschaltbar sein soll. Das PWM läuft mit dem Timer1 (Toggle on Compare
> Match)...
>
> Gleichzeitig habe ich eine AD-Wandlung in der ISR laufen. Wenn ich die
> Interrupts (sei() ) nicht aktiviert habe, habe ich keine Probleme.

Sei() in der ISR? Son Quatsch!

> Beendet wird das PWM bei mir zunächst dadurch, dass das Register ICR1 =
> 0 gesetzt wird. Dadurch stoppt es auch. Zusätzlich setze ich den Pin,
> über den das PWM ausgegeben wird als als Eingang.

In welcher ISR verwendest du den ADC? Name?


Zeig einfach dein Programm! Das ist immer besser als rumzustochern.
Es liegt definitv am Programm!

von nicht Gast (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> nicht Gast schrieb:
>> Hallo, ich habe ein kleines Problem:
>>
>> Mein Atmega8 soll ein PWM-Signal erzeugen, welches zur Laufzeit ein- und
>> ausschaltbar sein soll. Das PWM läuft mit dem Timer1 (Toggle on Compare
>> Match)...
>>
>> Gleichzeitig habe ich eine AD-Wandlung in der ISR laufen. Wenn ich die
>> Interrupts (sei() ) nicht aktiviert habe, habe ich keine Probleme.
>
> Sei() in der ISR? Son Quatsch!

sorry das war ein missverständnis, das sei() steht natürlich nicht in 
der ISR sondern in der main()

STK500-Besitzer schrieb:
>> Beendet wird das PWM bei mir zunächst dadurch, dass das Register ICR1 =
>> 0 gesetzt wird. Dadurch stoppt es auch. Zusätzlich setze ich den Pin,
>> über den das PWM ausgegeben wird als als Eingang.
>
> In welcher ISR verwendest du den ADC? Name?

Es war die ADC_Vect....
Leider habe ich den Stick mit dem Programm nicht bei mir :( Dass es am 
Programm liegt denke ich ja auch..

von Sascha W. (sascha-w)


Lesenswert?

nicht Gast schrieb:
> hallo Sascha!
>
> der Timer wird bei mir so konfiguriert:
>
> TCCR1A |= 1<<WGM11 | 1<<COM1A1 | 1<<COM1A0;
> TCCR1B |= 1<<WGM12 | 1<<WGM13  | 1<<CS10;

ok - Fast-PWM mit ICR als TOP-Wert

> das mit dem abkoppeln OCx habe ich noch nicht probiert, dafür das
> Abschalten von CSx, hat auch funktioniert jedoch brachte das keine
> Besserung..
du kannst den Ausgang abschalten indem du COM1A0 und COM1A1 auf Null 
setzt, dann läuft die PWM intern weiter am Controllerpin tut sich nix 
mehr.
Wenn du die CS-Bit's auf Null setzt dann bleit der Timer an der Stelle 
stehen und damit sollte sich auch am Ausgang nichts ändern. Eine 
Änderung von OC1x oder ICR könnte aber u.U. eine Änderung des 
Ausgangszustands hervorrufen.

Ohne dein Program kommen wir hier nicht weiter.

Sascha

von nicht Gast (Gast)


Lesenswert?

Hallo, ich habe mich heute noch ein wenig mit dem Programm beschäftigt, 
hab es euch auch angehängt.. (ist natürlich noch Work in Progress, also 
noch alles andere als Fertig..)..
1
#ifndef F_CPU
2
#define F_CPU 4000000UL
3
#endif
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7
8
static volatile int analog, frequenz, strom = 0;
9
int pwm = 0;
10
11
int main(void)  {
12
  //Ausgang fuer die PWM
13
  DDRB |= 1<<PINB1;    
14
  //Timer initialisiern      
15
  TCCR1A |= 1<<WGM11 | 1<<COM1A1 | 1<<COM1A0;
16
  TCCR1B |= 1<<WGM12 | 1<<WGM13  | 1<<CS10;  
17
  //AD-Wandler initialisieren
18
  ADCSRA |= 1<<ADPS2 | 1<<ADPS1; 
19
  ADMUX |= 1<<REFS0;  
20
  ADCSRA |= 1<<ADIE;  
21
  ADCSRA |= 1<<ADEN;  
22
  
23
  sei();  
24
  ADCSRA |= 1<<ADSC;  
25
  //2 Sekunden warten
26
  for(int i = 0; i < 2; i++)  {
27
    _delay_ms(1000);
28
  }
29
  //PWM starten...
30
  uint8_t zaehler = 40;
31
  OCR1A = zaehler/2;  //Wert für den Tastgrad, für 50 % eingestellt
32
  ICR1 = zaehler;  //Wert für die Periode
33
  //5 Sekunden Warten...
34
  for(int i = 0; i < 5; i++)  {
35
    _delay_ms(1000);
36
  }
37
  //PWM ausschalten mit unterschiedlichen Methoden...
38
  cli();
39
  TCCR1B &= ~(1<<CS10);
40
  ICR1 = 0;
41
  OCR1A = 0;
42
  DDRB &= ~(1<<PINB1);  
43
44
    while(1);  
45
  return 0;
46
}
47
48
ISR(ADC_vect)  {  
49
  //Auslesen des AD-Wandlers mit 10 bit
50
  uint8_t lowByte = ADCL;  
51
  analog = ADCH<<8 | lowByte;  
52
  //Umaschalten zwischen 2 Kanälen
53
  switch(ADMUX)  {
54
    case 0x40:  
55
      ADMUX = 0x41;
56
      strom = analog;
57
      break;
58
    
59
    case 0x41:  
60
      ADMUX = 0x40;
61
      frequenz = analog;
62
      break;
63
      
64
    default:
65
      break;  
66
  }
67
  ADCSRA |= 1<<ADSC;  // Nächste AD-Wandlung starten
68
}

Momentan soll das PWM über das _delay() eine Zeit lang am Leben gehalten 
werden, später wird das dann durch einen Analogwert ersetzt. Bei dem 
_delay() ist mir aufgefallen, dass es nicht bei allen Werten dieses 
Problem gibt.. Bei einem Delay von 5 Sekunden z.B. habe ich den Fehler, 
bei 4 Sekunden wiederum nicht.. Könnte es eventuell nur an der 
_delay()-Funkton liegen? eine andere Möglichkeit der zeitlichen 
Veränderung kann ich momentan leider schlecht testen...

thx!

von Karl H. (kbuchegg)


Lesenswert?

nicht Gast schrieb:

>   //PWM ausschalten mit unterschiedlichen Methoden...
>   cli();
>   TCCR1B &= ~(1<<CS10);
>   ICR1 = 0;
>   OCR1A = 0;


damit hast du erst mal nur den Timer angehalten.
Aber: Die Ausgabepins sind immer noch an den Timer gekoppelt, der sie 
unter seiner Fuchtel hat.
Und solange du das hier

  TCCR1A |=  ..... 1<<COM1A1 | 1<<COM1A0 .....

nicht rückgängig machst, bleibt das auch so.
Erst indem du die Pins durch Abschalten der COM... Bits wieder vom Timer 
entkoppelt hast, kriegst du wieder die Kontrolle darüber.

von nicht Gast (Gast)


Lesenswert?

Hallo, ich glaube das hat jetzt gewirkt. Wenn ich die COM pins 
abschalte, dann scheint das PWM bisher immer korrekt abzuschalten. Ist 
es dann eigentlich notwendig, den Timer noch zu stoppen bzw noch auf 
andere Weise sicherzustellen dass der Pin, an dem das PWM ausgegeben 
wird, nicht doch noch verrückt spielt?

von Sascha W. (sascha-w)


Lesenswert?

nicht Gast schrieb:
> Hallo, ich glaube das hat jetzt gewirkt. Wenn ich die COM pins
> abschalte, dann scheint das PWM bisher immer korrekt abzuschalten. Ist
> es dann eigentlich notwendig, den Timer noch zu stoppen bzw noch auf
> andere Weise sicherzustellen dass der Pin, an dem das PWM ausgegeben
> wird, nicht doch noch verrückt spielt?
den Timer kannst du im Hintergrund ruhig weiterlaufen lassen, sind die 
COM-Bits auf 0 dann hat der Pin den durch DDRx,PORTx vorgegebenen 
Zustand.
Auch anhalten den Timers mit CSxy=0 sollte die PWM sicher stoppen, 
allerdings sollte man dann die ICR, OCR Register nicht mehr ändern.

Sascha

von nicht Gast (Gast)


Lesenswert?

ok das klingt schonmal gut. Dann würde ich den Pin anfangs auf 0 setzen, 
denn meine einzige Sorge ist, dass er irgendwann auf 1 geht und dort 
bleibt, das wäre für meine Anwendung nicht so gut!


danke schonmal!

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.