Hallo ihr, erstmal kurz vorab ich habe sehr wenig Kenntnisse in µC Programmierung und das nach LED an aus schalten meine ersten Versuche, also entschuldigt meine vllt einfachen Fragen ich habe ein Problem mit dem 16 bit Timer. Ich sitze schon mehrere Tage an diesem Problem. Also mein Ziel: Ich will einen Takt erzeugen. (siehe Bild) Könnt ihr mir einen Tipp geben wie ich da am besten rangehe. Soweit ich das mitbekommen habe gehen solche niedrigen Frequenze nicht mit dem 8 Bit Timer sonder nur mit dem 16 bit Timer. Mein Ansatz nun: Atmel Timer Calculator Prescaler , TCNT1H und L berchnen. Dies habe ich dann auch in meinen Quellcode eingetragen leider kam immer die flasche Frequenz raus bzw gar nichts. Noch kurz als Info ich Programmiere in C mit dem STK500 und mein µC ist ein Atemega16. Quellcode: #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #include <timer_set.h> #include <avr/delay.h> SIGNAL (SIG_OVERFLOW1){ TCNT1L=0x24; // für 4 sec. Periodendauer TCNT1H=0xF4; } int main (void) { DDRC = 0xff; DDRD = 0xff; PORTD |= (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7) ; TCCR1A= (1<<COM1A1) | (0<<COM1A0) | (0<<WGM11) | (0<<WGM10);// pwm aus durch wgm 0 TCCR1B=(1<<CS10) | (1<<CS12); // Prescaler 1024 for (;;) { } ist dieser Ansatz völlig falsch? Wie kann ich die beiden geforderten Signale generieren? Danke
SIGNAL ist lange veraltet. signal.h rauswerfen und ISR verwenden. Was aber echt fatal ist:
1 | |
2 | TCNT1L=0x24; // für 4 sec. Periodendauer |
3 | TCNT1H=0xF4; |
Das High-Byte muss bei solchen 16-Bit-Registern immer zuerst geschrieben werden. Schau mal im Datenblatt nach, da ist bei dem 16-Bit-Timer ein extra Abschnitt zum Thema "Accessing 16-bit registers". Allerdings programmierst Du in C und kannst den Krempel mit der Zugriffsreihenfolge ganz komfortabel dem Compiler überlassen. Der kennt nämlich ein 16-Bit-(Pseudo-)Register TCNT1 (ohne L und H), und der macht daraus automatisch die richtige Zugriffssequenz. Also
1 | TCNT1 = 0xF424; |
tut's auch. Oder noch einfacher
1 | TCNT1 = 62500; |
Und wenn Du einen Interrupt benutzen willst, dann musst Du den auch freigeben. In Deinem Code ist aber weder eine lokale Freigabe über das entsprechende Enable-Bit noch die globale Freigabe zu sehen. Schau Dir bitte im AVR-GCC-Tutorial an, wie es geht. Da steht eigentlich alles drin. Es macht so wenig Sinn, in Deinem obigen Code noch nach irgendwelchen Fehlern zu suchen. Vor Allem solltest Du Dich über die unterschiedlichen Betriebsarten der Timer informieren (v.a. CTC und PWM). Die sind für Dein Vorhaben nämlich wesentlich besser geeignet als ein Timer-Reload, der beim AVR eigentlich generell keinen großen Sinn macht. Mit welcher Taktfrequenz läuft Dein Controller überhaupt? 62500 als Reload-Wert für 4 Sekunden lassen auf eine Taktfrequenz von unter 1 MHz schließen... ...und da Du das TCNT1 am Anfang nicht initialisierst, läuft der Timer erst mal von Null an bis zum ersten Overflow. Und das dauert bei einem Prescaler von 1024 sehr lange (bei 1 MHz mehr als eine Minute)...
Vielen Dank für die schnelle Antwort. Also mein Atmega16 müsste nach meinem Wissenstand mit 16 MHZ laufen. Ich habe da wie gesagt so ein Tool womit man das ausrechnet, wie TcCNTL und H aussehen müssen. Das mit dem von = anlaufen ist mir auch schon aufgefallen das am Anfang das sehr lange dauert. Also sagst du PWM. Noch eine schwierigkeit mehr:-) Naja danke erstmal. vllt findet sich ja noch jmd der mir weiterhelfen kann.
Marco Müeller wrote: > vllt findet sich ja noch jmd der mir weiterhelfen > kann. Mein Tip. Leg dieses Berechnungstool erst mal zur Seite und bemüh dich zu verstehen, wie ein Timer arbeitet und wie der Zusammenhang zum Prescaler ist. Das ist im Grunde Watscheneinfach. Und erst dann, wenn du die Prescaler bzw. Comparewerte mit der hand ausrechnen kannst (und das auch am 'lebenden' Objekt überprüft hast), dann benutze wieder das Tool um dir die fade Rechnerei zu ersparen. Auch das beste Tool hilft nichts, wenn man nicht versteht was da eigentlich abgeht.
Marco Müeller wrote: > Ich habe da wie gesagt so ein Tool womit man das ausrechnet, wie TcCNTL > und H aussehen müssen. Das kannst Du dir wie schon geschrieben sparen.. das macht der C-Compiler AUTOMATISCH. TCNT1 = x; reicht völlig aus und lenkt dich nicht vom wesentlichen ab, wie zB: sei(); // Interrupts global ein oder die Einstellung der fCPU-Register.. Lies Dir wirklich erstmal das Tutorial durch, da klären sich 99% der Fragen die Du grad hast von selber und ganz andere treten an deren Stelle ;-)
So also das habe ich bisher auf die Beine gestellt: Ist das mit den Interrupts ausschalten richtig? wann muss ich die Interrupts mit sei() zulassen? so wie ich jetzt mein Programm verstanden habe zählt der der zähler von 0 bis 65500 und dann wieder zurück, jedesmal wenn er den wert im vergleichsregister OCR1A erreicht lösst er einen Interrrupt aus. Und mit TCNT1 lade ich den Zähler dann vor, damit er dann nicht wieder von 0 anfängt oder wie? kann mir jmd nochmal die Formel hier rein schreiben, mit der ich mir die frequenz mit prescaler usw ausrechnen kann? Und im Datenblatt habe ich was von wegen BOTTOM und TOP gelesen für hoch und runter zählen wofür brauch man das? #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #include <avr/delay.h> SIGNAL (SIG_OVERFLOW1){ cli(); //interruptsausschalten TCNT1 = 0x1856; //eigentlich tcntl und h aber das weiss compiler } int main (void) { DDRC = 0xff; DDRD = 0xff; TCCR1A= (1<<COM1A1) | (0<<COM1A0) | (1<<WGM11) | (1<<WGM10);// pwmaus durch wgm 0 // Hochzählen OC1 auf 0 runter auf 1| 10-Bit PWM Betriebsart aktivieren. TCCR1B=(1<<CS10) | (1<<CS12); // Prescaler 1024 //TCCR1B=(1<<ICES1) ; //input compare steigende flanke auswertung //TCCR1B=(1<<CTC1); // Clear Timer/Counter on Compare Match Timer/Counter 1 OCR1A=6500; //compare register; for (;;) { } }
Noch mal: SIGNAL ist veraltet. Mach es so, wie es im AVR-GCC-Tutorial steht. Die delay.h steht auch nicht mehr im Ordner "avr", sondern unter "util". Also
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <util/delay.h> |
4 | |
5 | //und dann:
|
6 | ISR(TIMER1_OVF_vect) |
7 | {
|
8 | //Code
|
9 | }
|
Aber der Rest macht auch keinen Sinn! Bitte bitte bitte lies Dir das im Tutorial genau durch! Das ICES1-Bit hat mit Deiner Anwendung überhaupt nichts zu tun. Und Du lädst im Interrupt Handler immer noch den Timer nach, was völliger Unsinn ist. Außerdem gibst Du nach wie vor den Interrupt nicht frei, weder lokal noch global! Und ich frage mich, was Du für ein Datenblatt hast. CTC1 ist ein veralteter Bitname, und das steht in den aktuellen Datenblättern auch drin. Das Sperren der Interrupts im Interrupt Handler ist ebenfalls überflüssig. Das passiert automatisch durch die Controller-Hardware. Deine Ungeduld bringt gar nichts. Setz Dich in aller Ruhe hin und lies Dir die entsprechenden Passagen in der Literatur durch.
So folgendes hier sind auszüge aus dem AVR-GCC-Tutorial 8-Bit Timer zB zuerst stehen da in welchem register sich was befindet usw, schön und gut dann kommt dieser Absatz hier: Der Zähler zählt nun aufwärts bis 255, um dann wieder bei 0 zu beginnen. Der aktuelle Zählerstand steht in TCNT0. Bei jedem Überlauf von 255 auf 0 wird das Timer Overflow Flag TOV0 im Timer Interrupt Flag TIFR-Register gesetzt und, falls so konfiguriert, ein entsprechender Timer-Overflow-Interrupt ausgelöst und die daran gebundene Interrupt-Routine abgearbeitet. Das TOV Flag lässt sich durch das Hineinschreiben einer 1 und nicht wie erwartet einer 0 wieder zurücksetzen. Kann mir einer sagen was ein blutiger Anfänger mit sowas anfangen soll? Interrupts kommen auch erst später im Tutorial. Ich weiss nicht was daran so schwer ist mir ein einfaches Beispiel zu geben mit dem ich das dann nachvollziehen könnte. Wenn jmd von mir zum Beispiel Integralrechnung erklärt haben wollte dann würde ich ihm auchein einfaches Beispiel zeigen und nciht sagen "lies dir mal das und das buch durch" Danke
> Das ICES1-Bit hat mit Deiner Anwendung überhaupt > nichts zu tun. Deshalb ist es ja ausgeklammert > Und ich frage mich, was > Du für ein Datenblatt hast. CTC1 ist ein veralteter Bitname, und das > steht in den aktuellen Datenblättern auch drin. Deshalb auch ausgeklammert nur damit ich weiss das das eigentlich der CTC befehl ist
So, ich hab mir grad mal im Tutorial die betreffenden Passagen angesehen, und festgestellt, dass da tatsächlich etwas Überarbeitungsbedarf besteht. Der CTC-Modus wird gar nicht explizit erwähnt, was mir entgangen war. Abgesehen davon willst Du etwas mit dem 16-Bit-Timer machen (und nicht mit nem 8-Bit-Timer), weshalb Du natürlich besser den Abschnitt über den 16-Bit-Timer als Referenz nimmst. Für Dein derzeitiges Vorhaben, ein Signal an einem Portpin auszugeben, brauchst Du auch zunächst gar keinen Interrupt. Das Schalten des Portpins kann der µC auch allein machen, ohne dass das Programm eingreifen muss. Das Beste ist, sich das Datenblatt des µC (und zwar des Mega16 und nicht des Mega8, auf den sich das Tutorial bezieht) zur Hand zu nehmen und dort in den Tabellen nachzuschlagen, welche Bits für welche Betriebsart gesetzt werden müssen. Das ist in den betreffenden Passagen eigentlich sehr schön übersichtlich zusammengefasst. Der CTC-Modus (Clear Timer on Compare match) ist eine Betriebsart, in der der Timer bei Erreichen des Compare-Wertes in dem betreffenden Compare-Register zurückgesetzt wird. Beim Compare-Ereignis kann zusätzlich noch ein bestimmter Portpin automatisch umgeschaltet werden (was Du ja auch schon versucht hast, über die COM-Bits einzustellen). CTC bildet im Prinzip die Grundlage für PWM. Bei der PWM kommt dann eben zusätzlich eine zweite Compare-Einheit ins Spiel. Wie gesagt: Lass die ganze Interrupt-Sache erst mal weg und versuche, an einem OC-Pin ein Signal auszugeben.
Anbei mal eine Art "AVR-Tutorial", das zur Verwendung zusammen mit dem entsprechenden Controller-Datenblatt ausgelegt ist. Ich habe versucht, die wichtigen Komponenten und ihre Anwendung im Klartext verständlich zu beschreiben. Es werden dabei allerdings meist keine direkten Beispiele in Sachen I/O-Register u.ä. gegeben, v.a. weil es recht universell sein soll, und bei unterschiedlichen AVRs auch unterschiedliche Dinge zu beachten sind. Die konkreten Bitkonfigurationen für die Steuerregister muss man sich dann anhand des Datenblattes herleiten. Ist eben eigentlich für Studenten im Rahmen eines Programmierpraktikums gedacht, aber vielleicht hilft es Dir auch, gewisse Zusammenhänge zu verstehen.
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.