- 3D-Druck Einstieg und Tipps         
Seite 1 von 6 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 51

Thema: PWM 2 kleine Probleme.... bitte um Hilfe

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    38
    Beiträge
    795

    PWM 2 kleine Probleme.... bitte um Hilfe

    Anzeige

    Powerstation Test
    Hallo,

    Ich weiß dass die Fragen zu PWM für Profis sehr nervig sind,

    Leider sind für PWM-Anwendungen fast keine "Übungsbeispiele" in C im Netz zu finden.

    Nun zu meinen Problemchen....


    Soweit ich mir das erarbeitet habe, müsste folgender Code funktionieren


    Code:
    // PWM01 mit ATmega8535 mit 8MHz
    
    #include <io.h>
    
    int main (void)
    {
       
    TCCR1A = (1<<PWM11)|(1<<PWM10)|(1<<COM1A1);
    TCCR1B = (1<<CS12) | (1<<CS10);
    
    for (;;) {
    
    OCR1A = x;  // x ist jetzt mal ein Beispielwert,.... 
    
    }}
    Erklärung (bitte verbessern falls ich mich irre)

    TCCR1A = (1<<PWM11)|(1<<PWM10)|(1<<COM1A1);
    Befehl für nicht invertierenden 10-Bit PWM.

    TCCR1B = (1<<CS12) | (1<<CS10);
    Takt von CK / 1024 ( hier ergibt sich dann Frage 2 )

    OCR1A = xxx;
    Wert....


    nunja, wenn ich das ganze nun "HEXen" will, dann kommt die Meldung:

    "error: "PWM11" undeclared (first use in this funktion)"
    "error: "PWM10" undeclared (first use in this funktion)"


    Muss ich vielleicht noch ne andere Datei "includen" ausser io.h ?
    Oder woran könnte das liegen.... habe die codes aus:
    http://www.mikrocontroller.net/wiki/...nmodulation.29

    Frage 2:

    TCCR1B = (1<<CS12) | (1<<CS10);
    Takt von CK / 1024

    Ich will letzendlich ein Modellbauservo ansteuern, welches ja einen takt von ca. 50Hz braucht.

    aus CK / 1024, ergeben sich aber bei 8MHz ca. 7.8 kHz....

    wie komme ich runter auf 50Hz ?

    Soll ich "Externer Pin 1, positive Flanke" nutzen?

    also
    TCCR1B = (1<<CS12) | (1<<CS11) | (1<<CS10);
    ?
    und dort einen Oszillator mit 50Hz dranhängen?


    Ich bedanke mich schon mal im Vorfeld für eure Bemühungen,

    Gruß
    Kaiser F

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    23.05.2004
    Ort
    Untersöchering(Bayern,Alpenvorland)
    Alter
    37
    Beiträge
    215
    Include mal noch zusätzlich die Headerdatei <avr/io8535.h>.
    Und bei CK/Prescaler kommst du nur auf die Frequenz für einen Takt. Bei 10Bit sind das 2^10 also 1024Takte. Bei dir hast du bei 7.8kHz pro Takt insgesamt ein Frequenz von 7800Hz/1024=7.6Hz. Ist also schon zuwenig.
    Hier gibt es ein kleines Windows Programm.
    "Avr Timer-Berechnung
    Dieses Tool berechnet die Timereinstellungen und erzeugt Quellcode damit eine vorgegebene Timerfrequenz erreicht wird. Jetzt mit Zusatz-Rechenfunktion für Spannungsteiler."
    https://www.roboternetz.de/phpBB2/dl...gory&cat_id=18
    Gruß Muraad

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    38
    Beiträge
    795
    Hallo,

    das heisst also die resultierende Pulsfrequenz wird so berechnet:

    µC-Takt / BIT / Vorzähler = Pulsfrequenz.

    Dadurch ergäbe sich folgendes:


    Code:
    Takt	BIT	CK/x	 Hz:	ms:
    
    8000000	510	1	15686,27	0,06375
    8000000	510	8	1960,78	0,51
    8000000	510	64	245,10	4,08
    8000000	510	256	61,27	16,32
    8000000	510	1024	15,32	65,28
    8000000	1022	1	7827,79	0,12775
    8000000	1022	8	978,47	1,022
    8000000	1022	64	122,31	8,176
    8000000	1022	256	30,58	32,704
    8000000	1022	1024	7,64	130,816
    8000000	2046	1	3910,07	0,25575
    8000000	2046	8	488,76	2,046
    8000000	2046	64	61,09	16,368
    8000000	2046	256	15,27	65,472
    8000000	2046	1024	3,82	261,888
    
    16000000	510	1	31372,55	0,031875
    16000000	510	8	3921,57	0,255
    16000000	510	64	490,20	2,04
    16000000	510	256	122,55	8,16
    16000000	510	1024	30,64	32,64
    16000000	1022	1	15655,58	0,063875
    16000000	1022	8	1956,95	0,511
    16000000	1022	64	244,62	4,088
    16000000	1022	256	61,15	16,352
    16000000	1022	1024	15,29	65,408
    16000000	2046	1	7820,14	0,127875
    16000000	2046	8	977,52	1,023
    16000000	2046	64	122,19	8,184
    16000000	2046	256	30,55	32,736
    16000000	2046	1024	7,64	130,944


    Also Bräuchte ich bei 8MHz folgendes:

    10BIT PWM mit 64er Vorzähler, also CK/64

    ergäbe 61,09Hz = 16,368ms?




    Die Fehlermeldung

    "error: "PWM11" undeclared (first use in this funktion)"
    "error: "PWM10" undeclared (first use in this funktion)"


    Erscheint noch immer.... auch mit <avr/iom8535.h>.....


    Wäre toll wenn mir jemand hier weiterhelfen könnte....
    Sitze jetzt schon über zwei wochen an diesen Problem fest.


    mfg

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    20.06.2004
    Beiträge
    1.941
    doch, hier ist ein beispiel:
    Code:
    #include <avr/io.h>
    
    /* Diese ganze "Bibliothek" bezieht sich auf ATmega32. Es dürfte aber nicht schwer sein 
    sie für andere Atmels umzuschreiben                                                      */
    
    /* Erstmal ein paar sehr nützliche #defines die ich zum ersten mal bei www.mc-project sah */
    #define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))          // Setzt bit im gewünschten Register
    #define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))       // Löscht bit in ADDRESS
    #define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT))         // Prüfft ob bit gesetzt ist
    
    /*PWM-Teil
      Hier kommen meine #defines und Funktionen und zur PWM Ausgabe mit Timer2(16Bit Timer)  
      Beim ATmega32 geschiet die PWM Ausgabe an PD4(OC1B) und PD5(OC1A). Mit den #defines stellt
      man die ganze Voreinstellungen ein. Mit den Funtkionen pwmXbit() kann man dann das PWM 
      Ausgangssignal steuern. Mit pwm_index setzt man fest an welchen Ausgang. limit_range
      unterteil den PWM Bereich  in 0.0-100.0 Das ganze sieht dann so aus 
      z.B pwm9bit(35.0,1) damit ist PWM Ausgabe an Ausgang 2 wobei im OutputCompareRegister
      35.0*327.68 = (int) 11468.8 steht
    */
    #define PWMchannel_init         DDRD= _BV(PD4) | _BV(PD5);   // PWM Ports als ausgang deklarieren
    #define PWM8bit_init            TCCR1A |=_BV(WGM10)              // Gewünschte PWM 8,9 oder eben 10Bit
    #define PWM9bit_init            TCCR1A |=_BV(WGM11)
    #define PWM10bit_init           TCCR1A = _BV(WGM10) | _BV(WGM11)
    #define PWMdisable              TCCR1A = ~_BV(WGM10) & ~_BV(WGM11)   // Timer2 wieder normaler Timer    
    #define PWMnoCO1A               TCCR1A = ~_BV(COM1A0) & ~_BV(COM1A1) // Kein PWM an Ausgang1
    #define PWMnoCO1B               TCCR1A = ~_BV(COM1B0) & ~_BV(COM1B1) 
    #define PWM1upcounting          TCCR1A = _BV(COM1A0) | _BV(COM1A1)   // invertierende PWM
    #define PWM2upcounting          TCCR1A = _BV(COM1B0) | _BV(COM1B1)   
    #define PWM1downcounting        TCCR1A |= _BV(COM1A1)                // nicht invertierend
    #define PWM2downcounting        TCCR1A |= _BV(COM1B1)
    #define Timer2_prescaler_1      TCCR1B |= _BV(CS10)              // verschiedene Prescaler 
    #define Timer2_prescaler_8      TCCR1B |= _BV(CS11)
    #define Timer2_prescaler_64     TCCR1B = _BV(CS11) | _BV(CS10)
    #define Timer2_prescaler_256    TCCR1B |= _BV(CS12)
    #define Timer2_prescaler_1024   TCCR1B = _BV(CS12) | _BV(CS10)
    #define Timer2_stop             TCCR1B = ~_BV(CS12) & ~_BV(CS11) & ~_BV(CS10)      // stopt Timer2
    
    float limit_range(float val,float low,float high)   
    {
       if(val<low) return low;
       else if(val>high) return high;
       else return val;
    }
    
    void pwm8bit(float vel, unsigned char pwm_index)       // pwb_index 0 für Ausgang 1, 1 für Ausgang 2
    {                                               // für 8Bit Pwm
       vel = limit_range(vel,0.0,100.0);
       if(pwm_index==0)
          OCR1A= (int) (163.84*vel);
       if(pwm_index==1)
          OCR1B= (int) (163.84*vel);
    }
    
    void pwm9bit(float vel, unsigned char pwm_index)       // pwb_index 0 für Ausgang 1, 1 für Ausgang 2
    {
       vel = limit_range(vel,0.0,100.0);
       if(pwm_index==0)
          OCR1A= (int) (327.68*vel);
       if(pwm_index==1)
          OCR1B= (int) (327.68*vel);
    }
    
    void pwm10bit(float vel, unsigned char pwm_index)       // pwb_index 0 für Ausgang 1, 1 für Ausgang 2
    {
       vel = limit_range(vel,0.0,100.0);
       if(pwm_index==0)
          OCR1A= (int) (655.36*vel);
       if(pwm_index==1)
          OCR1B= (int) (655.36*vel);
    }
    
    /* Analog/Digiatl konverting */
    #define ADCchannel_init   DDRA=0x00                 // ADC Port als Eingang deklarieren
    #define ADCinit           ADCSRA|=_BV(ADEN)         // Teilt dem Board mit das der jeweilige Port für ADC verwendet wird
    #define ADCdisable        ADCSRA &=~_BV(ADEN)       // machs das vorherige wieder rückgänig
    #define ADCstart          ADCSRA|=_BV(ADSC)         // startet eine konvertierung auf dem gewünschten Kannal/Pin
    #define ADCfree           ADCSRA|=_BV(ADATE)        // schaltet den freilaufenden Modus ein
    #define ADCvintern        ADMUX|=_BV(REFS0)     // interne Spannungsversorgung
    #define ADCinterrupt_on   ADCSRA|=_BV(ADIE)                // ADC interrupt wird freigeschalten
    #define ADCprescaler_2    ADCSRA |=_BV(ADPS0)              // gewünschter Teilungsfaktor/Prescaler 
    #define ADCprescaler_4    ADCSRA|=_BV(ADPS1)
    #define ADCprescaler_8    ADCSRA=_BV(ADPS1) | _BV(ADPS0)
    #define ADCprescaler_16   ADCSRA|=_BV(ADPS2)
    #define ADCprescaler_32   ADCSRA=_BV(ADPS2) | _BV(ADPS0)
    #define ADCprescaler_64   ADCSRA=_BV(ADPS2) | _BV(ADPS1)
    #define ADCprescaler_128  ADCSRA=_BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0)
    #define ADCprescaler_reset ADCSRA = ~_BV(ADPS2) & ~_BV(ADPS1) & ~_BV(ADPS0)        
    #define ADCchannel_1                                      //gewünschter Kannal z.B bei ATmega32 PINA0 - PINA7
    #define ADCchannel_2      ADMUX|=_BV(MUX0)                // bei nicht freilaufen muss ADCchannel_x vor
    #define ADCchannel_3      ADMUX|=_BV(MUX1)                // ADCstart kommen dann kann man mit getadc() der 
    #define ADCchannel_4      ADMUX= _BV(MUX1) | _BV(MUX0)    // Adcwert des gewählten Kannals auslesen
    #define ADCchannel_5      ADMUX|=_BV(MUX2)
    #define ADCchannel_6      ADMUX= _BV(MUX2) | _BV(MUX0)
    #define ADCchannel_7      ADMUX= _BV(MUX2) | _BV(MUX1)
    #define ADCchannel_8      ADMUX= _BV(MUX2) | _BV(MUX1) | _BV(MUX0)
    #define ADCchannel_reset  ADMUX= ~_BV(MUX2) & ~_BV(MUX1) & ~_BV(MUX0)
    inline unsigned int getadc(void)
    {
       while (ADCSRA & _BV(ADSC)) {}
       return ADC;
    }
    und weiter:

    Code:
    #include <adc_pwm.h> (so heisst oben die datei für diese main)
    
    // PWM Beispiel 
    
    int main(void)
    {
       PWMchannel_init;
       PWM9bit_init;
       PWM1upcounting;
       PWM2upcounting;
       Timer2_prescaler_256;
       pwm9bit(35.0,0);
       pwm9bit(45.0,1);
       Timer2_stop;
       Timer2_prescaler_1024;
       pwm9bit(35.0,0);
       pwm9bit(45.0,1);
    }
    habe ich hier vom forum.

    weil es so schön war, noch für adc (bibliothek von ganz oben für diese main):

    Code:
    #include <adc_pwm.h>
    
    // AD beispiel
    int main(void)
    {
       unsigned int x;
       ADCinit;
       ADCchannel_init;
       ADCvintern;
       ADCprescaler_16;
       ADCchannel_3;
       x=getadc();
       ADCprescaler_reset;
       ADCchannel_reset;
       ADCprescaler_128;
       ADCchannel_5;
       x=getadc();
    }
    mdf pebisoft

  5. #5
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    03.01.2004
    Ort
    Pottenstein
    Alter
    45
    Beiträge
    269
    Moin moin,

    Also erstmal sollte man nicht die ioxxxx.h fuer den jeweiligen AVR direkt includen, sondern nur die avr\io.h. Die bindet dann naemlich die jeweils noetige ioxxx.h ein (wird vom Compiler anhand des im Makefile eingestellten AVR-Typs erkannt).

    Um ein PWM-Signal fuer ein Servo zu erzeugen, wuerde ich nicht die PWM-Ausgaenge des AVRs nehmen, sondern normale Ausgangspins und die Timer, um das Signal selbst zu erzeugen.

    Hab meinen Code gerade in einem anderen Thread gepostet, also vielleicht mal hier spicken:
    https://www.roboternetz.de/phpBB2/ze...rag.php?t=7252

    Wenn ich den Beitrag von Pebisoft oben sehe (geht das echt nur mit diesem voluminoesen code?), scheint mir meine Loesung doch etwas einfacher zu sein. Und ich kann mehrere Servos versorgen, nicht nur soviele wie der AVR PWM-Ausgaenge hat (2 Stueck?). Wobei das natuerlich bei vielen Servos die verfuegbare Rechenzeit fuer andere Aufgaben etwas einschraenkt, ich weiss (noch) nicht, wie gross dieser Effekt ist...

    Nils

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    38
    Beiträge
    795
    Hallo,

    Vielen Dank an euch beiden für eure Tipps und Codes.

    Hebe nun das ganze in Gang gebracht!
    Die ursache war diese zeile:

    TCCR1A = (1<<PWM11)|(1<<PWM10)|(1<<COM1A1);

    PWM ist anscheinend falsch, muss WGM heissen, also:

    TCCR1A = (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);

    Hab ich aus Pebisoft's Code gefolgert.

    Der lange Code von Pebisoft lässt sich durch die Defines begründen, die eine Headerdatei darstellen, um die PWM"Befehle" zu vereinfachen.

    Wer sein PWM-Signal oft ändert, für den ist das sehr Vorteilhaft!

    Normal genügen folgende Zeilen um ein Servo anzusteuern:

    (mit 8MHz µC-Frequenz)
    Code:
    #include <io.h>
    
    {
    
    // den entsprechenden Pin muss man glaub ich als Ausgang definieren, nicht vergessen
    
    TCCR1A = (1<<WGM11)|(1<<WGM10)|(1<<COM1A1); //10BIT PWM aktivieren
    TCCR1B = (1<<CS11); //Vorzähler 8 also CK/8
    
    for (;;) {
    
    OCR1A = "Wert";  // wert liegt zwischen 50 und 150 (Vollausschläge)
    
    }}

    Die Softwarelösung werd ich mir noch anschauen!

    MfG

  7. #7
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    23.05.2004
    Ort
    Untersöchering(Bayern,Alpenvorland)
    Alter
    37
    Beiträge
    215
    Der Code ist von mir. Ich bin mal erfreut drüber das ihn welche benutzen und er funktioniert Und es stimmt schon das es mit den Defines viel Code wird wobei der Code auch als Beispiel dafür gedacht war wie die ganzen Register zu setzten sind.
    Gruß Muraad
    PS: Ist komisch das der Code von dir nicht ging da die Bits nur in der Headerdatei vom ATmega32 WGM11 und WGM10 heissen, in der io8535.h heissen die Defines wirklich PWM11 und PWM10. Naja aber wenns funktioniert ists gut.

  8. #8
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    03.01.2004
    Ort
    Pottenstein
    Alter
    45
    Beiträge
    269
    Hallo Kaiser-F,

    Kannst du nochmal erklaeren, wie du die Werte berechnet hast? Irgendwie kann ich das nicht so ganz nachvollziehen.
    Dein Prescaler steht auf CPUCLK/8, also laeuft der Timer mit 1MHz, ein Timertick entspricht also einer Mikrosekunde.
    Du benutzt 10bit-PWM und der Timer laeuft jeweils hoch und runter, also wiederholt sich dein PWM-Puls immer nach 1/(1MHz/(1024*2))ms=2ms.
    Du setzt den Vergleichswert auf 50 (fuer Vollausschlag links), damit ist dein Puls also 2*50*1Mikrosekunde, also 100 Mikrosekunden lang. Du hast "nicht invertierend" eingestellt, also bekommst du fuer Vollausschlag links einen Puls von 100 Mikrosekunden HIGH (bzw 300 Mikrosekunden bei Vollausschlag rechts). Dieser Puls wiederholt sich alle 2 ms. Ein Servo braeuchte aber einen Puls von 1 bis 2ms alle 20ms. Hast du das mal mit nem Servo getestet? Wenn ja und erfolgreich: Wo ist denn mein Denkfehler?

    Gruss,

    Nils

  9. #9
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    04.01.2005
    Ort
    Bayern
    Alter
    38
    Beiträge
    795
    Hallo Minifriese,

    Da ist was drann!!!

    Ich Muss mal ein Oszi anschließen!

    Du hast sicherlich recht! ich hab halt den vergleiswert so tief gesetzt, dass es trotzdem funktioniert hat! ---- zufall ----

    Ich poste morgen den korrekten Code. Danke für die Aufmerksamkeit!

    Ich hab den invertierten und nicht invertierten voll durcheinandergebracht.

    Danke für den Tipp!


    Gruß
    Kaiser

  10. #10
    Benutzer Stammmitglied
    Registriert seit
    17.02.2005
    Ort
    Pfullingen, am Rande der Schwäbischen Alb
    Alter
    41
    Beiträge
    56
    OK, damit lässt sich auch mein Versuch von gestern erklären. Hab den oben verwendeten Quellcode in einem Testaufbau von mir verwendet und die Servos sind gelaufen haben aber nie die Fahrtrichtung verändert...

    @Kaiser-F:

    also wenn du mal den neuen Code postest, hat sich auch meine pm an dich erledigt...

    gruss Siggi

Seite 1 von 6 123 ... LetzteLetzte

Berechtigungen

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

12V Akku bauen