Forum: Mikrocontroller und Digitale Elektronik CTC Verständnisproblem -> PWM-Modus?


von Emanuel (Gast)


Lesenswert?

Hallo allerseits,

ich hatte mal ein bisschen mit uCs rumgespielt, aber bin nicht weit 
gekommen. Nun habe ich ein Projekt im Kopf, bei dem ich gerne LEDs via 
PWM steuern will.
Da soll die Taktrate folgende sein: 1ms Impuls alle 10 ms. Also 1ms an, 
9ms aus, etc.
Dabei soll am Ende, bzw. muss (!) der Abstand der Impulse über einen 
Poti steuerbar sein. D.h. drehen bedeutet längere Zeiten zwischen den 
An-Zeiten. An einem weiteren Poti würde ich gerne noch ein Delay 
einbauen, soll heißen, wenn man daran dreht, verschieben sich die 
Impulse in der Zeit nach vorne/hinten, was nichts anderes wäre, als ein 
paar Mal die Aus-Zeit zu verlängern bzw. zu verkürzen.

Nun dachte ich, dass das ganze mit der CTC-PWM sehr gut machbar wäre, da 
ich hier ja per Interrupt immer wieder die Impulsdauer etc. nachregeln 
kann.
Ich habe einen ATMega 644P, der zwar ziemlich überdimensioniert ist, 
aber eben gerade vorhanden.

Ich scheitere schon beim Anfang:
Ich habe das Datenblatt natürlich durchgelesen und auch schon mal eine 
PWM erstellt, allerdings noch keine CTC und irgendwie will das hier 
nicht. Ihr könnte mir gerne meinen absoluten Anfängerfehler aufzeigen 
und/oder mir andere/bessere Möglichkeiten für mein Vorhaben nennen. Den 
Eingang für die Potis (auf den ADC darf ja nur ein Eingangspin 
geschaltet sein) würde ich per Taster und Interrupt switchen.

Vielen Dank für Eure Hilfe!!

Hier mal der Code


1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>  // fuer Interrupts
4
5
 
6
int main( void )
7
{
8
9
  // OC1A  auf Ausgang  
10
  DDRD = ( 1<<PD5 );        // PD5 an PORTD als Ausgang setzen
11
//  PORTD = ( 1<<PD5 );
12
13
  //
14
  // Timer 1 einstellen
15
  //  
16
  // Modus 12:
17
  //    CTC, Top von ICR1
18
  //
19
  //    WGM13    WGM12   WGM11    WGM10
20
  //      1        1       0        0
21
  //
22
  //    Timer Vorteiler: 8
23
  //     CS12     CS11    CS10
24
  //       0        0       1
25
  //
26
  //    nicht-invertierende PWM:
27
  //    COM1A1  COM1A0
28
  //      1    0
29
30
31
  TCCR1A = (0<<WGM11)| (0<<WGM10) | (1<<COM1A1) | (0<<COM1A0);
32
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (0<<CS12) |(0<<CS11) | (1<<CS10);
33
34
35
  //  den Endwert (TOP) für den Zähler setzen
36
  //  der Zähler zählt bis zu diesem Wert
37
38
  ICR1 = 0x32; // 50
39
40
41
  // der Compare Wert
42
  // Wenn der Zähler diesen Wert erreicht, wird mit
43
  // obiger Konfiguration der OC1A Ausgang abgeschaltet
44
  // Sobald der Zähler wieder bei 0 startet, wird der
45
  // Ausgang wieder auf 1 gesetzt
46
  //
47
  // Durch Verändern dieses Wertes, werden die unterschiedlichen
48
  // PWM Werte eingestellt.
49
50
  OCR1A = 0x30;
51
52
  return 0;
53
54
}

von Emanuel (Gast)


Lesenswert?

edit:
Der interne RC läuft mit 1 MHz.

von Spess53 (Gast)


Lesenswert?

Hi

>Nun dachte ich, dass das ganze mit der CTC-PWM sehr gut machbar wäre,...

CTC-PWM gibt es nicht.

CTC erzeugt eine Frequenz mit einem Tastverhältnis von 1:1
PWM erzeugt eine Frequenz mit variablen Tastverhältnis.

Es gibt aber z.B. die Timermode 14 und 15 (WGM13:10= 1110/1111) bei 
denen die Frequenz über ICR1 oder OCR1A eingestellt wird und das 
Tastverhältnis über OCR1A/B bzw. OCR1B bestimmt wird.

MfG Spess

von Emanuel (Gast)


Lesenswert?

Danke für die schnelle Antwort! Sowas konnte ich wohl so schnell nicht 
aus dem Tutorial oder Datenblatt herauslesen ;).

