Hallo! Nicht lachen, aber ich versuche jetzt schon den ganzen Tag einen Timer auf einem atmega16 zum laufen zu bekommen (in C). Kann mir mal bitte jm. ein Bsp für den 8-Bit und den 16-Bit Timer posten? Wäre echt super nett, ich bekomme es einfach nicht hin. Hab schon einiges dazu hier im Forum gelesen, klappt aber leider immer noch nicht. Vielleicht mal zu folgendem Beispiel. Ich habe an PortB 5 LED's hängen, PINB0 - PINB4. Die sollen wie ein Lauflicht durchlaufen, mit 2sec Abstand. Sprich (1<<PINB0), 2sec an, dann aus und LED2 an. Wäre super nett, wenn mir da mal jm. Bsp-Code mit vielen, vielen Kommentaren posten könnte!!! Danke schon mal, Andreas
oder du stellst dein Programm hier rein und wir zerreissen dass dann gnadenlos. Hinterher läufts aber :-)
Ich will ja auch nicht klugsch... aber wär´s nicht einfacher, in Assembler anzufangen? Beispiele dafür gibt´s im Datenblatt des Controllers und in zahllosen Application-Notes und man braucht nur sehr wenige Bytes Code dafür. Übersichtlicher für´s Anfängerauge ist´s auch... Aber muß ja nicht....
Also. Zuerst musst du das TCCR? des jeweiligen Zählers beschreiben. Dann läuft der Zähler, indem er TCNT? alle n Takte (n=Prescalerwert) incrementiert. mit dem TimerInterruptMaskRegister kannst du den OverFlow-Interrupt einschalten. Dann wird immer bei einem Überlauf der Timer-Interrupt ausgeführt. Am Anfang des Chips steht dann die Interrupt-Tabelle. Im Reset-Interrupt steht dann z.B. rjmp RESET und im Timer0-interrupt rjmp TIMER. in Reset initialisierst du den Chip (Stack unbedingt auf RAM-Ende setzen), die Register, etc. und enablest die Interrupts (in Assembler : sei). Am Ende eine Endlosschleife, in die sich der Prozessor einfängt. Der Timer-Interrupt wird nun alle PRESCALE*TIMERBREITE Takte ausgeführt. Timerbreite ist für einen 8bit von 1-256 und für einen 16bit 1-65536. Die Zeitspanne zwischen den Interrupts kannst du mit (PRESCALE*TIMERBREITE)/TAKT ausrechnen. Einstellen tust du die Timerbreite, indem du zu beginn des Timerinterruptes die TCNT-Register analog dem Datenblatt auf einen vordefinierten Wert setzt. Damit beginnt der Timer nicht jedesmal bei 0 mit dem Zählen. In ebendiesem Timer schreibst du dann noch eine Routine, mit der deine LEDs gesetzt werden und fertig. Als beispiel : mit einem 4MHz Takt stellst du Timer1 (16bit) auf einen Prescaler von 256 ein und setzt TCNT1H und TCNT1L (reihenfolge des Beschreibens beachten) auf (65536-31250), also 34286. Dann wird der Timer/Counter Interrupt 1 exakt alle 2sec. ausgeführt. Codebeispiel für die LEDs: im RESET-Teil setzt du PORTB auf 0 (alle 5 LEDs aus) in den TIMER-Teil kommt folgendes : TEMP := PORTB; untere 5 Bits ausmasken TEMP := TEMP shl 1 ; die Bits um 1 nach links schiften (0 in BIT 0 schiften) TEMP := TEMP AND 0x1F ; die oberen 3 Bits ausmasken if TEMP = 0 then TEMP = 1 ; wenn keine LED an (Bit ist ausmaskiert worden, dann schalte PORTB.0 an. PORTB := TEMP So oder so ähnlich sollte es dann ablaufen. Code ist nicht getestet und da ich nur Assembler programmiere auch nicht in der C-Syntax. Fragen, welche IO-Register wie zu verwenden und einzustellen sind, beantworte ich mit einem Verweis auf www.atmel.com. Ziehe dir dort das betreffende Datenblatt und lies es einfach nach. Hoffe das hilft weiter
> Ich will ja auch nicht klugsch... aber wär´s nicht einfacher, in > Assembler anzufangen? Mit der Meinung stehst du aber nicht alleine da... ;-) Gruß von MD nach HBS... ...
So, danke erst mal für die Antworten, wobei nicht alle produktiv waren. Ich habe mich daran gemacht, AVR's mit C zu programmieren, da ich von C ein bisschen Ahnung habe, von Assembler aber gar keinen. In den Datenblättern gibt es unter jedem Assembler Beispiel-Code auch den C-Code. Zumindest in denen, in denen ich bis jetzt geschaut hab. Aber das soll ja jetzt auch erst mal nebensächlich sein, kann ja jeder machen wie er will. Ich will das auf jeden Fall in C lernen. Ich poste jetzt einfach mal meinen Code, ist ein bisschen umfangreich. Kann mir jm. sagen, was da falsch ist, bzw. das nicht funktioniert??? #include <avr/io.h> #include <avr/interrupt.h> #include <avr/delay.h> #include <stdint.h> #include <avr/delay.h> int counter = 0; int led_on = 0; static void io_init(void) { PORTA =0xff; //eingänge DDRA = 0x0; // PortB PORTB = 0x0; //ausgänge, an 0, 1, 2, 3, 4, hängen die LED's DDRB = 0xff; // PortC PORTC = 0x0; //ausgänge DDRC = 0xff; // PortD PORTD = 0x0; //ausgänge DDRD = 0xff; ACSR = 0x80; } void timerinit(void){ //jetzt kommt die sache mit dem Timer TCCR0 |= (1<<CS00)|(1<<CS02); sei(); //sollte doch heißen, dass der CPU-Takt / 1024 geteilt wird und dann der //counter immer um eins hochgezählt wird. //bei 16MHz wären das dann immer noch 15,625KHz } //in TCNT0 wird doch jetzt immer um eins hoch gezählt, wenn 1024 Prozessor-Takte //vorbei sind. Wenn der TCNT0 = 0xFF ist doch der Überlauf und es wird ein //INTERRUPT ausgelöst, was zur folge hat, dass diese Funktion aufgerufen wird, oder? SIGNAL(SIG_OVERFLOW0)/* signal handler for tcnt0 overflow interrupt */ { counter++; //eine Fariable um 1 hochzählen } int main(void) { io_init(); timerinit(); while(1) { if (counter == 60){ //wenn der counter 60 Mal um eins hochgezählt wurde, //ist in etwa eine Minute vorbei counter = 0; //counter wieder auf null setzen PORTB = (1 << PINB1); if(led_on == 0){ PORTB = (1 << PINB0); //led0-anschalten led_on++; return; } if(led_on == 1){ PORTB = (1 << PINB1); //led1-anschalten led_on++; return; } if(led_on == 2){ PORTB = (1 << PINB2); //led2-anschalten led_on++; return; } if(led_on == 3){ PORTB = (1 << PINB3); //led3-anschalten led_on++; return; } if(led_on == 4){ PORTB = (1 << PINB4); //led4-anschalten led_on = 0; return; } } } return(0); } Wäre nett, wenn mir jm. weiterhelfen könnte. Ich weiß, das ist ne Anfängerfrage, aber ich bekomme es halt nicht hin. Wenn also mal jm. drüber schauen könnte, der sich damit besser auskennt als ich und mir nicht nur sagen will, das ich besser mit Assembler programmieren sollte, wäre ich euch echt dankbar! mfg Andreas
Den counter musst Du volatile definieren, sonst könnte es sein, dass der Compiler das innerhalb des Hauptprogramms in ein Register hineinoptimiert. Also: volatile int counter;
Hallo! Vielen Dank für eure Hilfe! Ich hab das jetzt mal so abgeändert, habe die Variable counter mit volatile definiert. Meine init_counter sieht jetzt so aus: TIMSK=0x01; //Timer/Counter Interrupt Mask TCCR0=0x02; //Timer/Counter Control Register auf CK/8 sei(); //All Interrupt enable Wenn ich mir das jetzt simulieren lasse, zählt der counter auch, also TCNT0 zählt hoch. Wenn es jetzt zu einem überlauf kommt, sprich, wenn TCNT0 = 0xFF, dann wird einfach meine main - Funktion neu aufgerufen, sprich init_io in meinem Programm. Warum springt das Programm nicht in meine SIGNAL(SIG_OVERFLOW0) Funktion? Ist die überhaupt richtig angelegt so, oder hab ich da was falsch gemacht? DANKE!!!!!!
Wenn du SIGNAL verwendest, dann musst du auch signal.h includieren #include <avr/signal.h> sonst kommts zu diesem Effekt.
freu Vielen Dank euch allen, ihr seit super! :) Funktioniert jetzt endlich. Danke noch mal!!!!
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.