PWM Ein- und Ausschalten und Interrupts verursacht Probleme

Gast #2634789
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!
Gast #2635174
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..
Gast #2635185
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!
Gast #2636544
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..
#2637314
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
Gast #2638807
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!
#2638829
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.
Gast #2639807
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?
#2640340
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
Gast #2640807
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!

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.