Hat jemand dann noch direkt einen passenden Tip oder Code, wie ich mit 
der internen RC-Frequenz (1 MHz) diese PWM, wie oben beschrieben, 
einstellen kann? Also dass ich eben die LEDs takte mit 1ms an, 9ms aus, 
usw.
Es muss nicht zeitkritisch sein, also Uhrwerk-genau, nur sollte es grob 
passen. Gibt es dazu Bib-Funktionen oder wird das dann über den 
Prescaler einfach eingestellt?

Grüße

von Stefan W. (swessels)


Lesenswert?

Spess53 schrieb:
> CTC erzeugt eine Frequenz mit einem Tastverhältnis von 1:1

Wieso das? Wenn ich den CTC Mode richtig verstehe kann ich das 
Tastverhältnis über den Comparewert festlegen. Der Nachteil ist nur das 
die Werte in OCRx jederzeit geändert werden können, während in den PWM 
Modi zunächst zwischengespeichert wird und OCRx zu einem definierten 
Zeitpunkt geändert wird.

Daher stelle ich mir die Frage, wozu der CTC-Mode überhaupt benötigt 
wird. Oder benötigen die PWM Modi wesentlich  mehr Zeit bzw. Speicher?

Gruß,
Stefan

von spess53 (Gast)


Lesenswert?

Hi

Im CTC-Mode zählt der Timer bis zum OC-Wert und fängt dann von Null 
wieder an. Am Comparezeitpunkt wird die dur COMxY1:0 festgelegte Aktion 
am OC-Pin ausgelöst.

Ich beschränke mich mal auf Fast PWM. Dort löst der Timer bei Erreichen 
des OC-Wertes die Aktion aus, zählt aber bis Top weiter. Erst dann wird 
wieder bei Null angefangen.

D.h. um mit CTC eine PWM zu erzeugen müsstest du bei jedem Erreichen des 
OC-Wertes einen neuen Wert reinschreiben. In einem PWM-Mode gibst du 
einmal den Compare-Wert und den Top-Wert vor und das Ganze läuft 
selbständig bis du z.B. ein anderes Tastverhältnis haben willst.

MfG Spess

von Stefan W. (swessels)


Lesenswert?

Ich habe mich mit dem CTC Mode nie wirklich beschäftigt, da die Gefahr 
besteht den OCRx Registern zum falschen Zeitpunkt neue Werte zu 
übergeben. Wenn ich PWM benötige benutze ich auch die PWM Modi.

Aber mal rein zu meinem Verständnis:

Die Auflösung des Timers (Beispiel Tiny24 Timer 1) kann mittels mittels 
OCR1A oder ICR1 festgelegt werden.
Somit kann ich doch bei TOP = ICR1 an OCR1A / OCR1B ein variables 
Tastverhältnis erreichen?

Gruß,
Stefan

von Karl H. (kbuchegg)


Lesenswert?

Stefan Weßels schrieb:

> Die Auflösung des Timers (Beispiel Tiny24 Timer 1) kann mittels mittels
> OCR1A oder ICR1 festgelegt werden.
> Somit kann ich doch bei TOP = ICR1 an OCR1A / OCR1B ein variables
> Tastverhältnis erreichen?

Ja, kannst du

von Emanuel (Gast)


Lesenswert?

Danke nochmals für die Antworten!

Kann ich in (irgendeiner) PWM Mode auch einfach, während er läuft, mit 
z.B. einem Poti den Compare-Wert bzw. den TOP-Wert ändern? Brauche ich 
hierfür interrupts oder gibt es eine elegante Möglichkeit (Code?), mit 
einem Poti, programmtechnisch klein gerastert, den Wert einfach so 
einzustellen?

MfG

von spess53 (Gast)


Lesenswert?

Hi

>Kann ich in (irgendeiner) PWM Mode auch einfach, während er läuft, mit
>z.B. einem Poti den Compare-Wert bzw. den TOP-Wert ändern?

Wenn dein AVR einen ADC besitzt, kein Problem. Die Potis an den ADC 
anschliessen. Spannung messen und nach passender Umrechnung die 
entsprechenden laden.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Emanuel schrieb:

> Kann ich in (irgendeiner) PWM Mode auch einfach, während er läuft, mit
> z.B. einem Poti den Compare-Wert bzw. den TOP-Wert ändern?

Natürlich kannst du.
Lern bitte mit deinem Datenblatt zu arbeiten.

> Brauche ich
> hierfür interrupts oder gibt es eine elegante Möglichkeit (Code?),

Noch eleganter als einfache Registerzuweisung?

von Stefan W. (swessels)


Lesenswert?

Emanuel schrieb:
> Kann ich in (irgendeiner) PWM Mode auch einfach, während er läuft, mit
> z.B. einem Poti den Compare-Wert bzw. den TOP-Wert ändern?

Kannst Du z.B. so:

