Hi! Hier mal mein Gesamtprogramm... Ich habe noch nicht viel verändert, da ich mir über die Timer nicht ganz im klaren bin. Müsste ich die Timer Einstellungen in die while(g_run) Schleife schreiben, damit sie erst beim Start anfangen zu zählen? Und mach ich dann im Timeroverflow Interrupt eine Schleife die Hochzählt? #include <avr/io.h> #include <inttypes.h> #include <avr/delay.h> // definiert _delay_ms() #include <avr/interrupt.h> #include <util/delay.h> // aktuelle Version in util #include <stdio.h> #include <stdio.h> #include <stdlib.h> #ifndef F_CPU #define F_CPU 3686400UL // Quarz mit 3.6864 Mhz ?? noch prüfen!! #endif #define true 1 #define false 0 // Funktion zum Entprellen inline uint8_t debounce(volatile uint8_t *port, uint8_t pin) { if ( ! (*port & (1 << pin)) ) { // Pin wurde auf Masse gezogen, 100ms warten _delay_ms(100); if ( *port & (1 << pin) ) { // Anwender Zeit zum Loslassen des Tasters geben _delay_ms(100); return 1; } } return 0; }; //---------------- Global variables ------------------------ char g_run; // Variable zum Stoppen int g_count; // Zähler // --------------------------------------------------------- // --------------- Interrupt zum Umschalten von g_run ------ ISR(INT0_vect) { // toggle g_run = false; } // --------------- Interrupt bei Timeroverflow -------------- ISR(TIMER1_OVF_vect) { g_count = 0; g_count++; int main(void) { DDRD = 0x00; // Port D ist Eingang PORTD = 0xFF; // interne Pullup-Widerstände aktiviert DDRB = 0xFF; // Port B ist Ausgang PORTB = 0x00; EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus EIMSK |= (1<<INT0); TIMSK |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1 wird Timer Overflow 1 Interruot ausgelöst //Konfiguration von Timer 1 TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM TCCR1B |= (1<<CS12) | (1<<CS10); // CPU-Takt/ 1024 sei(); // Interrupts eingeschaltet g_run = 1; while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt wird while verlassen. while(g_run == 1) { int i; long j; i = rand() % 20; // Generierung der "Pulsbreite" j = rand() % 20; // Generierung der Zeit zwischen zwei Pulsen j = j * 60000; // Umrechnung in Millisekunden _delay_ms(j); // Verzögerungszeit zwischen zwei Pulsen PORTB |= (1<<PB0); // PB0 auf high _delay_ms(i); // PB0 für 1-20 ms auf high PORTB &= ~ (1<<PB0); // PB0 wieder auf low PORTB |= (1<<PB1); // PB1 auf high _delay_ms(10); // PB1 immer für 10 ms auf high PORTB &= ~ (1<<PB1); // PB1 wieder auf low }; cli(); // Interrupts ausgeschaltet while(1); return 0; } Danke für eure Hilfe...
> j = j * 60000; // Umrechnung in Millisekunden > _delay_ms(j); // Verzögerungszeit zwischen zwei Pulsen Hatten wir das nicht schon mal? Die _delay_xx-Funktionen funktionieren nur dann korrekt, wenn sie mit zur compile-Zeit bekannten Konstanten Werten aufgerufen werden und sie sind in Abhängigkeit von der CPU-Frequenz begrenzt! > Und mach ich dann im Timeroverflow Interrupt eine Schleife die Hochzählt? Zählschleifen haben in einer ISR eigentlich nichts verloren. Was soll das Programm überhaupt machen? Warum postest Du sowas nicht in Deinem originalen Thread? Dann müsste man sich jetzt nicht den anderen Thread raussuchen um zu erfahren worum es eigentlich geht!
@ ghost >Hier mal mein Gesamtprogramm... Aha, es geht immer noch um die 1..20 min Verzögerung zur LED-Ansteuerung >Und mach ich dann im Timeroverflow Interrupt eine Schleife die >Hochzählt? Nö. >#define true 1 >#define false 0 Das kannst du dir sparen. >// --------------- Interrupt bei Timeroverflow -------------- >ISR(TIMER1_OVF_vect) >{ > g_count = 0; > g_count++; } fehlt hier Die Initialisierung sieht mal gut aus. Dein Main läuft dann eigentlich nur noch in einer Endlosschleife etwas so while(1); Die Schow findet im Interrupt statt. // --------------- Interrupt bei Timeroverflow -------------- ISR(TIMER1_OVF_vect) { static uin16_t i, j; static uin8_t state=0; switch (state) { case 0: // start, get new random values i = rand() % 20; // Generierung der "Pulsbreite" j = rand() % 20; // Generierung der Zeit zwischen zwei Pulsen j = j * 60000; // Umrechnung in Millisekunden state = 1; break; case 1: // first delay j--; if (j==0) state =2; break; case 2: // first LED action PORTB |= (1<<PB0); // PB0 auf high state =3; break; case 3: // second delay i--; if (i==0) state =4; break; case 4: // second LED action PORTB &= ~ (1<<PB0); // PB0 wieder auf low PORTB |= (1<<PB1); // PB1 auf high state =5; i = 10; break; case 5: // second delay i--; if (i==0) state =6; break; case 6: // third LED action PORTB &= ~ (1<<PB1); // PB1 wieder auf low state =0; break; default: state = 0; // just in case ;-) } } MfG Falk
>> #define true 1 >> #define false 0 > Das kannst du dir sparen. Nö. #define TRUE 1 #define FALSE 0 könnte er sich sparen.
@ Jupp >>> #define true 1 >>> #define false 0 >> Das kannst du dir sparen. >Nö. >#define TRUE 1 >#define FALSE 0 >könnte er sich sparen. Warum muss ich da gerade wieder an eine griechische Stadt mit K und den Auswurf von Exkrementen denken . . .? MFG Falk
@ ghost
>Merci, sowas hab ich gesucht.
Ich hoffe du verstehst auch den Unterschied?
MFG
Falk
>Ich hoffe du verstehst auch den Unterschied?
Ich denke schon.
Der Compiler scheint nur die zwei Zeilen net zu mögen:
static uin16_t i, j;
static uin8_t state=0;
main.c:53: error: expected '=', ',', ';', 'asm' or '__attribute__'
before 'i'
main.c:53: error: 'i' undeclared (first use in this function)
main.c:53: error: (Each undeclared identifier is reported only once
main.c:53: error: for each function it appears in.)
main.c:53: error: 'j' undeclared (first use in this function)
main.c:53: warning: left-hand operand of comma expression has no effect
main.c:53: warning: statement with no effect
main.c:56: error: 'state' undeclared (first use in this function
)
ghost wrote: >>Ich hoffe du verstehst auch den Unterschied? > > Ich denke schon. > > Der Compiler scheint nur die zwei Zeilen net zu mögen: > > static uin16_t i, j; > static uin8_t state=0; > > main.c:53: error: expected '=', ',', ';', 'asm' or '__attribute__' > before 'i' mach noch ein #include <stdint.h> ganz an den Anfang. Der Compiler weiss nicht was ein uint16_t ist. stdint.h enthält die dazu notwendigen Definitionen.
Da fehlen ja auch zwei 't'! uin8_t und uin16_t findet er sicher auch mit der stdint.h nicht...
@ johnny.m >Da fehlen ja auch zwei 't'! uin8_t und uin16_t findet er sicher auch mit >der stdint.h nicht... Ich sach nur Licherkette. An alle Badesalz-Fans ;-) MFG Falk
So schaut jetzt main() aus: int main(void) { DDRD = 0x00; // Port D ist Eingang PORTD = 0xFF; // interne Pullup-Widerstände aktiviert DDRB = 0xFF; // Port B ist Ausgang PORTB = 0x00; // ------- Einstellungen für Ext. Interrupt zum Stoppen des Programms ---- EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus EIMSK |= (1<<INT0); // ----------------------------------------------------------------------- TIMSK1 |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1 wird Timer Overflow 1 Interrupt ausgelöst //Konfiguration von Timer 1 TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM TCCR1B |= (1<<CS12) | (1<<CS10); // 3,6864MHZ/ 1024 = 3600 Hz sei(); // Interrupts eingeschaltet g_run = 1; while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt wird, wird while verlassen cli(); // Interrupts ausgeschaltet while(1); return 0; } Ich habe in switch mal i recht groß gemacht um ein Blinken zu sehen, aber es tut sich nix. Hab ich in main noch nen groben Bock drin??
ghost wrote: > So schaut jetzt main() aus: ... > > sei(); // Interrupts eingeschaltet > > g_run = 1; > > while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt > wird, wird while verlassen > > cli(); // Interrupts ausgeschaltet > > while(1); > return 0; > } Wenn du mittels cli() die Interrupts global ausschaltest, kannst du lange warten, bis ein Overflow Interrupt durchkommt. Die eigentliche Arbeit wird während while(1) ; im Hintergrund von einer ISR (Interrupt Service Routine) erledigt. Die muss aber auch aufgerufen werden können! Das kann sie aber nicht, wenn du mittels cli() die Interrupts sperrst.
@Falk >Warum muss ich da gerade wieder an eine griechische Stadt mit K und den >Auswurf von Exkrementen denken . . .? Keine Ahnung, vielleicht hast du ein Problem mit deiner Verdauung? Wie auch immer, ich wollte es nur klarstellen, denn ich hasse Halbwissen, welches du hier gezeigt hast. LOL
Also irgendwie funzt es net so wie ich will. Das Programm soll nach 1- 20 Minuten einen Pin für ca 10 ms auf high legen und dann wieder auf low. Sofort danach einen anderen Pin auf high für ca 10 ms und dann wieder auf low. Und das ganze halt immer wieder bis man stoppen will. Und halt noch ne Stop-Taste, die aber schon funktioniert ( mit dem externen interrupt). Der Vorschlag von Falk ist ja ok, aber da muss ich doch irgendwie noch meine Frequenz anpassen? Könnte da der Fehler liegen?
Regler wrote: > Wie auch immer, ich wollte es nur klarstellen, denn ich hasse > Halbwissen, welches du hier gezeigt hast. LOL Du meinst, solcherart wie du gerade zur Schau stellst? (Falls Regler derselbe wie Yupp sein sollte.) Guck dir mal <stdbool.h> von C99 an.
Tja, dann muß ich das wohl zurücknehmen. Dennoch ist es schon bescheuert, dass einerseits in der von dir genannten Datei #define true 1 #define false 0 auftaucht, man aber andererseits ohne die Inkludierung dieser Datei #define TRUE 1 #define FALSE 0 definiert wurde, wo auch immer. Frei nach dem Motto: doppelt gemoppelt hält besser.
Regler wrote: > auftaucht, man aber andererseits ohne die Inkludierung dieser Datei > > #define TRUE 1 > #define FALSE 0 > > definiert wurde, wo auch immer. Wo denn? Bei mir nicht. Keine der avr-libc- oder GCC-Headerdateien bringt das mit.
1 | $ cat foo.c |
2 | #include <avr/io.h> |
3 | |
4 | int |
5 | main(void) |
6 | { |
7 | return TRUE; |
8 | } |
9 | $ avr-gcc -mmcu=atmega1281 -c foo.c |
10 | foo.c: In function 'main': |
11 | foo.c:6: error: 'TRUE' undeclared (first use in this function) |
12 | foo.c:6: error: (Each undeclared identifier is reported only once |
13 | foo.c:6: error: for each function it appears in.) |
Hab des Programm jetzt so geschrieben: #include <avr/io.h> #include <inttypes.h> #include <avr/delay.h> // definiert _delay_ms() #include <avr/interrupt.h> #include <util/delay.h> // aktuelle Version in util #include <stdio.h> #include <stdint.h> #include <stdlib.h> #ifndef F_CPU #define F_CPU 3686400UL // Quarz mit 3.6864 Mhz ?? noch prüfen!! #endif #define true 1 #define false 0 // -------- Funktion zum Entprellen -------------------------- inline uint8_t debounce(volatile uint8_t *port, uint8_t pin) { if ( ! (*port & (1 << pin)) ) { // Pin wurde auf Masse gezogen, 100ms warten _delay_ms(100); if ( *port & (1 << pin) ) { // Anwender Zeit zum Loslassen des Tasters geben _delay_ms(100); return 1; } } return 0; }; //---------------- Global variables ------------------------ char g_run; // Variable zum Stoppen // --------------------------------------------------------- // --------------- Interrupt zum Umschalten von g_run ------ ISR(INT0_vect) { // toggle g_run = false; } // --------------- Interrupt bei Timeroverflow -------------- ISR(TIMER1_OVF_vect) { static uint16_t i, j; static uint8_t state=0; switch (state) { case 0: // Start, Erzeugung der neuen Zufallszahlen i = rand() % 20; // Generierung der "Pulsbreite" j = rand() % 20; // Generierung der Zeit zwischen zwei Pulsen j = j * 60000; // Umrechnung in Millisekunden state = 1; break; case 1: // Erste Verzögerung: 1 - 20 Minuten j--; if (j==0) state =2; break; case 2: PORTB |= (1<<PB0); // PB0 auf high state =3; break; case 3: // Verzögerung 1 - 20 ms i--; if (i==0) state =4; break; case 4: PORTB &= ~ (1<<PB0); // PB0 wieder auf low PORTB |= (1<<PB1); // PB1 auf high state =5; i = 10; break; case 5: // 10ms Verzögerung i--; if (i==0) state =6; break; case 6: PORTB &= ~ (1<<PB1); // PB1 wieder auf low state =0; break; default: state = 0; } } int main(void) { DDRD = 0x00; // Port D ist Eingang PORTD = 0xFF; // interne Pullup-Widerstände aktiviert DDRB = 0xFF; // Port B ist Ausgang PORTB = 0xFC; // ------- Einstellungen für Ext. Interrupt zum Stoppen des Programms ---- EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus EIMSK |= (1<<INT0); // ----------------------------------------------------------------------- sei(); // Interrupts eingeschaltet g_run = 1; while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt wird, wird while verlassen while(g_run == 1) { TIMSK1 |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1 wird Timer Overflow 1 Interrupt ausgelöst //Konfiguration von Timer 1 TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM TCCR1B |= (1<<CS12) | (1<<CS10); // 3,6864MHZ/ 1024 = 3600 Hz }; while(1); return 0; } Jetzt sollte es doch eigentlich beim drücken des Tasters an Pin PD0 starten und solange durchlaufen bis ich den externen Interrupt durch drücken des Tasters an PD2 auslöse. Das ganze ist ein kleines Teil für meine BA und sollte mich eigentlich nicht zu lange damit aufhalten ( auch wenn ich das Programmieren schon interessant finde...) Habe ich evtl. den Overflow Vektor falsch gewählt? Oder noch ein Register falsch belegt?
ghost wrote: > Habe ich evtl. den Overflow Vektor falsch gewählt? Oder noch ein > Register falsch belegt? Schmeiss mal das ganze Gerödel mit deinen Tastern raus. Da blickt doch keiner mehr durch. Halte dich an das einfache Schema: int main() { alles initialisieren // // Endlosschleife und den Timer Interrupt // machen lassen // while(1) ; } Dazu packst du dann noch die ISR und alles was an globalen Variablen dazugehört. Dann setzt du den Vorteiler für den Timer mal auf 1 (*) und gehst mit dem Ganzen in den Simulator zum durchdebuggen. (*) 1 deswegen, damit du dir im Simulator keinen Wolf auf der F10 Taste tippst um den Timerwert um 1 zu erhöhen.
@ ghost Deine Programmierkenntnisse sind wohl schon ein wenig arg rostig, was? int main(void) { DDRD = 0x00; // Port D ist Eingang PORTD = 0xFF; // interne Pullup-Widerstände aktiviert DDRB = 0xFF; // Port B ist Ausgang PORTB = 0xFC; // ------- Einstellungen für Ext. Interrupt zum Stoppen des Programms ---- EICRA |= (1<<ISC01); // Fallende Flanke löst Interrupt aus EIMSK |= (1<<INT0); // TIMSK1 |= (1<<TOIE1); // Bei Überlauf des Datenregisters von Timer 1 wird Timer Overflow 1 Interrupt ausgelöst //Konfiguration von Timer 1 TCCR1A = 0x00; // Timer 1 ohne Outputpins und ohne PWM TCCR1B |= (1<<CS12) | (1<<CS10); // 3,6864MHZ/ 1024 = 3600 Hz // sämtliche Konfiguration VOR das Aktivieren der Interrupts ----------------------------------------------------------------------- sei(); // Interrupts eingeschaltet g_run = 1; while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt wird, wird while verlassen while(g_run == 1); // Endlosschleife, bis durch INT0 G_run false wird, das Semikolon ist wichtig! cli(); // alle Interrupts, aus, das wars while(1); // bis zum Sant Nimmerleinstag } >Habe ich evtl. den Overflow Vektor falsch gewählt? Oder noch ein >Register falsch belegt? Nur kleinere logische Schwächen ;-). Die Interrupts hast du nicht wirklich kapiert, oder? Ausserdem musst du noch die Multiplikatoren anpassen, bei ~3600 Hz Timertakt ist deine Überlauf (=Interrupt)freqeunz 3600/256 ~14 Hz, sprich 71ms. Das ist dein Zeitraster. MfG Falk
Hab mittlerweile das Programm nochmal neu geschrieben. Jetzt funktioniert eigentlich alles so wie es soll. Nur mit dem externen Interrupt klappt es net so gut. Wenn in der ISR meine globale Variable g_run = 0 gesetzt wird, sollte mein programm die while(g_run == 1) schleife verlassen und in die while(1) schleife laufen. Dann dürfte aber eigentlich nichts mehr passieren, oder? weil bei mir die testLEDs weiterhin blinken...
#include <avr/io.h> #include <inttypes.h> #include <avr/delay.h> // definiert _delay_ms() #include <avr/interrupt.h> #include <util/delay.h> // aktuelle Version in util #include <stdio.h> #include <stdio.h> #include <stdlib.h> #ifndef F_CPU #define F_CPU 3686400UL // Quarz mit 3.6864 Mhz ?? noch prüfen!! #endif // Funktion zum Entprellen inline uint8_t debounce(volatile uint8_t *port, uint8_t pin) { if ( ! (*port & (1 << pin)) ) { // Pin wurde auf Masse gezogen, 100ms warten _delay_ms(100); if ( *port & (1 << pin) ) { // Anwender Zeit zum Loslassen des Tasters geben _delay_ms(100); return 1; } } return 0; }; //---------------- Global variables ------------------------ // Variable zum Stoppen char g_run; // --------------------------------------------------------- // --------------- Interrupt zum Umschalten von g_run ------ ISR(INT0_vect) // Externer Interrupt beim Drücken von Taster an PD2 { // toggle g_run = 0; } int main(void) { DDRD = 0x00; // Port D ist Eingang PORTD = 0xFF; // interne Pullup-Widerstände aktiviert DDRB |= (1<<DDB0) | (1<<DDB1); // Pin 0 und 1 von Port B als Ausgang definiert PORTB = 0x00; EICRA |= (1<<ISC01); // fallende Flanke löst Interrupt aus EIMSK |= (1<<INT0); sei(); // Interrupts eingeschaltet g_run = 1; while( ! debounce(&PIND, PD0) ); //Wenn Taster an PIN PD0 gedrueckt wird while verlassen. while(g_run == 1) { _delay_ms(60); PORTB |= (1<<PB0); // PB0 auf high _delay_ms(10); // PB0 für 10 ms auf high PORTB &= ~ (1<<PB0); // PB0 wieder auf low PORTB |= (1<<PB1); // PB1 auf high _delay_ms(10); // PB1 immer für 10 ms auf high PORTB &= ~ (1<<PB1); // PB1 wieder auf low }; while(1); return 0; }
@ ghost >Wenn in der ISR meine globale Variable g_run = 0 gesetzt wird, sollte >mein programm die while(g_run == 1) schleife verlassen und in die >while(1) schleife laufen. Dann dürfte aber eigentlich nichts mehr >passieren, oder? Ja. Aber erstzte mal char g_run; durch volatile char g_run; > weil bei mir die testLEDs weiterhin blinken... Dann wird dein Interrupt nicht ausgeführt. Hast du deinen 2. Taster, welcher den Interrupt auslösen soll auch and PD2 angeschlossen?. MFG Falk
hab das mit volatile grad selber bei AVR freaks gefunden... jetzt klappt es. volatile heißt also, dass der wert global also auch in main geändert wird oder? dacht immer das macht eine globale variable sowieso??
ghost wrote: > volatile heißt also, dass der wert global also auch in > main geändert wird oder? dacht immer das macht eine globale variable > sowieso? Das macht eine globale Variable immer, ja. `volatile' besagt, dass der Compiler den Code so schreiben muss, dass an einem sogenannten sequence point der Inhalt der Variablen auch tatsächlich dem Ergebnis entsprechend der abstrakten Maschine entsprechen soll. In freier Übersetzung bedeutet das etwa so viel wie, dass er jegliche Zugriffsoptimierung auf derartige Variablen sein lassen soll.
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.