- Reichelt Elektronik    Werbung      
Ergebnis 1 bis 3 von 3

Thema: PWM Generator bis 100kHz

  1. #1
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.297

    PWM Generator bis 100kHz

    Anzeige

    E-Bike
    Ich arbeite zur Zeit an einem PWM Generator, der Frequenzen von 1Hz bis 100kHz mit einer Pulsweiten Auflösung von 0,5% erzeugen kann.
    Als Basis dient ein AVR32DB28 Controller und als Treiber hab Ich einen L293D geplant. Als Display hab Ich ein 128x64 OLED Display mit SSD1306 Controller auf I2C.
    Als Stromversorgung werde Ich wohl ein einstellbares Steckernetzteil nehmen.

    Die Frequenzeinstellung hab Ich per Drehencoder mit Drucktaste gemacht.
    Die Drucktaste verstellt die Dezimalstelle, der Drehencoder inkrementiert oder dekrementiert dann die ausgewählte Stelle.

    Für die Pulsweite habe Ich ein Spindelpoti mit 5k Ohm Widerstand benutzt ( 10k sollte auch funktionieren ).

    Es läuft eigentlich schon alles. Die Frequenz stimmt noch nicht ganz genau - Ich denk mal, das liegt an der Benutzung der internen 24MHz Quelle des AVR32DB.
    Die Pulsweiteneinstellung bei den Prozentwerten suggeriert eine Genauigkeit, die so nicht ganz stimmt. Die Zeitwerte in us kommen aber gut hin.
    Der L293D verarbeitet keine Impulse mehr die kürzer als 1us sind, aber damit kann Ich leben.
    Der Ausgangspegel geht bis knapp unter die Betriebsspannung, die maximal 30V beträgt ( 36V lt. Datenblatt ).
    Beim Spannungsregler für die 5V Seite muss man aufpassen, das der Spannungsregler auch die 36V am Eingang verträgt (TSR 1-2450 ?).
    Die Schaltung zieht zur Zeit 60mA ohne Last.


    Bild  
    10kHz mit 50% Duty Cycle
    Bild  
    Aktueller Versuchsaufbau
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken Oszillogramm.jpg   Ver_Aufbau.jpg  
    Geändert von wkrug (Heute um 07:26 Uhr)

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.723
    Hallo,

    Zitat Zitat von wkrug Beitrag anzeigen
    Die Frequenzeinstellung hab Ich per Drehencoder mit Drucktaste gemacht.
    Die Drucktaste verstellt die Dezimalstelle, der Drehencoder inkrementiert oder dekrementiert dann die ausgewählte Stelle.
    Hört sich an, als wenn die Frequenz in 1 Hz Schrittweiten einstellbar wäre. Wie bekommst Du das hin und mit welcher Peripherie des AVR32DB28?

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  3. #3
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.297
    Code:
    // Enuberation für 1 bis 10000
    enum incs
    {
        ones = 1,
        tens = 10,
        hundrets = 100,
        thousends = 1000,
        tenthousends = 10000    
    };
    
    
    
    
    // Globale Variable für das aktuelle PER-Register
    static volatile uint16_t current_per = 240;
    
    
    
    uint8_t pwm_set_frequency(uint32_t freq_hz) {
        // Sicherheitsgrenzen prüfen
        if (freq_hz < 1 || freq_hz > 100000) {
            return 0; // Fehler: Frequenz außerhalb des erlaubten Bereichs
        }
    
        uint32_t ticks = 0;
        uint8_t clk_sel = 0;
    
        // Timer stoppen für glitchfreies Umschalten
        uint8_t ctrla_backup = TCA0.SINGLE.CTRLA;
        TCA0.SINGLE.CTRLA &= ~TCA_SINGLE_ENABLE_bm;
    
        // Dynamische Berechnung des optimalen Prescalers bei 24 MHz
        if (freq_hz >= 367) {
            ticks = F_CPU / freq_hz;
            clk_sel = TCA_SINGLE_CLKSEL_DIV1_gc;
            } else if (freq_hz >= 92) {
            ticks = (F_CPU / 4) / freq_hz;
            clk_sel = TCA_SINGLE_CLKSEL_DIV4_gc;
            } else if (freq_hz >= 46) {
            ticks = (F_CPU / 8) / freq_hz;
            clk_sel = TCA_SINGLE_CLKSEL_DIV8_gc;
            } else if (freq_hz >= 23) {
            ticks = (F_CPU / 16) / freq_hz;
            clk_sel = TCA_SINGLE_CLKSEL_DIV16_gc;
            } else if (freq_hz >= 6) {
            ticks = (F_CPU / 64) / freq_hz;
            clk_sel = TCA_SINGLE_CLKSEL_DIV64_gc;
            } else if (freq_hz >= 2) {
            ticks = (F_CPU / 256) / freq_hz;
            clk_sel = TCA_SINGLE_CLKSEL_DIV256_gc;
            } else {
            ticks = (F_CPU / 1024) / freq_hz;
            clk_sel = TCA_SINGLE_CLKSEL_DIV1024_gc;
        }
    
        // Das Periodenregister schreiben
        current_per = (uint16_t)(ticks - 1);
        TCA0.SINGLE.PER = current_per;
    
        // Neuen Prescaler in CTRLA schreiben
        TCA0.SINGLE.CTRLA = (TCA0.SINGLE.CTRLA & ~TCA_SINGLE_CLKSEL_gm) | clk_sel;
    
        // Timer wieder starten, falls er vorher lief
        TCA0.SINGLE.CTRLA |= (ctrla_backup & TCA_SINGLE_ENABLE_bm);
    
        return 1; // Erfolg
    }
    
    void pwm_set_duty_cycle_percent(float percent) {
        if (percent < 0.0) percent = 0.0;
        if (percent > 100.0) percent = 100.0;
    
        // Berechnung des Registerwertes basierend auf der aktuellen Periode
        uint16_t cmp_value = (uint16_t)((percent / 100.0) * current_per);
        
        // Vergleichsregister für Kanal 0 beschreiben (Gibt das Signal nun auf PA0 aus)
        if(percent >= 100)cmp_value++;
        TCA0.SINGLE.CMP0 = cmp_value;
    }
    
    void pwm_init(void) {
        // 1. PORTMUX konfigurieren: TCA0-Ausgang WO0 von PORTA auf PORTC umleiten
        // Das Bitfeld TCA0_bm in PORTMUX.TCAROUTEA steuert das Routing für TCA0
        //PORTMUX.TCAROUTEA = PORTMUX_TCA0_PORTC_gc;
    
        // 2. Pin PC0 (WO0) als Ausgang definieren
        PORTA.DIRSET = PIN0_bm;
    
        // 3. TCA0 im Single-Slope PWM Modus konfigurieren (WGMODE = SINGLESLOPE)
        TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc | TCA_SINGLE_CMP0EN_bm;
    
        // 4. Standardfrequenz beim Start setzen (z. B. 1 kHz)
        pwm_set_frequency(1000);
        pwm_set_duty_cycle_percent(50.0); // 50% Tastverhältnis starten
    
        // 5. Timer aktivieren (Der Prescaler wird in pwm_set_frequency gesetzt)
        TCA0.SINGLE.CTRLA |= TCA_SINGLE_ENABLE_bm;
    }
    Das funktioniert natürlich nur bei hohen Teilerfaktoren also niedrigen Frequenzen.
    Beim kleinsten Teilerfaktor = 1 sind dann schon 425Hz Sprünge drin.
    Das geht im Prinzip auch nicht genauer, weil der Controller natürlich nur Ganze Zahlen für das MAX ( PER ) Register verwenden kann.
    Das ist also ein Fehler von 0,4%.
    Bei größeren Teilfaktoren wird natürlich die Frequenzauflösung besser bis hinunter in den Hz Bereich.

    120kHz wären bei Duty Cycle mit 0,5% auch noch möglich. Aber auch der L293D schafft das nicht.

    Es läuft der interne 24MHz Generator. An Peripherie ist nur der Treiber, das Display, der Drehencoder und das Poti. Betrieben wird das Ganze vorerst mit nem Labornetzteil.

Ähnliche Themen

  1. Sinus Generator 100khz-600khz/800khz
    Von deko im Forum Elektronik
    Antworten: 1
    Letzter Beitrag: 14.01.2013, 21:31
  2. Mathematik: 100kHz ISR
    Von Merlin321 im Forum C - Programmierung (GCC u.a.)
    Antworten: 11
    Letzter Beitrag: 27.01.2010, 18:12
  3. frequenzmessen über 100khz nicht möglich
    Von kleinstar im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 15.05.2007, 17:45
  4. Robby als 100KHz IIC Slave vervenden
    Von glowbrain1 im Forum Robby CCRP5
    Antworten: 2
    Letzter Beitrag: 31.10.2006, 20:25
  5. 100KHz IIC(I2C) Slave on MC05 (platform Robby)
    Von glowbrain1 im Forum Controller- und Roboterboards von Conrad.de
    Antworten: 1
    Letzter Beitrag: 01.08.2004, 13:22

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

    Werbung      12V Akku bauen