1
/*
2
2-Kanal PWM-Steuerung
3
MCU: ATtiny 25
4
Takt: 8MHz
5
PWM an PB0, PB1 (OC0A, OC0B)
6
ADC an PB3, PB4 (ADC3, ADC2)
7
*/
8
9
#include <avr/io.h>
10
#include <avr/interrupt.h>
11
12
#ifndef F_CPU
13
    #define F_CPU 8000000UL
14
#endif
15
16
17
volatile uint8_t flag;
18
uint8_t get_ADC(uint8_t channel);
19
20
int main(void){
21
22
    //PB 0,1 auf Ausgang
23
    DDRB |= 1 << PB0 | 1 << PB1;
24
25
    //ADC Referenz Vcc , Left Adjusted, Single Ended, prescaler 16
26
    ADMUX |= 1 << ADLAR;
27
    ADCSRA |= 1 << ADPS2;
28
    ADCSRA |= 1 << ADEN;
29
30
    //Timer 0 Mode 3 (FastPWM), Prescaler 256 => Fpwm ~ 122 Hz, Overflow Interrupt
31
    //enable, Output Compare A und B ein
32
    TCCR0A |= 1 << COM0A1 | 1 << COM0B1 | 1 << WGM01 | 1 << WGM00;
33
    TIMSK |= 1 << TOIE0;
34
    OC0A = 0;
35
    OC0B = 0;
36
    TCCR0B |= 1 << CS02;
37
38
    sei();
39
40
    flag = 1;
41
42
    while(1){
43
        if(flag == 1){
44
            //zuweisen der ADC-Werte an die Output-Compare Register
45
            OCR0A = get_ADC(2);
46
            OCR0B = get_ADC(3);
47
            flag = 0;
48
        }
49
        set_sleep_mode(SLEEP_MODE_IDLE);
50
        sleep_mode();
51
    }
52
53
    return(1);
54
}
55
56
uint8_t get_ADC(uint8_t channel){
57
58
    //Zwischenspeicher
59
    uint16_t buffer;
60
    uint8_t i;
61
62
    buffer = 0;
63
64
    //ADC Kanal wählen
65
    ADMUX=(ADMUX &~(0x1F)) | (channel & 0x1F);
66
67
    //4 Messungen mit Mittelwertbildung
68
    for(i = 0; i < 4; i++){
69
        ADCSRA = 1 << ADSC;
70
        while(ADCSRA & (1 << ADSC));
71
        buffer += ADCH;
72
    }
73
    //buffer durch 4 teilen und zurückgeben
74
    return(buffer >> 2);
75
}
76
ISR(TIMER0_OVF_vect){
77
    flag = 1;
78
}

Der Sleepmode und die ISR sind für die Funktion nicht relevant.

Gruß,
Stefan

von Emanuel (Gast)


Lesenswert?

Hi,

Vielen Dank für diesen Code, das hat mir sehr weitergeholfen!

Allerdings habe ein ein kleines Problem:

Mit der FastPWM kann ich offenbar nicht den TOP-Wert verändern. Meine 
Anforderung ist aber, die Aus-Zeit der LEDs zu verlängern, ohne die 
An-Zeit zu verkürzen. Hierzu müsste ich doch eine andere PWM nehmen oder 
nicht?

Mit zwei Potis will ich am Ende auf folgendes zugreifen:
Drehen am einen Poti - Den ganzen Takt nach "hinten" bzw. "vorne" 
verschieben.
Drehen am anderen Poti - Die Pausen verlängern.

Das ganze soll für eine Time-Fountain sein: 
http://www.cre.ations.net/creation/the-time-fountain

Grüße

von Karl H. (kbuchegg)


Lesenswert?

Emanuel schrieb:

> Allerdings habe ein ein kleines Problem:
>
> Mit der FastPWM kann ich offenbar nicht den TOP-Wert verändern. Meine
> Anforderung ist aber, die Aus-Zeit der LEDs zu verlängern, ohne die
> An-Zeit zu verkürzen. Hierzu müsste ich doch eine andere PWM nehmen oder
> nicht?

Ja.
Gibt ja noch genug andere Modi.
Im Datenblatt ist eine schöne Tabelle in der alle Modi aufgeschlüsselt 
sind. Dort steht auch jeweils dabei, wodurch der TOP Wert festgelegt 
wird. Da gibt es welche mit fixem Top-Wert (die sog. Fast-PWM) aber es 
gibt auch welche, in denen ein Register den Top-Wert vorgibt

von spess53 (Gast)


Lesenswert?

Hi

'Fast PWM' hat nichts mit festem Top-Wert zu tun. Im Datenblatt findest 
du bei jedem Timer einen Abschnitt 'Modes of Operation'. Da steht, was 
der Timer alles kann.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

spess53 schrieb:
> Hi
>
> 'Fast PWM' hat nichts mit festem Top-Wert zu tun.

Mein Fehler.
Du hast natürlich recht. Bei Fast-PWM geht es um die Art und Weise wie 
der Timer zählt.

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.