Hi Freaks, nachdem Ihr mir so gut beim letzten Mal geholfen habt, komme ich mit noch einem Problem. Das hängt zusammen mit dem Heizkörperthermostat, den ich neu programmieren will, hier der Artikel dazu in der Wiki: Heizungssteuerung mit Honeywell HR20 Eckdaten: - ATMega169 - Frequenz 1 MHz (CKDIV8, CKSEL 0010, SUT=10) - Timer 0 Jetzt weiss ich aus der Analyse, des bestehenden Thermostaten, dass der ein PWM-Signal an PB4/OCOA mit der Frequenz von 15,625 kHz und den Verhältnissen 44.5us:19.5us und 19.5us:44.5us erzeugt. Würde der Counter jetzt von 0-255 zählen wäre dass der compare value von 179 im normalen bzw. im invertierten Betrieb. Aber dann komme ich nur auf 3,9kHz (1/256 von 1MHz). Die gemessenen 15,625 kHz sind 1/64 der 1MHz. Jetzt die Fragen: 1.) Wie kann ich die 15,625 kHz mit 1MHz erreichen? 2.) Oder soll ich lieber die Frequenz temporär mit CLKPS3..0 auf 4Mhz erhöhen wenn ich den Motor anschmeisse und danach wieder auf 1MHz schalten. Der Motor läuft ja weniger als 0,1% der Zeit. 3.) Ist das für so einen Mini-Gleichstrommotor sowieso egal, ob die PWM-Frequenz bei 4kHz oder 16kHz liegt? In der Hoffnung auf fachkundige Hilfe, Dario.
Dario C. wrote: > Jetzt die Fragen: > > 1.) > Wie kann ich die 15,625 kHz mit 1MHz erreichen? 1MHz/15,625kHz=64 Demnach muss der Timer nur bis 63 zählen. Das geht bei den meisten AVRs auch, indem man einen PWM Modus wählt, bei dem man den TOP Wert vorgeben kann. > 2.) > Oder soll ich lieber die Frequenz temporär mit CLKPS3..0 auf 4Mhz > erhöhen wenn ich den Motor anschmeisse und danach wieder auf 1MHz > schalten. Der Motor läuft ja weniger als 0,1% der Zeit. Ist auch möglich, aber eigentlich unnötig. > 3.) > Ist das für so einen Mini-Gleichstrommotor sowieso egal, > ob die PWM-Frequenz bei 4kHz oder 16kHz liegt? Weitestgehend. Die Frage ist, ob die Elektronik dazwischen ausreichend schnell ist.
Benedikt K. wrote: > 1MHz/15,625kHz=64 > Demnach muss der Timer nur bis 63 zählen. Das geht bei den meisten AVRs > auch, indem man einen PWM Modus wählt, bei dem man den TOP Wert vorgeben > kann. Und genau den finde ich nicht bei dem ATMega1169 am Timer0. Und es muss Timer0 sein, da das ja in der Originalschaltung verkabelt ab PB4, also OC0A funktioniert. Im Datenblatt zum Mega169 steht nämlich: Seite 80 BOTTOM whern it becomes 0x00 MAX whern it becomes 0xFF TOP ... can be stored in the OCR0A Register Seite 85 Fast PWM Mode: ... The counter counts from BOTTOM to MAX ... Seite 86 Phase Correct PWM Mode: ... The counter counts from BOTTOM to MAX ... Ich sehe nicht, wie ich den Timer0 einen PWM Modus wählen kann, bei dem ich den TOP != MAX wähle. Spricht denn generell was dagegen zwischenzeitich über das CLKPR Register die Clock zu verändern (insbesondere wenn die Echtzeituhr asynchron über einen 32kHz Quarz gemacht wird)? Dario
Dario C. wrote: > Und genau den finde ich nicht bei dem ATMega1169 am Timer0. Der kann das nur bei Timer1 (mittels OCR1A oder ICR1). > Spricht denn generell was dagegen zwischenzeitich über das CLKPR > Register die Clock zu verändern (insbesondere wenn die Echtzeituhr > asynchron über einen 32kHz Quarz gemacht wird)? Generell nicht. Allerdings musst du schauen was du so alles laufen hast: UART, Timer, ADC usw. laufen dann alle schneller. Das sollte man berücksichtigen.
Würde das dann so gehen?
1 | cli(); |
2 | CLKPR=(1<<CLKPCE); |
3 | CLKPR=(1<<CLKPS0); |
4 | sei(); |
Nicht dass mir da der Compiler was wegoptimoert.
Ja, aber pack noch ein asm("nop"); hinter das cli(); denn die Interrupts werden erst einen Takt später abgeschaltet.
Hi Benedikt
> Ja, aber pack noch ein asm("nop"); hinter das cli();
Danke.
Das cli(); habe ich nur Proforma da hin geschrieben, denn ich habe
mich entschlossen alles auf 4MHz laufen zu lassen (dann kann ich eben
mehr sleepen)
Die Frequenz stelle ich nach einem Reset ein, wo die Interrups sowieso
aus sind.
Danke nochmal an alle,
Dario
@ Benedikt K. (benedikt) >Ja, aber pack noch ein asm("nop"); hinter das cli(); denn die Interrupts >werden erst einen Takt später abgeschaltet. Käse. Nach cli() ist definiv Ruhe. Sonst würde cli() gar nicht funktionieren, weil der RETI der ISR das I-Bit wieder anschalten würde. MFG Falk
Falk Brunner wrote:
> Käse. Nach cli() ist definiv Ruhe.
Irgendwas gabs da doch mit den Interrupts, was einen Takt verzögerung
hatte, war das dann bei sei ?
- Zwischen zwei Interrupts wird immer noch eine Instruktion ausgeführt. - Laufende Mehrtaktbefehle werden beim Auftreten eines Interrupts zu Ende ausgeführt. Vielleicht hattest du davon einen im Kopf... Die cli/sei-Klammer wird auch im Datasheet in den Codebeispielen verwendet.
Ich habs gefunden: Es ist bei sei, aber angeblich nirgends dokumentiert: Beitrag "Re: Compilerbug bei AVR-GCC ?: Stack Pointer und Interrupts"
Na ja... in der Instruction Set-Doku findet sich bei SEI folgender Absatz...
1 | sei ; set global interrupt enable |
2 | sleep ; enter sleep, waiting for interrupts |
3 | ; note: will enter sleep before any pending interrupt(s) |
In der Doku zum ATmega16 findet sich darüber: When using the SEI instruction to enable interrupts, the instruction following SEI will be executed before any pending interrupts, as shown in this example. ... Ich würd's schon als dokumentiert bezeichnen ;)
Kai Giebeler wrote: > When using the SEI instruction to enable interrupts, the instruction > following SEI will be executed before any pending interrupts, as shown > in this example. Das trifft übrigens nur auf das /Zu/schalten der Interrupts zu, nicht auf das Abschalten. Daher ist der NOP oben nicht nötig. > Ich würd's schon als dokumentiert bezeichnen ;) Dokumentiert ist es für SEI, nicht aber für den (beim GCC genutzten) impliziten Fall, dass das I-Bit durch das Zurückspeichern des SREG eingeschaltet wird.
>Das trifft übrigens nur auf das /Zu/schalten der Interrupts zu, >nicht auf das Abschalten. Daher ist der NOP oben nicht nötig. Bezog sich ja auch nicht mehr auf das Originalposting sondern auf Benedikts Querverweis. >Dokumentiert ist es für SEI, nicht aber für den (beim GCC genutzten) >impliziten Fall, dass das I-Bit durch das Zurückspeichern des SREG >eingeschaltet wird. Hier noch ein paar Indikatoren, die dafür sprechen:
1 | _SEI(); /* set global interrupt enable */ |
2 | _SLEEP(); /* enter sleep, waiting for interrupt */ |
3 | /* note: will enter sleep before any pending interrupt(s) */
|
(ohne Anmerkungen zu den Implementierungsdetails von _SEI()) Die Beschreibung zum I-Bit im SREG nennt keinen Unterschied zwischen dem Setzen per SREG oder CLI/SEI: The I-bit can also be set and cleared by the application with the SEI and CLI instructions, as described in the instruction set reference. Das Verhalten beim Setzen des Flags deckt sich mit dem einer RETI-Anweisung: When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction before any pending interrupt is served. Last but not least: SEI ist ja nur ein Alias von BSET 7 in dessen Doku das Warteverhalten auch Erwähnung finden müsste - steht aber nicht drin. Ich gehe also davon aus, dass die Verhaltensbeschreibung von SEI irreführender Weise für alle Varianten zum Setzen des I-Bits gelten. Ich sehe aber den verbleibenden Interpretationsspielraum. Insofern danke für die Ergänzung.
Komische Logik. Da habe diverse Leute das Verhalten von SEI im Kopf und schliessen daraus auf das Verhalten von CLI. Es wird dazu sogar die Doku zu SEI zitiert. Aber auf die Idee direkt bei CLI nachzusehen kommt keiner? "No interrupt will be executed after the CLI instruction, even if if occurs simultaneously with the CLI instruction".
Danke, das haben wir oben auch schon ein paar mal festgestellt! Benedikt hatte nur ein verwandtes Thema angesprochen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.