www.mikrocontroller.net

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


Autor: Emanuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>  // fuer Interrupts

 
int main( void )
{

  // OC1A  auf Ausgang  
  DDRD = ( 1<<PD5 );        // PD5 an PORTD als Ausgang setzen
//  PORTD = ( 1<<PD5 );

  //
  // Timer 1 einstellen
  //  
  // Modus 12:
  //    CTC, Top von ICR1
  //
  //    WGM13    WGM12   WGM11    WGM10
  //      1        1       0        0
  //
  //    Timer Vorteiler: 8
  //     CS12     CS11    CS10
  //       0        0       1
  //
  //    nicht-invertierende PWM:
  //    COM1A1  COM1A0
  //      1    0


  TCCR1A = (0<<WGM11)| (0<<WGM10) | (1<<COM1A1) | (0<<COM1A0);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (0<<CS12) |(0<<CS11) | (1<<CS10);


  //  den Endwert (TOP) für den Zähler setzen
  //  der Zähler zählt bis zu diesem Wert

  ICR1 = 0x32; // 50


  // der Compare Wert
  // Wenn der Zähler diesen Wert erreicht, wird mit
  // obiger Konfiguration der OC1A Ausgang abgeschaltet
  // Sobald der Zähler wieder bei 0 startet, wird der
  // Ausgang wieder auf 1 gesetzt
  //
  // Durch Verändern dieses Wertes, werden die unterschiedlichen
  // PWM Werte eingestellt.

  OCR1A = 0x30;

  return 0;

}

Autor: Emanuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
edit:
Der interne RC läuft mit 1 MHz.

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Emanuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Weßels (swessels)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Weßels (swessels)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Emanuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan Weßels (swessels)
Datum:

Bewertung
0 lesenswert
nicht 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:

/*
2-Kanal PWM-Steuerung
MCU: ATtiny 25
Takt: 8MHz
PWM an PB0, PB1 (OC0A, OC0B)
ADC an PB3, PB4 (ADC3, ADC2)
*/

#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
    #define F_CPU 8000000UL
#endif


volatile uint8_t flag;
uint8_t get_ADC(uint8_t channel);

int main(void){

    //PB 0,1 auf Ausgang
    DDRB |= 1 << PB0 | 1 << PB1;

    //ADC Referenz Vcc , Left Adjusted, Single Ended, prescaler 16
    ADMUX |= 1 << ADLAR;
    ADCSRA |= 1 << ADPS2;
    ADCSRA |= 1 << ADEN;

    //Timer 0 Mode 3 (FastPWM), Prescaler 256 => Fpwm ~ 122 Hz, Overflow Interrupt
    //enable, Output Compare A und B ein
    TCCR0A |= 1 << COM0A1 | 1 << COM0B1 | 1 << WGM01 | 1 << WGM00;
    TIMSK |= 1 << TOIE0;
    OC0A = 0;
    OC0B = 0;
    TCCR0B |= 1 << CS02;

    sei();

    flag = 1;

    while(1){
        if(flag == 1){
            //zuweisen der ADC-Werte an die Output-Compare Register
            OCR0A = get_ADC(2);
            OCR0B = get_ADC(3);
            flag = 0;
        }
        set_sleep_mode(SLEEP_MODE_IDLE);
        sleep_mode();
    }

    return(1);
}

uint8_t get_ADC(uint8_t channel){

    //Zwischenspeicher
    uint16_t buffer;
    uint8_t i;

    buffer = 0;

    //ADC Kanal wählen
    ADMUX=(ADMUX &~(0x1F)) | (channel & 0x1F);

    //4 Messungen mit Mittelwertbildung
    for(i = 0; i < 4; i++){
        ADCSRA = 1 << ADSC;
        while(ADCSRA & (1 << ADSC));
        buffer += ADCH;
    }
    //buffer durch 4 teilen und zurückgeben
    return(buffer >> 2);
}
ISR(TIMER0_OVF_vect){
    flag = 1;
}

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

Gruß,
Stefan

Autor: Emanuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.