Hi, wollte mir vl mal ne uhr oder so bauen,
aber der code soll bisjetzt blos einen ausgang dauerhaft blinkenlassen,
und mit interrupt nach 1s einen anderen ausgang dauerhaft einschalten.
Jetzt hab ich das Problem, das der eine zwar dauerhaft blinkt,
aber der andere der nach einer sekunde dauerhaft an sein soll
erst nach ca 8s. mal kurz blinkt, und dann wieder nach ca.8s ....
1 | #include <inttypes.h>
| 2 | #include <avr/io.h>
| 3 | #include <avr/interrupt.h>
| 4 | #include <util/delay.h>
| 5 | #include <stdlib.h>
| 6 |
| 7 | // Initialisierung vom Timer1
| 8 | void init_timer_1(){
| 9 | TCCR1A = 0x00; // PWM ausgeschaltet, Es gibt kein signal nach ausen
| 10 | TCCR1B = (1<<3)|(1<<2)|(0<<1)|(0<<0); //3 = bei erreichen des vergleichwertes auf 0 setzen 2-1-0 = 100= teiler auf 256 010=8
| 11 | OCR1AH=0x7A; //höherwertiges bit des vergleichwertes //es wird bis 31250 gezählt, (8Mhz/256)=1s
| 12 | OCR1AL=0x12; //niederwertiges bit der vergleichwertes
| 13 | TIMSK = 0xff;//(1<<6)|(1<<7);//Interupt bei compare enable
| 14 | }// init_timer_1
| 15 |
| 16 |
| 17 | ISR(TIMER1_COMPA_vect) {//Timerinterupt
| 18 | PORTD|=(0 << 0) | (0 << 1) | (0 << 2) | (0 << 3) | (0 << 4) | (0 << 5) | (1 << 6) | (0 << 7);
| 19 | //sollte ausgang PD6 dauerhaft ein schalten
| 20 | }//Timerinterupt TIMER1_COMPA_vect
| 21 |
| 22 |
| 23 | int main (void)
| 24 | {
| 25 | DDRD = (0 << 0) | (0 << 1) | (0 << 2) | (0 << 3) | (0 << 4) | (1 << 5) | (1 << 6) | (0 << 7); //festlegen der ein0/ausgänge1
| 26 | PORTD = 0; //alle ausgänge des PortD sind auf 0
| 27 |
| 28 | init_timer_1();//Timer 1 Initialisieren
| 29 | sei(); //interupts aktivieren
| 30 |
| 31 | while(1)
| 32 | {
| 33 | //einen ausgang immer abwechselnd ein/aus schalten
| 34 | if(bit_is_set (PORTD,5)){
| 35 | PORTD&=(1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (0 << 5) | (1 << 6) | (1 << 7);
| 36 | }else{
| 37 | PORTD|=(0 << 0) | (0 << 1) | (0 << 2) | (0 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (0 << 7);
| 38 | }
| 39 | }
| 40 | return 0;
| 41 | }
|
ich betreibe den ATMega16 auf dem Pollin Ev.Board
Quarz=8Mhz;
Compiliere mit WinAVR
Übertrage mit Ponyprog
Fusebits: BOTSZ1, BOTSZ0, SUT0, CKSEL3, CKSEL2, CKSEL1 (haben alle
hacken)
Hallo,
1. Deine Fusebits dürften der Auslieferungszustand sein, also läuft der
Mega16 mit 1MHz intern.
8MHz externer Quarz wäre CKSEL3...0 auf 1, also bei Pony Haken raus.
2. Sind Deine LED zwischen Ausgang und GND oder zwischen Ausgang und +
angeschlossen?
Die &-Verknüpfung in der While-Schleife macht vermutlich nicht, was Du
erwartest.
Gruß aus Berlin
Michael
Ja, sie waren noch im Auslieferungszustand, hab jetzt die hacken raus,
es sind jetz nur noch die hacken bei
Fusebits: BOTSZ1, BOTSZ0, SUT0
drin.
Meine LED sind zwischen Ausgang und GND => müssten bei ausgang HI
leuchten
Die & verknüpfung in der whileschleife...
soll rücksetzen wenn ausgang aktiv, und setzen wenn inaktiv,
(das scheint sie auch zu machen, nur halt so schnell das man es nicht
sieht)
Jetzt ist nur noch das Problem das der Ausgang den der Timerinterupt
setzen soll nur ganz kurz aufblinkt
Ich habe mal wie in einem anderen Thema empfohlen einen Kondensator
zusätzlich nahe am uC angeschlossen (+->GND) hilft aber auch nichts
Hilfe !!!
Weis denn keiner eine Antwort ?
Ich verstehe deine Fragestellung nicht ganz und müsste mich erst
durchkämpfen.
EDIT: Hier wurde ein Teil gelöscht. Der falsche Takt wurde bereits
festgestellt. Anpassung der folgenden Vermutungen dazu spare ich mir ;-)
Die Analyse eines Timer-Codes ist IMHO ja müssig, wenn der µC mit einem
anderen als dem erwarteten Takt rennt.
OK, soweit bin ich
1 | #include <inttypes.h>
| 2 | #include <avr/io.h>
| 3 | #include <avr/interrupt.h>
| 4 | #include <util/delay.h>
| 5 | #include <stdlib.h>
| 6 |
| 7 | // Initialisierung vom Timer1
| 8 | // als Clear Timer on Compare Match (CTC) Mode
| 9 | // (Mode 4 Tabelle 47 Atmega16 Datenblatt)
| 10 | void init_timer_1()
| 11 | {
| 12 | // PWM ausgeschaltet, Es gibt kein Signal nach aussen
| 13 | TCCR1A = 0x00;
| 14 |
| 15 | // Bit
| 16 | // 3 : bei Erreichen des Vergleichwertes auf 0 setzen
| 17 | // 2-1-0 : 100 : Teiler auf 256
| 18 | // 010 : 8
| 19 | TCCR1B = (1<<3) | (1<<2); // Teiler 256
| 20 |
| 21 | /*
| 22 | To do a 16-bit write, the High byte must be written
| 23 | before the Low byte.
| 24 |
| 25 | For a 16-bit read, the Low byte must be read before
| 26 | the High byte.
| 27 | */
| 28 |
| 29 | // Höherwertiges Bit des Vergleichwertes
| 30 | // es wird bis 31250 gezählt, (8 Mhz / 256) = 1 s
| 31 | OCR1AH = (31250 & 0xFF00) >> 8;
| 32 |
| 33 | // Niederwertiges Bit des Vergleichwertes
| 34 | OCR1AL = 31250 & 0x00FF;
| 35 |
| 36 | //Interupt bei Compare enable
| 37 | TIMSK = 0xff; //(1<<6)|(1<<7);
| 38 | }
| 39 |
| 40 |
| 41 | //Timerinterupt TIMER1_COMPA_vect
| 42 | ISR(TIMER1_COMPA_vect)
| 43 | {
| 44 | // Ausgang PD6 dauerhaft einschalten
| 45 | PORTD |= (1 << 6); // PD6 HIGH
| 46 | }
| 47 |
| 48 |
| 49 | int main (void)
| 50 | {
| 51 | // Pin 5 und 6 Ausgänge, Rest Eingänge (unbenutzt)
| 52 | DDRD = (1 << 5) | (1 << 6);
| 53 |
| 54 | // alle Ausgänge des PortD sind auf 0 (LOW)
| 55 | PORTD = 0;
| 56 |
| 57 | init_timer_1(); // Timer 1 initialisieren
| 58 | sei(); // Interupts global aktivieren
| 59 |
| 60 | while(1)
| 61 | {
| 62 | // Ausgang an Pin 5 abwechselnd ein/aus schalten
| 63 | PORTD ^= (1 << 5); // PD5 toggeln mit XOR
| 64 |
| 65 | // 1s = 1000 ms warten
| 66 | // 1000 setzt aktuelle avr-libc voraus s. Doku
| 67 | _delay_ms(1000);
| 68 | }
| 69 |
| 70 | return 0;
| 71 | }
|
Du siehst, ich habe die Bitfummeleien (für mich) lesbarer geschrieben.
Aus deiner Beschreibung und dem Originalcode ist mir nicht klar, was du
bei welcher LED bzw. Pin du beobachtest.
Deine while(1) Hauptschleife wechselt quasi ohne Wartezeiten PD5. Noch
extremer in meinem Umschrieb mit dem Toggeln ohne Abfrage. Ich würde
erwarten, dass man mit dem Auge kein Blinken beobachten kann.
Deshalb habe ich in der umgeschriebenen Source ein 1s Warten
hinzugefügt. Eine LED PD5 sollte mit 1s hell/1s dunkel blinken, wenn
F_CPU + Fuses + Taktquelle stimmen und mit Optimierung übersetzt wurde.
Ein langsameres Blinken wäre ein Zeichen für falschen Takt. Kein Blinken
ein zeichen für Fehler in der Schaltung und/oder beim Programmieren.
Die ISR(TIMER1_COMPA_vect) sieht OK aus.
Bei der init_timer_1() war ich gerade dran, deine Bitnummern und
Hexwerte mit dem Datenblatt zu vergleichen und Kommentare zu dem
einzufügen, was ich meine, was du machen willst.
Für mich lesbarer habe ich das Setzen des Compare-Wertes geschrieben und
ich habe die Reihenfolge des 16-Bit Register-Schreiben gecheckt.
Bin aber noch nicht fertig. Verdächtig ist mir die Zeile
> TIMSK = 0xff; //(1<<6)|(1<<7);
denn das würde bedeuten
TICIE1 Timer 1 Input Capture Interrupt Enable
OCIE1A Timer 1 Output Compare A Match Interrupt Enable
OCIE1B Timer 1 Output Compare B Match Interrupt Enable
TOIE1 Timer 1 Overflow Interrupt Enable
Und da 3 von 4 Interruptroutinen fehlen... rattert der µC wohl in den
Reset. Nach dem Reset wird der Anfang von main() wieder durchlaufen,
d.h. PD5 und PD6 in "Grundstellung".
Wenn die LED an PD6 diese ist:
> der andere der nach einer sekunde dauerhaft an sein soll erst nach
> ca 8s. mal kurz blinkt, und dann wieder nach ca.8s beschrieben wird
würde das zu falschem Takt (1 MHz statt 8 MHz) und Reset durch fehlende
ISRs passen.
Das Blinken der LED an PD5 verstehe ich nicht, wenn in while(1) nichts
wirklich wartendes ist.
Aber mich macht das in deiner Source ungenutzte #include <util/delay.h>
stutzig.
Hast du vielleicht mal mit _delay_ms probiert (was das Blinken erklären
könnte) und hier nur die falsche Source hochgeladen?
Das in der While(1) schleife vergessen wir einfach mal
(war nur zum testen, es blinkt so schnell das man das blinken nur daran
merkt das die led nicht ganz so hell ist)
Da anfangs garkein Interrupt ausgelöst worden ist hab ich halt mal das
ganze register auf 1 gesetzt (TIMSK = 0xff;)
mit
TIMSK =(1<<6); //OCIE1A (Output Compare Match Interrupt Enable
Timer/Counter 1)
oder
TIMSK =(1<<7);//TOIE1 (Timer/Counter Overflow Interrupt Enable
Timer/Counter 1)
oder
TIMSK =(1<<6)|(1<<7);kommt leider gar kein interrupt
also resettet der uC jetzt weil ich interrupts auslöse sie aber nicht
auswerte ?
TCCR1B und TIMSK benutzt du falsch, jedenfalls wenn ich nach dem
Datenblatt gehe und vermute, was du machen willst. Bei TIMSK haben die
Bits 6 und 7 nichts mit dem CTC Modus zu tun.
1 | // Initialisierung vom Timer1
| 2 | // als Clear Timer on Compare Match (CTC) Mode
| 3 | // (Mode 4 Tabelle 47 Atmega16 Datenblatt)
| 4 | void init_timer_1()
| 5 | {
| 6 | // Non-PWM, Tabelle 44
| 7 | TCCR1A = 0x00;
| 8 |
| 9 | // Non-PWM Mode 4 (CTC), Tabelle 47
| 10 | // Teiler 256, Tabelle 48
| 11 | TCCR1B = (1<<WGM12) | (1<<CS12);
| 12 |
| 13 | /*
| 14 | To do a 16-bit write, the High byte must be written
| 15 | before the Low byte.
| 16 |
| 17 | For a 16-bit read, the Low byte must be read before
| 18 | the High byte.
| 19 | */
| 20 |
| 21 | TCNT1H = 0;
| 22 | TCNT1L = 0;
| 23 |
| 24 | // Vergleichswert setzen. 8 Mhz / 256 => 1 s
| 25 | OCR1AH = ((8000000L/256) & 0x0000FF00) >> 8;
| 26 | OCR1AL = (8000000L/256) & 0x000000FF;
| 27 |
| 28 | // Interupt bei Compare Enable A
| 29 | // s. 115
| 30 | TIMSK = (1<<OCIE1A);
| 31 | }
|
Ok, Herzlichen dank!
mein Fehler lag an
bzw.
mit
geht es
jetzt frag ich mich was daran der unterschied ist,
laut Tabelle im AVR-GCC Tutorial ist OCIE1A doch bit 6 ???
Bit 7 6 5 4 3 2 1 0
Name TOIE1 OCIE1A - - TICIE - TOIE0 -
Sebastian N. wrote:
> jetzt frag ich mich was daran der unterschied ist,
> laut Tabelle im AVR-GCC Tutorial ist OCIE1A doch bit 6 ???
Im Tutorial steht aber auch: 1 | Die folgenden Ausführungen beziehen sich auf den AT90S2313.
| 2 | Für andere Modelltypen müsst ihr euch die allenfalls
| 3 | notwendigen Anpassungen aus den Datenblättern der entsprechenden
| 4 | Controller herauslesen.
|
Beim Atmega 16 ist OCIE1A Bit 4.
Sebastian N. wrote:
> laut Tabelle im AVR-GCC Tutorial ist OCIE1A doch bit 6 ???
>
> Bit 7 6 5 4 3 2 1 0
> Name TOIE1 OCIE1A - - TICIE - TOIE0 -
Diese Tabelle aus dem AVR-GCC-Tutorial stimmt für den Atmega16
nicht. Leider steht im Tutorial rel. unauffällig:
> Einige Registerbeschreibungen dieses Tutorials beziehen
> sich auf den inzwischen veralteten AT90S2313.
Möglicherweise ist das hier der Fall.
Lerne:
1/ Man sollte immer das passende Datenblatt lesen und vergleichen.
2/ Symbolische Namen wie OCIE1A sind im Code sinnvoller als absolute
Zahlen.
...hätte ich dass nur früher gewusst, ...
danke für den hinweis
sollte vieleicht n bischen grösser geschrieben werden für welchen uC das
Tutorial ist,
der Tip das man die Bits nicht direkt eingibt ist echt gut werd ich mir
merken
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|