Hallo Gerko,
bin auch Lernender und bin mir nicht sicher, daß ich deinen Code richtig verstehe. Wenn du einen Timer-Int willst, wenn der Timer0 einen OV-Int auslösen soll, dann muß ins Register TIMSK noch TOIE0 hinein.
Gruß!
Simmt, da hast du natürlich recht das das vielleicht ein Vorteil wäre gleich einen eigenen µC dafür zu verwende. Trotzdem würde ich gerne wissen wie Timer funktionieren.
Wie kann ich meinen PWM Ausgang auf ein Interrupt legen? Wenn jedesmal ein Interrupt ausgelöst wird, wenn der Timmer umschaltet, kann ich ja Softwartechnisch alles dazu machen das ich daraus eine Aktion Programmiere um Ausgänge ein/aus zu schalten. Ich verstehe nur nicht wie ich einen Interrupt auslöse
mfg Gerko
Hallo Gerko,
bin auch Lernender und bin mir nicht sicher, daß ich deinen Code richtig verstehe. Wenn du einen Timer-Int willst, wenn der Timer0 einen OV-Int auslösen soll, dann muß ins Register TIMSK noch TOIE0 hinein.
Gruß!
Hallo Leute!
Ich habe jetzt wieder mal ein bischen herumexperimentiert, aber ich komme zu keinem Interrupt. Mitlwerweile verwende ich nicht mehr Phase Correct PWM, sondern CTC.
Ist CTC überhaupt noch PWM?, dabei wird doch die Frequenz verändert oder?
Mit diesem Programmcode wird zwar ein Interrupt ausgelöst, aber das Programm springt nicht in die Interruptvektortabelle, sondern einfach nur 3 zeilen weiter rauf. Das Hilft mir sogut wie garnicht.
Im Register TIMSK habe ich nun OCIE0 aktiviert, mit TOIE0 passiert garnichtsCode:.include "m16def.inc" .def temp = r16 .org 0x000 ; kommt ganz an den Anfang des Speichers rjmp main ; Interruptvektoren überspringen ; und zum Hauptprogramm rjmp EXT_INT0 ; IRQ0 Handler rjmp EXT_INT1 ; IRQ1 Handler reti ;TIM2_COMP reti ;TIM2_OVF reti ;TIM1_CAPT ; Timer1 Capture Handler reti ;TIM1_COMPA ; Timer1 CompareA Handler reti ;TIM1_COMPB ; Timer1 CompareB Handler reti ;TIM1_OVF ; Timer1 Overflow Handler reti ;TIM0_OVF ; Timer0 Overflow Handler reti ;SPI_STC ; SPI Transfer Complete Handler reti ;USART_RXC ; USART RX Complete Handler reti ;USART_DRE ; UDR Empty Handler reti ;USART_TXC ; USART TX Complete Handler reti ;ADC ; ADC Conversion Complete Interrupt Handler reti ;EE_RDY ; EEPROM Ready Handler reti ;ANA_COMP ; Analog Comparator Handler reti ;TWSI ; Two-wire Serial Interface Handler reti ;SPM_RDY ; Store Program Memory Ready Handler main: ;Stackpointer ldi temp, LOW(RAMEND) out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;Aus/Eingänge ldi temp, 0x00 out DDRD, temp ;Eingang ldi temp, 0xFF out DDRB, temp ;Ausgang ;Interrupteingänge ldi temp, 0b00001001 ;INT0 und INT1 konfigurieren out MCUCR, temp ldi temp, 0b11000000 ;INT0 und INT1 aktivieren out GIMSK, temp ;PWM ldi temp, 0b00001001 ;Einstellungen siehe Seite 81-83 out TCCR0, temp ldi temp, 0b00111111 out OCR0, temp ;Stellt die Einschaltzeit ein (Alles gesetzte --> immer ein, alles aus --> immer aus) ldi temp, (1<<OCIE0) out TIMSK, temp ldi temp, (1<<OCF0) out TIFR, temp ;Interrupts freigeben sei ;Interrupts allgemein aktivieren Ende: jmp ende EXT_INT0: sbi PortB, 0 reti EXT_INT1: cbi PortB, 0 reti
Im Register TIFR habe ich OCF0 aktiviert. Brauche ich das TIFR Register überhaupt für einen Interrupt?
Ich merke allerdings je mehr ich herumprobiere, desto mehr weiche ich von einer richtigen PWM ab. Es muss doch möglich sein, das man einfach mit einer Phase Correct PWM einen Interrupt bei jeder Änderung aufruft oder?
mfg Gerko
Das TIFR brauchst du dabei nicht. Du kannst aber im Simulator während er läuft auf das entsprechende Kästchen klicken, warauf dann der entsprechende Int ausgelöst wird.
Mit Timer0 im Simular habe ich auch Probleme, weil ich noch eine ältere Version des AVR-Studio habe. Das war auch hier meine erste Frage, weil ich sicher war alles richtig gemacht zu haben, nur es einfach nicht funktionieren wollte. Ich habe dann das Ganze probehalber mit Timer1 laufen lassen und da ging es.
Ja, es wäre vielleicht besser wenn du das Ganze ersteinmal auf eine einfache PWM-Ausgabe an einem Pin reduzierst. Wenn das Codestückchen funktioniert, dann kann man davon ausgehend dazu bauen, bzw umbauen - in kleinen Schritten.
Weniger ist oft mehr!
Grüße
Was mich beunruhigt ist das ich für den Timer0 nur einen Eintrag in der Interruptvektortabelle habe. Für alle anderen sind mehrere vorhanden.
Wo ist eigentlich der unterschied zwischen Timer0, 1 und 2? Ich weiß das der Timer0 eien Auflösung von 8Bit hat, und die anderen 2 eine von 16Bit. Gibts sonst noch unterschiede?
Sollte das OCIE0 Bit im TIMSK Register den Interrupt TIM0_OVF auslösen oder einen anderen?
mfg Gerko
Hallo.
ich fange mal ganz oben an bei der Beantwortung der Fragen die sich bisher aufgestaut haben.
- Wie kann man einstellen das man nicht den OCR0 Port als Ausgang für den Timer haben will, sondern PortB, 0?
In dem man anstatt der Hardware PWM, die manche Timer generieren können eine Software PWM nutzt.- Ist es nicht möglich das man den OCR einfach mit einem anderen Ausgang verbindet?
Nein, das ist nicht möglich.- ... aber später möchte ich damit ja auch 2 Motoren steuern ...
Wenn du dafür 2 PWM's benötigst, nimm am besten den Timer 1 oder einen µC, der dieMöglichkeit hat mit jedem Timer 2 Hardware PWM's zu generieren.- Wie kann ich jetzt einstellen das ich nur in der Software einen Ausgang haben will, nicht aber bei einem Hardwareausgang?
Du lässt die COM?0 & COM?1 Bits auf 0 stehen.- ... Also wie kann ich einen Interrupt auslösen? ... {Anm: Bezug vorherige Frage}
In dem du im TIMSK Register die einsprechenden Bits setzt.
Damit kann z.B. ein Interupt ausgelöst werden wenn:
a) der Zähler überläuft
b) Der Zählerstand = dem Wert im OCR Register entspricht.- Es muss doch möglich sein, das man einfach mit einer Phase Correct PWM einen Interrupt bei jeder Änderung aufruft oder?
Wenn sich die Aussage auf eine Änderung des Zählerstandens bezieht, also z.B. von 21 auf 22, dannmuss die Antwort NEIN lauten.- Was mich beunruhigt ist das ich für den Timer0 nur einen Eintrag in der Interruptvektortabelle habe. Für alle anderen sind mehrere vorhanden.
Es sind auch mehrere ... du hast uns hier schlicht und einfach einen unterschlagen (schau mal im Datenblatt auf Seite 45).
So, und hier noch ein kleines Codebeispiel (für den ATmega16) zum Thema: "Wie erzeuge ich an jedem X - beliebigen Pin eine Pulsweitenmodulation":
Eine Anmerkung zu diesem Code:Code:.nolist .include "m16def.inc" .list .def sregsave = r4 ; SREG Backup .def ch_1 = r5 ; PWM Werte der LED's .def ch_2 = r6 .def ch_3 = r7 .def ch_4 = r8 .def temp = r16 ; temporäre Daten .def pwm_cnt = r17 .CSEG .ORG 0 jmp isr_reset ; Reset Interupt Handler jmp isr_not_used ; INT 0 Interupt Handler jmp isr_not_used ; INT 1 Interupt Handler jmp isr_not_used ; Timer 2 Compare Interupt Handler jmp isr_not_used ; Timer 2 Overflow Interupt Handler jmp isr_not_used ; Timer 1 Capture Interupt Handler jmp isr_not_used ; Timer 1 Compare A Interupt Handler jmp isr_not_used ; Timer 1 Compare B Interupt Handler jmp isr_not_used ; Timer 1 Overflow Interupt Handler jmp isr_not_used ; Timer 0 Overflow Interupt Handler jmp isr_not_used ; SPI Transfer Complete Interupt Handler jmp isr_not_used ; USART RX Complete Interupt Handler jmp isr_not_used ; USART UDR empty Interupt Handler jmp isr_not_used ; USART TX Complete Interupt Handler jmp isr_not_used ; ADC Conversion Complete Interupt Handler jmp isr_not_used ; EEPROM Ready Interupt Handler jmp isr_not_used ; Analog Comperator Interupt Handler jmp isr_not_used ; TWI Interupt Handler jmp isr_not_used ; INT 2 Interupt Handler jmp isr_t0_cp ; Timer 0 Compare Interupt Handler jmp isr_not_used ; Store Program Memory Ready Interupt Handler isr_reset: ldi temp, high(RAMEND) ; STACK initialisieren out SPH, temp ldi temp, low(RAMEND) out SPL, temp in temp, MCUCSR ; Disable JTAG Interface ori temp, (1<<JTD) out MCUCSR, temp out MCUCSR, temp clr temp ; Ports konfigurieren: ldi temp, (1<<DDA0) ; PIN A0, B0, C0, D0 -> Ausgang +H ; Rest: Eingang + Pullup out DDRA, temp out DDRB, temp out DDRC, temp out DDRD, temp ldi temp, 0xFF out PORTA, temp out PORTB, temp out PORTC, temp out PORTD, temp ldi temp, (1<<WGM01) | (1<<CS00) ; Timer 0 konfigurieren out TCCR0, temp ldi temp, 0x80 out OCR0, temp ldi temp, (1<<OCIE0) ; Timerinterupts aktivieren out TIMSK, temp ldi temp, 0x80 ; Defaultwerte setzen mov ch_1, temp mov ch_2, temp mov ch_3, temp mov ch_4, temp clr temp sei ; Interupts Global aktivieren main_loop: ; Irgendwelcher sonstiger Code ; Irgendwelcher sonstiger Code ; Irgendwelcher sonstiger Code jmp main_loop isr_not_used: ; Blanko für nicht genutzte Interupt Handler reti isr_t0_cp: ; Timer 0 Compare Interupt Handler in sregsave, SREG ; Statusregister sichern inc pwm_cnt ; Hilfszähler für die PWM um eins erhöhen cp ch_1, pwm_cnt ; Vergleiche gewünschtes Tastverhältniss mit aktuellem PWM Hilfszählerstand brlo PC+4 breq PC+3 sbi PORTA, 0 rjmp PC+2 cbi PORTA, 0 cp ch_2, pwm_cnt brlo PC+4 breq PC+3 sbi PORTB, 0 rjmp PC+2 cbi PORTB, 0 cp ch_3, pwm_cnt brlo PC+4 breq PC+3 sbi PORTC, 0 rjmp PC+2 cbi PORTC, 0 cp ch_4, pwm_cnt brlo PC+4 breq PC+3 sbi PORTD, 0 rjmp PC+2 cbi PORTD, 0 out SREG, sregsave ; Statusregister wiederherstellen reti
Speziell auf die PWM bezogen ist er sicherlich nicht das Optimum an Code. Dieses hat unter anderem den ganz einfachen Grund, das der derselbige doch noch irgendwo verständlich erscheinen soll, auch ohne das man erst im groß im Datenblatt nachsehen muss, um beispielsweise herauszufinden: Welche Flags denn in welchem Fall bei diversen Befehlen beeinflusst werden und welche Sonderfälle in der PWM hier nun möglich sind.
Im übrigen, ist eine Software PWM doch eher eine Taktzeitaufwändige Aktion (also in dem Fall 128 * 256 Takte für eine Periode) um die so gedimmten LED's noch flimmerfrei wahrzunehmen (also ich sag mal mit einer Refreshrate von 200 Hz) sollte der µC schon mit ca. 6,55 MHz laufen (128 x 256 x 200) was aufgerundet eben mal 8 MHz sind.
Vielleicht sollte man noch erwähnen, das es einen kleinen Fallstrick beim STK 500 gibt, da dort die LED's nicht mit "H" sondern mit "L" Pegel leuchten.
@ Schokohoernl:
Sicherlich kann man mit einem Vernünftig durchdachtem Code eine 16 oder gar 24 Kanal Software PWM zum Dimmen von LED's erzeugen, aber sicherlich nicht "theoretisch" unendlich viele.
Die limitierenden Faktoren sind direkt:
- die Taktfrequenz des Mikrocontrollers
- der Dauer die die Befehle zum Ausführen benötigen
und indirekt:
- die Programmiersprache des Programmieres.
Grüße,
da Hanni.
Hallo da Hanni,
vielen Dank für den Code. Das meiste davon ist ja typunabhängig und den Teil zu durchblicken brauch ich ein wenig Zeit. Gleich aufgefallen ist mir aber das mit der direkten Verwendung des PC. Die Möglichkeit ist mir bislang noch nicht begegnet. Prima!
Gruß!
Ja, sicherlich ist der Großteil recht universell auf diversen ATmegas einsetzbar.Zitat von rungo
Naja, ehe ich mich bei diesem eher simpel gestricktem Code mit 20 Sprungmarken selbst verwirre, mach ich es in dem Fall lieber so.Zitat von rungo
Aber das entscheide ich je nach Fall individuell.
Grüße,
Hanni.
Danke für diese Ausführliche und sehr Hilfreiche Antwort von Hanni. Ich werde jetzt noch ein Wenig an meinem Code herumbasteln, und anschließend warten bis das STK 500 kommt.
Das das STK 500 die LEDs bei low und nicht bei high zum leichten bringt war mir bisher nicht bekannt, aber das ist ja für meine jezigen Testzwecke auch nicht so wichtig denke ich.
Grüße,
Gerko
Kein Problem, wenn du den Code soweit verstanden hast, meld dich einfach mal, dann erkläre ich mal eine Variante, wie man das ganze unter gewissen Voraussetzungen wesentlich verkürzen kann.
Grüße,
Hanni.
Lesezeichen