- fchao-Sinus-Wechselrichter AliExpress         
Ergebnis 1 bis 10 von 15

Thema: Ewiges Thema Timer und PWM

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    26.10.2017
    Beiträge
    11

    Ewiges Thema Timer und PWM

    Hallo zusammen,

    ich arbeite mich weiter mit Hilfe eine PIC 18F458 Entwicklungsboard in
    die µC Thematik ein und bin jetz dabei ein 50 kHZ PWM Signal für einen
    PWM Modulator zu erstellen. Es gibt da viel Möglichkeiten und ich habe
    jetzt mal 2 realisiert.

    Einmal über die SETUP_CCP Funktion und einmal über einen Timer
    Interrupt. Das funktioniert soweit, nur bei der Methode mit dem
    Interrupt erhalte ich nicht die berechnete Frequenz. Ich habe wie immer
    schon in diesem Forum und bei Tante Google gesucht aber nichts gefunden
    was mir weiter hilft.

    Code:
    #include <18f458.h>
    #device ICD=TRUE
    #fuses HS,NOLVP,NOWDT,PUT
    #use delay(clock=20000000)
    
    void init_timers()
    {
       SETUP_TIMER_1(T1_INTERNAL);
       SET_TIMER1(65436);
       SETUP_CCP1(CCP_PWM);
       setup_timer_2(T2_DIV_BY_4, 24, 1);
       set_pwm1_duty(1);
    }
    
    #INT_TIMER1
    void timer0_isr()
    {
       SET_TIMER1(65436);    //Einstellen der gewünschten Frequenz
    
       output_high(PIN_D1);  //Einstellen des gewünschten Pulsbreite
       output_high(PIN_D1);
       output_high(PIN_D1);
    
       output_low(PIN_D1);
    }
    
    void main()
    {
       setup_timer_1(T1_DISABLED);
       setup_timer_2(T2_DISABLED,0,1);
    
       SET_TRIS_D( 0x50 );
       SET_TRIS_C( 0x00 );
    
       init_timers() ;
    
       enable_interrupts(INT_TIMER1);
       enable_interrupts(GLOBAL);
    
       While(True);
    }
    Nach meinen Berechnungen müsste 20Mhz/4 => 0,2µs Tick ergeben. 50 kHz
    entsprechen 0,02 ms und somit ergeben sich 0,02ms/0,2µs = 100 Ticks.

    Somit muss ich rechnerisch den Zähler des Interrupts auf 65536-100 =
    65436 einstellen um die gewünschte Frequenz zu erhalten, damit ergeben
    sich leider nicht 50 kHz sondern 33.79kHz.

    Ich muss den Wert auf 65484 einstellen um 50 kHz zu erhalten, ich kann
    den Fehler in meiner Berechnung nicht finden?!

    Kann mir jemand sagen was ich falsch mache oder falsch annehme/
    verstanden habe?
    Geändert von GeoMan (13.11.2017 um 10:42 Uhr)

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von GeoMan Beitrag anzeigen
    Kann mir jemand sagen was ich falsch mache oder falsch annehme/
    verstanden habe?
    Erstmal, Code liest sich viel leichter, wenn man ihn auch als Code postet. Du solltest auch angeben, wo du z.B. die Funktion SETUP_TIMER_1(T1_INTERNAL) herhast, ich kenne sie nicht.

    Aber ich denke, dein Problem lässt sich auch so lösen. Der Interrupt wird ausgelöst, wenn der Timer abgelaufen ist. Dann dauert es aber noch eine nicht genau definierte Zeit, bis in deinem Interrupthandler der Timer neu gesetzt wird. Der Prozessor führt erstmal den laufenden Befehl zuende aus, dann braucht er etwas um dem Handler aufzurufen. Dann muß er alle möglichen Zustände sichern damit er sie am Ende des Handlers wiederherstellen kann. Und erst dann fängt er an, deine Code im Handler abzuarbeiten. Inzwischen ist schon etwas Zeit vergangen und damit stimmt deine Rechnung nicht mehr. Deine 100 Ticks für einen Zyklus entsprechen knapp 100 Befehlen, das ist sehr wenig. Für eine 50kHz Frequenz mit Steuerung in Software ist dein Prozessor zu langsam.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    26.10.2017
    Beiträge
    11
    Danke für die Antwort Klebwax. Der Code liest sich tatsächlich so nicht einfach, die Formatierung stimmt aber sobald ich den Beitrag freigebe kommt Obiges heraus

    Wie dem auch sei, die Funktion wird im CCS Compiler verwendet ununabhängig davon kann ich deinen Ausführungen soweit folgen. Dann muss ich jetzt nur zusehen wie ich die
    Zeit am besten messe die für die Abarbeitung etc. benötigt wird und dann bei der Berechnung mit berücksichtigen.

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von GeoMan Beitrag anzeigen
    Danke für die Antwort Klebwax. Der Code liest sich tatsächlich so nicht einfach, die Formatierung stimmt aber sobald ich den Beitrag freigebe kommt Obiges heraus
    Deswgen schrieb ich: als Code formatieren. Beim Editor auf erweitert und dann Code einfügen.
    Wie dem auch sei, die Funktion wird im CCS Compiler verwendet
    Ahnte ich. Der CCs Compiler ist manchmal ein wenig am C-Standard vorbei, oder wars früher. Das kann schon mal wichtig sein.
    Dann muss ich jetzt nur zusehen wie ich die Zeit am besten messe die für die Abarbeitung etc. benötigt wird und dann bei der Berechnung mit berücksichtigen.
    Diese Zeit muß nicht konstant sein. Je nachdem, wie schlau der Compiler ist, wird er mehr oder weniger Werte retten, abhängig von deinem Code. Du müsstest also nach jeder Codeänderung neu bestimmen, wie lange die Interruptpräambel dauert. Und sobald du in der Mainloop etwas tust und dabei auch Befehle vorkommen, die zwei Zyklen dauern, geht es auch mal schneller oder langsamer. Und zu guter Letzt: 100 Befehle zwischen zwei Interrupten sind zuwenig.

    50kHz für eine Softpwm sind für deinen Prozessor zu schnell. Machs lansamer, benutze die eingebaute Hardware (deswegen gibts die) oder nimm einen wesentlich schnelleren Prozessor.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  5. #5
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    39
    Beiträge
    3.416
    die Formatierung stimmt aber sobald ich den Beitrag freigebe kommt Obiges heraus
    setz einfach [ C O D E ] vor und [ / C O D E ] nach deinem code ein dann formatiert er es richtig .... natürlich ohne die leerzeichen, sonst hätte er aus meinem text code gemacht
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  6. #6
    Neuer Benutzer Öfters hier
    Registriert seit
    26.10.2017
    Beiträge
    11
    O.K. das mit dem Code habe ich jetzt verstanden und direkt umgesetzt - also das mit dem Formtieren des Codes

    Wenn ich das jetzt richtig verstanden habe ist es also so, dass beim Interrupt der Stack gesichert und anschliessend zurück geschrieben werden muss. Da ich diese Zeitdauer nicht berücksichtige stimmt meine Berechnung nicht.

    So weit so gut.

    An für sich ist die Zeitdauer dafür bekannt da ich den Wert ja solange angepasst habe bis die gewünschte Frequenz eingestellt wurde, also 65484 - 65436 = 48 Ticks, d.h. 48 Ticks * 0,2µs = 9,6µs. Ist das ein realistischer Wert für das Sichern und Schreiben des Stackse, erscheint mir etwas hoch

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    11.12.2007
    Ort
    weit weg von nahe Bonn
    Alter
    39
    Beiträge
    3.416
    da es nicht die einzige ISR sein wird die du später verwendest, würde ich dir noch empfehlen innerhalb der ISR das globale Itnerrupt Flag zu lsöchen und am ende wieder einzuschalten um glitches zu vermeiden wenn ein interrupt im interrupt feuert (sofern das beim pic18 möglich ist, ich kenn den chip leider nicht)
    Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
    nicht.

  8. #8
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.678
    .. dass beim Interrupt der Stack gesichert und anschliessend zurück geschrieben werden muss .. erscheint mir etwas hoch ..
    Hallo PICman - sorry, GeoMan.

    Ich kenn mich mit den PICs nicht aus, ich programmiere Atmels in C. Aber vielleicht gibts bei PIC ähnliche Dinge. Ich bekomme z.B. mit dem Compilat noch ne so genannte LLS-Datei. In der ist eine Art Assemblerlisting mit Maschinencode, dazwischen eingefügtem C-Code und mit mancherlei organisatorischen Daten zum Compilat enthalten. Als Beispiel mal eine vollständige ISR zum USART-Empfang
    Code:
    ISR( USART0_RX_vect )
    {
         148:    1f 92           push    r1
         14a:    0f 92           push    r0
         14c:    0f b6           in    r0, 0x3f    ; 63
         14e:    0f 92           push    r0
         150:    0b b6           in    r0, 0x3b    ; 59
         152:    0f 92           push    r0
         154:    11 24           eor    r1, r1
         156:    8f 93           push    r24
         158:    9f 93           push    r25
         15a:    ef 93           push    r30
         15c:    ff 93           push    r31
      u8 i = rx_in;
         15e:    90 91 20 0f     lds    r25, 0x0F20
    
      ROLLOVER( i, RX0_SIZE );
         162:    9f 5f           subi    r25, 0xFF    ; 255
         164:    97 fd           sbrc    r25, 7
         166:    90 e0           ldi    r25, 0x00    ; 0
      if( i == rx_out ){            // buffer overflow
         168:    80 91 21 0f     lds    r24, 0x0F21
         16c:    98 17           cp    r25, r24
         16e:    31 f4           brne    .+12         ; 0x17c <__vector_20+0x34>
        URX0_IEN = 0;            // disable RX interrupt
         170:    80 91 c1 00     lds    r24, 0x00C1
         174:    8f 77           andi    r24, 0x7F    ; 127
         176:    80 93 c1 00     sts    0x00C1, r24
         17a:    0a c0           rjmp    .+20         ; 0x190 <__vector_20+0x48>
        return;
      }
      rx_buff[rx_in] = UDR0;
         17c:    e0 91 20 0f     lds    r30, 0x0F20
         180:    f0 e0           ldi    r31, 0x00    ; 0
         182:    80 91 c6 00     lds    r24, 0x00C6
         186:    e0 56           subi    r30, 0x60    ; 96
         188:    f1 4f           sbci    r31, 0xF1    ; 241
         18a:    80 83           st    Z, r24
      rx_in = i;
         18c:    90 93 20 0f     sts    0x0F20, r25
    }
         190:    ff 91           pop    r31
         192:    ef 91           pop    r30
         194:    9f 91           pop    r25
         196:    8f 91           pop    r24
         198:    0f 90           pop    r0
         19a:    0b be           out    0x3b, r0    ; 59
         19c:    0f 90           pop    r0
         19e:    0f be           out    0x3f, r0    ; 63
         1a0:    0f 90           pop    r0
         1a2:    1f 90           pop    r1
         1a4:    18 95           reti
    Hier siehst Du diesen gesamten Overhead an pushs und pops, zugehörigen Registerbewegungen und dem reti; der Jump nach "ISR( USART0.."
    50:...0c 94 a4 00.....jmp.....0x148.....; 0x148 <__vector_20>
    ist hier aber noch NICHT erfasst. Aus den entsprechenden Befehlen und dem Datenblatt des Controllers kann man nun (bei Atmel und GCC) den tatsächlichen Zeitbedarf in Einheiten der CPUclocks (siehe unten: #Clocks) genau ausrechnen:

    Code:
    DATA TRANSFER INSTRUCTIONS
    Mnemonics Operands Description .............. Operation .. Flags .. #Clocks
    ...
     PUSH .... Rr ..... Push Register on Stack ... STACK ← Rr . None .... 2
     POP ..... Rd ..... Pop Register from Stack .. Rd ← STACK . None .... 2
     RETI ..............Interrupt Return ......... PC ← STACK .. I ...... 4
    Nachtrag:
    Zitat Zitat von Doku zu m328/p, Atmel-42735B
    ..
    When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The
    user software can write logic one to the I-bit to enable nested interrupts.
    ..
    Man kann bei den Atmels in einer ISR das Interruptbit explizit auf "erlaube Interrupts" setzen. Ich habe hin und wieder zwar nested interrupts in meinen Quellen - aber die sind schon ein heisses Eisen.
    Geändert von oberallgeier (14.11.2017 um 14:05 Uhr) Grund: noch etwas zu (nested) Interrupts
    Ciao sagt der JoeamBerg

  9. #9
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von Ceos Beitrag anzeigen
    da es nicht die einzige ISR sein wird die du später verwendest, würde ich dir noch empfehlen innerhalb der ISR das globale Itnerrupt Flag zu lsöchen und am ende wieder einzuschalten um glitches zu vermeiden wenn ein interrupt im interrupt feuert (sofern das beim pic18 möglich ist, ich kenn den chip leider nicht)
    Keine gute Empfehlung. Wenn du am Ende den Interrupt wieder einschaltest ist der Interrupthandler noch lange nicht fertig. Da kann dir jetzt jeder Interrupt inklusive der, der gerade abgeschlossen wird, reinpfuschen. Der Interrupt darf nur atomar mit dem letzten Befehl wieder freigegeben werden. Daher gibt es den Assemblerbefehl "return from interrupt", den der Compiler automatisch ans Ende eine Interrupthandlers packt.

    Und abschalten brauchst du ihn auch nicht. Das muß automatisch passieren. Da das jeweilige Interruptflag meißt individuell in SW gelöscht werden muß, würde sonst der Interrupt nach dem ersten Assemblerbefehl des Interrupthandlers erneut zuschlagen. Und das solange, bis der µC abstürzt. Und das gilt prinzipiell für alle Prozessoren.

    Zitat Zitat von GeoMan Beitrag anzeigen
    Wenn ich das jetzt richtig verstanden habe ist es also so, dass beim Interrupt der Stack gesichert und anschliessend zurück geschrieben werden muss. Da ich diese Zeitdauer nicht berücksichtige stimmt meine Berechnung nicht.

    So weit so gut.

    An für sich ist die Zeitdauer dafür bekannt da ich den Wert ja solange angepasst habe bis die gewünschte Frequenz eingestellt wurde, also 65484 - 65436 = 48 Ticks, d.h. 48 Ticks * 0,2µs = 9,6µs. Ist das ein realistischer Wert für das Sichern und Schreiben des Stackse, erscheint mir etwas hoch
    Es geht nicht wirklich um den Stack, es geht um das Sichern des ganzen Kontext der gerade laufenden Funktion. Und das kann schon dauern. Es ist auch nicht gesagt, daß es immer gleichlange dauert. Dein Ansatz ist also schlecht und, wie ich schon sagte, für dein Konzept (Interrupt mit 50kHz) ist der Prozessor zu langsam.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

Ähnliche Themen

  1. Ewiges Leben: Hybrider Lohner-Porsche „Semper Vivus“
    Von Roboternetz-News im Forum Neuigkeiten / Technik-News / Nachrichten / Aktuelles
    Antworten: 0
    Letzter Beitrag: 19.03.2011, 19:00
  2. C167 Drehzahlberechnung mit Timer 3 od. Timer 3 & 4?
    Von cieks0301 im Forum Software, Algorithmen und KI
    Antworten: 5
    Letzter Beitrag: 13.03.2009, 11:37
  3. fragen zum thema HF
    Von Che Guevara im Forum Elektronik
    Antworten: 4
    Letzter Beitrag: 06.01.2008, 04:01
  4. PWM mit Timer 0 und 2 geht, aber nicht mit Timer 1 (mega64)
    Von popi im Forum C - Programmierung (GCC u.a.)
    Antworten: 3
    Letzter Beitrag: 14.06.2006, 17:00
  5. thema spannungsverdoppler
    Von im Forum Elektronik
    Antworten: 7
    Letzter Beitrag: 05.12.2004, 15:40

Berechtigungen

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

12V Akku bauen