bitte um Korrektur, der Motor sollte nach 100 Schritte anhalten, aber das tut er nicht: [c] #include <avr/io.h> #include <avr/interrupt.h> unsigned int zx=0,zy=0; void motorxR(unsigned int schr); void motorxL(unsigned int schr); int main() { DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)| (1<<PB5); // PIN0-5 als Ausgang für die Motoren definieren // PortB als Ausgang definieren DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren TCCR1A = (1<<COM1A0) | (0<<WGM11); TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10); OCR1A=18432; //****************** Interrupt initialisieren ************************************* PCMSK1 = (1 << PCINT|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 setzen PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30 //*********** TIMER1 OVF ***************** TIMSK1|=(1<<TOIE1); sei(); while (1) {} } ISR(TIMER1_OVF_vect) { zx++; if(zx>100) { PORTB&=~(1<<PB0); TCCR1B&=~(1<<CS10); } zx=0; } ISR(PCINT1_vect) //Interrupt Service Routine { if(!(PINC&(1<<PC0))) {motorxR(zx); } if(!(PINC&(1<<PC1))) {motorxL(zx); } } void motorxR(unsigned int schr) { PORTB|=(1<<PB4); PORTB|=(1<<PB0); } void motorxL(unsigned int schr) { PORTB&=~(1<<PB4); PORTB|=(1<<PB0); } [c]
Der Fehler liegt hier drin amal schrieb: > unsigned int zx=0,zy=0; Du musst die Variablen zx und als volatile deklarieren. Sonst weiß der kompiler nicht das zx auch von außerhalb der ISR gesetzt werden kann und das er sie nicht bei jeder ausfürhugn der ISR neu initialisieren soll.
Ohne das jetzt gelesen zu haben ... Globale Variablen müssen mit volatile deklariert werden wenn sie in der ISR routine verändert werden sollen
Mir ist in der ISR beim genaueren betrachten folgendes aufgefallen: amal schrieb: > ISR(TIMER1_OVF_vect) > { > zx++; > if(zx>100) > { > PORTB&=~(1<<PB0); > TCCR1B&=~(1<<CS10); > } > zx=0; > } Du zählst zx am Anfang hoch udn vergleichst dann, und am Ende setzt du es wieder auf 0 zurück. natürlich wird es so niemals 100 erreichen da es immer wieder bei 0 anfängt. Du musst zx=0 in die if-Abfrage packen.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | volatile uint16_t zx=0, |
4 | void motorxR(unsigned int schr); |
5 | void motorxL(unsigned int schr); |
6 | |
7 | int main() |
8 | {
|
9 | DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)| (1<<PB5); // PIN0-5 |
10 | als Ausgang für die Motoren definieren // PortB als Ausgang definieren |
11 | DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren |
12 | |
13 | |
14 | |
15 | TCCR1A = (1<<COM1A0) | (0<<WGM11); |
16 | TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10); |
17 | OCR1A=18432; |
18 | |
19 | |
20 | //****************** Interrupt initialisieren
|
21 | *************************************
|
22 | PCMSK1 = (1 << PCINT|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << |
23 | PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 |
24 | setzen
|
25 | PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 |
26 | setzen für PCINT30 |
27 | |
28 | //*********** TIMER1 OVF *****************
|
29 | |
30 | TIMSK1|=(1<<TOIE1); |
31 | sei(); |
32 | |
33 | while (1) {} |
34 | }
|
35 | |
36 | ISR(TIMER1_OVF_vect) |
37 | {
|
38 | zx++; |
39 | if(zx>100) |
40 | {
|
41 | PORTB&=~(1<<PB0); |
42 | TCCR1B&=~(1<<CS10); |
43 | }
|
44 | zx=0; |
45 | }
|
46 | |
47 | ISR(PCINT1_vect) //Interrupt Service Routine |
48 | {
|
49 | if(!(PINC&(1<<PC0))) |
50 | {motorxR(zx); |
51 | }
|
52 | if(!(PINC&(1<<PC1))) |
53 | {motorxL(zx); |
54 | }
|
55 | }
|
56 | |
57 | void motorxR(unsigned int schr) |
58 | {
|
59 | PORTB|=(1<<PB4); |
60 | PORTB|=(1<<PB0); |
61 | }
|
62 | void motorxL(unsigned int schr) |
63 | {
|
64 | PORTB&=~(1<<PB4); |
65 | PORTB|=(1<<PB0); |
66 | }
|
ja wie gesagt der Motor dreht sich permanent
1 | C- |
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
4 | volatile uint16_t zx=0, |
5 | void motorxR(unsigned int schr); |
6 | void motorxL(unsigned int schr); |
7 | |
8 | int main() |
9 | {
|
10 | DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)| (1<<PB5); // PIN0-5 |
11 | als Ausgang für die Motoren definieren // PortB als Ausgang definieren |
12 | DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren |
13 | |
14 | |
15 | |
16 | TCCR1A = (1<<COM1A0) | (0<<WGM11); |
17 | TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10); |
18 | OCR1A=18432; |
19 | |
20 | |
21 | //****************** Interrupt initialisieren
|
22 | *************************************
|
23 | PCMSK1 = (1 << PCINT|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << |
24 | PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 |
25 | setzen
|
26 | PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 |
27 | setzen für PCINT30 |
28 | |
29 | //*********** TIMER1 OVF *****************
|
30 | |
31 | TIMSK1|=(1<<TOIE1); |
32 | sei(); |
33 | |
34 | while (1) {} |
35 | }
|
36 | |
37 | ISR(TIMER1_OVF_vect) |
38 | {
|
39 | zx++; |
40 | if(zx>100) |
41 | {
|
42 | PORTB&=~(1<<PB0); |
43 | TCCR1B&=~(1<<CS10); |
44 | }
|
45 | zx=0; |
46 | }
|
47 | |
48 | ISR(PCINT1_vect) //Interrupt Service Routine |
49 | {
|
50 | if(!(PINC&(1<<PC0))) |
51 | {motorxR(zx); |
52 | }
|
53 | if(!(PINC&(1<<PC1))) |
54 | {motorxL(zx); |
55 | }
|
56 | }
|
57 | |
58 | void motorxR(unsigned int schr) |
59 | {
|
60 | PORTB|=(1<<PB4); |
61 | PORTB|=(1<<PB0); |
62 | }
|
63 | void motorxL(unsigned int schr) |
64 | {
|
65 | PORTB&=~(1<<PB4); |
66 | PORTB|=(1<<PB0); |
67 | }
|
ja wie gesagt der Motor dreht sich permanent
das liegt daran das du zx direkt wieder auf 0 setzt das muss in die if anweisung ulp schrieb: > das liegt daran das du zx direkt wieder auf 0 setzt > > das muss in die if anweisung
Kannst du mit deiner Entwicklungsumgebnung (welche?) den Programmablauf nicht simulieren und dabei die Variablenwerte verfolgen? Dann würdest du sofort sehen, wenn etwas anders läuft als vorgesehen. AVR-Strudio 4.18 z.B. konnte das.
Tip schrieb: > Kannst du mit deiner Entwicklungsumgebnung (welche?) den Programmablauf > nicht simulieren und dabei die Variablenwerte verfolgen? Dann würdest du > sofort sehen, wenn etwas anders läuft als vorgesehen. > AVR-Strudio 4.18 z.B. konnte das. ich könnte das nur wenn ich mit Assembler programmiere, in C weiß ich nicht wie das geht, weil du gar nicht weißt wo dein Prog steht. auf jedenfall der Fehler liegt daran, dass ich nie einen OVF erreichen kann, weil in CTC Mode 4 erreicht man OVF nur bei Max=FFFF, deswegen wird ich jetzt anderen Weg nehmen, und zwar über ISR(TIMER1_COMPA_Vect).übrigens ich habe AVR4.14
Albert ... schrieb: > Du musst die Variablen zx und als volatile deklarieren. Sonst weiß der > kompiler nicht das zx auch von außerhalb der ISR gesetzt werden kann und > das er sie nicht bei jeder ausfürhugn der ISR neu initialisieren soll. Falsch. Nikos schrieb: > Globale Variablen müssen mit volatile deklariert werden wenn sie in der > ISR routine verändert werden sollen Auch falsch. Aber schon ein wenig besser... ;-) Variablen müssen als volatil deklariert werden, wenn sie unverhofft von ausserhalb einer Funktion geändert werden könnten. Wenn z.B. in einer "normalen" Funktion ein Wert verwendet wird, sich dieser Wert aber von aussen ändern kann (z.B. ein Timer oder ein Pin oder eine globale Variable), dann muß dem Compiler gesagt werden, er soll diesen Wert doch bitte jedesmal neu einlesen. Und dieses "der Wert kann sich unvermittlet ändern" bedeutet volatil (=flüchtig). Eine globale Variable, die in einer nicht unterbrechbaren Interuptroutine nur gelesen wird, braucht dieses Schlüsselwort also sicher nicht. Eine globale Variable, die nur in 1 Interuptroutine verwendet, braucht dieses Schlüsselwort auch nicht. Ein Problem wurde schon genannt:
1 | ISR(TIMER1_OVF_vect) |
2 | {
|
3 | zx++; // hochzählen |
4 | if(zx>100) |
5 | {
|
6 | PORTB&=~(1<<PB0); |
7 | TCCR1B&=~(1<<CS10); |
8 | }
|
9 | zx=0; // zu Null setzen |
10 | }
|
zx wird NIEMALS größer 100. zx hatt immer nur die Werte 0 und 1. Die meiste Zeit ist zx = 0. @ amal Formatier deinen Quelltext mit Einrückungen, dann siehst du das gleich..
Hallo, Du must beim Hochzählen beachten, dass du wirklich zwei Möglichkeiten programmierst. ISR(TIMER1_OVF_vect) { zx++; // hochzählen if(zx>100) { PORTB&=~(1<<PB0); TCCR1B&=~(1<<CS10); } zx=0; // zu Null setzen } Bei dem hier gibt es nur eine Möglichkeit da zx den Wert 100 nie erreichen kann. ISR(TIMER1_OVF_vect) { if(zx>100) { PORTB&=~(1<<PB0); TCCR1B&=~(1<<CS10); zx=0; // zu Null setzen }esle{ zx++; // hochzählen } } Bei dieser Variante wird zx nur dann auf 0 gesetzt, wenn die Abfrage zutrifft. Gruß Jannis
ich habe jetzt den COMP Interrupt benutzt, ich möchte jetzt zum beispiel 100schritte machen dann auf einem PIN eine PWM signal ausgeben, dann nochmal 100 Schritte, das ganze 10mal,das heißt der Motor soll sich 1000 Schritte machen und 10 mal pwm signal ausgeben. und das habe ich so realisiert, ich bitte um Korrektur.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | volatile uint16_t zx=0,zy=0; |
9 | void motorxR(void); |
10 | |
11 | void sleep_ms(unsigned int ms); |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | int main() |
19 | {
|
20 | |
21 | |
22 | DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5); // PIN0-5 als Ausgang für die Motoren definieren // PortB als Ausgang definieren |
23 | DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren |
24 | |
25 | |
26 | // Timer 1 einstellen
|
27 | //
|
28 | // Modus 15:
|
29 | // Fast PWM, Top von OCR1A
|
30 | //
|
31 | // WGM13 WGM12 WGM11 WGM10
|
32 | // 0 1 0 0
|
33 | //
|
34 | // Timer Vorteiler: 1
|
35 | // CS12 CS11 CS10
|
36 | // 0 0 1
|
37 | //
|
38 | // Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
|
39 | // COM1A1 COM1A0
|
40 | // 0 1
|
41 | // OCR1A=(fclk/2*N)-1 N: Vorteiler
|
42 | TCCR1A = (1<<COM1A0) | (0<<WGM11)| (0<<WGM10); |
43 | TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10); |
44 | OCR1A=18432; |
45 | |
46 | |
47 | //****************** Interrupt initialisieren *************************************
|
48 | PCMSK1 = (1 << PCINT8)|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 setzen |
49 | PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30 |
50 | |
51 | //*********** TIMER1 COMP *****************
|
52 | |
53 | TIMSK1|=(1<<OCIE1A); |
54 | TCNT1=0; |
55 | |
56 | |
57 | |
58 | sei(); |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | while (1) {} |
66 | }
|
67 | |
68 | |
69 | |
70 | ISR(TIMER1_COMPA_vect) |
71 | {
|
72 | if(zx>100) |
73 | {
|
74 | PORTB&=~(1<<PB0); |
75 | }
|
76 | zx++; |
77 | |
78 | }
|
79 | |
80 | ISR(PCINT1_vect) //Interrupt Service Routine |
81 | {
|
82 | |
83 | sei(); |
84 | //******************************* MESSUNG STARTEN ********************************************
|
85 | //*****************************************************************************************************
|
86 | |
87 | if(!(PINC&(1<<PC0))) |
88 | {
|
89 | |
90 | for(unsigned int j=0;j<10;j++) |
91 | {
|
92 | motorxR(); |
93 | PORTB|=(1<<PB5); // |
94 | sleep_ms(5); // TRIGGERN |
95 | PORTB&=~(1<<PB5); // |
96 | sleep_ms(2);*/ |
97 | zx=0; // WARTEN 2ms |
98 | }
|
99 | }
|
100 | |
101 | void motorxR(void) |
102 | {
|
103 | PORTB|=(1<<PB3); |
104 | PORTB|=(1<<PB0); |
105 | //PORTB&=~(1<<PB2);
|
106 | |
107 | }
|
108 | |
109 | |
110 | |
111 | void sleep_ms(unsigned int ms) |
112 | {
|
113 | for (unsigned int s=0; s<ms; s++) |
114 | {
|
115 | for (long int i=0; i<461; i++) |
116 | {
|
117 | asm volatile("nop"); |
118 | }
|
119 | }
|
120 | }
|
Hallo ISR(PCINT1_vect) //Interrupt Service Routine { sei (); Willst du an dieser Stelle den Interrupt erlauben oder nicht? Wenn du in abschalten willst dann musst du diesen Befehl benutzen: cli (). Gruß Jannis
Jannis C. schrieb: > Willst du an dieser Stelle den Interrupt erlauben oder nicht? erlauben, ich will den nicht löschen
amal schrieb: > ich könnte das nur wenn ich mit Assembler programmiere, in C weiß ich > nicht wie das geht, weil du gar nicht weißt wo dein Prog steht. Wieso weißt du nicht wie das geht, wenn ich nicht weiß, wo mein "Prog" steht? In C unter AVRStudio gibt es im Menü "Debug" einige nützliche Funktionen. Vielleicht solltest du dich damit mal beschäftigen. Das würde dir die Fehlersuche deutlich erleichtern.
Hallo, Um den Interrupt zu löschen musst du aber cli (); schreiben. sleep_ms(2); Dafür gibt es delay- Funktion. Du musst also also die Funktion sleep löschen und ein paar Zeilen ergänzen. #ifndef F_CPU #define F_CPU ( Takt in Herz) UL #endif #include <util/delay.h> Die vier Zeilen kopierst du dir unter die anderen Includes. Anstelle von Sleep schreibst du jetzt _delay_ms(Zeit in Ms); Gruß Jannis
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.