Hallo Forum, ich möchte über den ATMEGA 168 zwei DC-Motoren im PWM-Modus steuern. Leider funktioniert es momentan nur so, dass nur ein Motor läuft. hier mal der bisherige c-Code: #include<avr/io.h> //#define F_CPU 20000000UL //Taktfrequenz 20MHz #include<util/delay.h> // Verzögerung int main(void) { DDRB |= (1<<PB2); //initialisieren Output 16 [Motor rechtslauf] DDRB |= (1<<PB1); //initialisieren Output 15 [Motor linkslauf] DDRB |= (1<<PB0); //initialisieren Output 14 [Motor rechtslauf] DDRB |= (1<<PB3); //initialisieren Output 17 [Motor linkslauf] DDRD |= (1<<PD5); //initialisieren Output 11 [LED] PORTD |= (1<<PD5); //LED einschalten unsigned char duty_cyc_a,duty_cyc_b; duty_cyc_a=0; // Initial Duty Cycle for Channel A duty_cyc_b=0; // Initial Duty Cycle for Channel B // erster Motor start: (PB2 im PORTB setzten [1A]) PORTB &= ~(1<< PB1); //PB1 im PORTB löschen [2A] TCCR2B = (1<<CS21) | (1<<CS20); //Clock select TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode OCR2A = 0; OCR2B = 0; while(duty_cyc_a < 255) { OCR2A=duty_cyc_a++; OCR2B=duty_cyc_b--; _delay_ms(100); } while(duty_cyc_b < 255) { OCR2A=duty_cyc_a--; OCR2B=duty_cyc_b++; _delay_ms(200); } // erster Motor stop PORTB &= ~(1<< PB2); // PB2 im PORTB löschen [1A] //zweiter Motor start (PB4 im PORTB setzten [4A]) PORTB &= ~(1<< PB3); // PB3 im PORTB löschen [3A] TCCR2B = (1<<CS21) | (1<<CS20); //Clock select TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode OCR2A = 0; OCR2B = 0; while(duty_cyc_a < 255) { OCR2A=duty_cyc_a++; OCR2B=duty_cyc_b--; _delay_ms(100); } while(duty_cyc_b < 255) { OCR2A=duty_cyc_a--; OCR2B=duty_cyc_b++; _delay_ms(200); } // zweiter Motor stop PORTB &= ~(1<< PB4); // PB4 im PORTB löschen [4A] return 0; } ___________________________________ ich kann mir schon denken, dass die Register-Einstellung nur einmalig nach der Input/Output Deklaration gesetzt werden müssen, jedoch schlug dieser Versuch bei mir ebenfalls fehl. Könnte mir bitte einer helfen?
Julia W schrieb: > Leider funktioniert es momentan nur so, dass nur ein Motor läuft. Und wir dürfen raten welcher. > hier mal der bisherige c-Code: Ohne Kommentare und Erläuterung (Funktionsbeschreibung) welcher Gedanke dahinter steckt. Im allgemeinen wird ein Timer in einem PWM Modus intitialisiert und seine OCA-Pins bzw OCB-Pins mit dem COM Bits durchgeschaltet. Über die OCR Register wird der Duty Cycle eingestellt - fertig. Die OC Pins kann man auf die EN Pins des L293 schalten.
mecker schrieb: >> Leider funktioniert es momentan nur so, dass nur ein Motor läuft. > > Und wir dürfen raten welcher. es wird nur PB2 [A1] angesprochen. wäre es ein Lösungsweg, wenn ich nach dem "erster Motor stop" alle Timer deaktiviere/ resete und die Ports bis auf den anzusprechenden lösche? #include<avr/io.h> //#define F_CPU 20000000UL //Taktfrequenz 20MHz #include<util/delay.h> // Verzögerung int main(void) { DDRB |= (1<<PB2); //initialisieren Output 16 [Motor rechtslauf] DDRB |= (1<<PB1); //initialisieren Output 15 [Motor linkslauf] DDRB |= (1<<PB0); //initialisieren Output 14 [Motor rechtslauf] DDRB |= (1<<PB3); //initialisieren Output 17 [Motor linkslauf] DDRD |= (1<<PD5); //initialisieren Output 11 [LED] PORTD |= (1<<PD5); //LED einschalten PORTB &= ~(1<< PB1); //PB1 im PORTB löschen [2A], um Invertierung am [1A] zu vermeiden PORTB &= ~(1<< PB3); //PB3 im PORTB löschen [3A], um Invertierung am [4A] zu vermeiden unsigned char duty_cyc_a,duty_cyc_b; duty_cyc_a=0; // Initial Duty Cycle for Channel A duty_cyc_b=0; // Initial Duty Cycle for Channel B // erster Motor start: (PB2 im PORTB setzten [1A]) PORTB &= (1<< PB2); // PB2 im PORTB setzen [1A] TCCR2B = (1<<CS21) | (1<<CS20); //Clock select TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode OCR2A = 0; OCR2B = 0; while(duty_cyc_a < 255) //hochfahren { OCR2A=duty_cyc_a++; OCR2B=duty_cyc_b--; _delay_ms(100); } while(duty_cyc_b < 255) //runterfahren { OCR2A=duty_cyc_a--; OCR2B=duty_cyc_b++; _delay_ms(200); } // erster Motor stop, Register reseten PORTB &= ~(1<< PB2); // PB2 im PORTB löschen [1A] TCCR2A = 0; // Timer auf 0 reseten TCCR1A = 0; // Timer auf 0 reseten TCNT2 = 0; // clear TIFR2 = 0xFF; // clear interrupt-flags //zweiter Motor start (PB4 im PORTB setzten [4A]) PORTB &= (1<< PB0); // PB0 im PORTB setzen [4A] TCCR2B = (1<<CS21) | (1<<CS20); //Clock select TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode OCR2A = 0; OCR2B = 0; while(duty_cyc_a < 255) { OCR2A=duty_cyc_a++; OCR2B=duty_cyc_b--; _delay_ms(100); } while(duty_cyc_b < 255) { OCR2A=duty_cyc_a--; OCR2B=duty_cyc_b++; _delay_ms(200); } // zweiter Motor stop PORTB &= ~(1<< PB0); // PB0 im PORTB löschen [4A] return 0; }
Schaust Du auch mal in Datenblätter? Julia W schrieb: > es wird nur PB2 [A1] angesprochen PB2 mit Sicherheit nicht - PB3 ja, da hängt OC2A dran. mecker schrieb: > Die OC Pins kann > man auf die EN Pins des L293 schalten. mecker hat insofern Recht, als Du nur 2 OC..-Pins mit Deiner PWM beeinflusst. Die wirken sich auf PB3 (OC2A) und PD3 (OC2B) aus. Ob es reicht, diese beiden PWM-Pins auf die enable-Leitungen des L293D zu geben weiß ich nicht, vermute es aber. Damit gibst Du dann die "Drehzahl" / Geschwindigkeit vor. Ferner musst Du dann zusätzlich noch die jeweilige Richtung über insgesamt 4 Ausgänge (high / low) steuern. Alternativ kannst Du natürlich 4 (von den vorhanden 6) PWM-Ausgängen für die Richtungssteuerung incl."Drehzahl" nutzen. Das musst Du entscheiden - musst aber in jedem Fall mal die Datenblätter studieren :-). Deine Schaltung scheint mir aber auch noch nicht (wenn ich das Datenblatt des L293D richtig lese) optimal zu sein. Fehlen da noch ein paar Dioden? Gruß Dieter Julia W schrieb: > es wird nur PB2 [A1] angesprochen
#include<avr/io.h> //#define F_CPU 20000000UL //Taktfrequenz 20MHz #include<util/delay.h> // Verzögerung int main(void) { DDRB |= (1<<PB2); //initialisieren Output 16 [Motor rechtslauf] DDRB |= (1<<PB1); //initialisieren Output 15 [Motor linkslauf] DDRB |= (1<<PB0); //initialisieren Output 14 [Motor rechtslauf] DDRB |= (1<<PB3); //initialisieren Output 17 [Motor linkslauf] DDRD |= (1<<PD5); //initialisieren Output 11 [LED] PORTD |= (1<<PD5); //LED einschalten PORTB &= ~(1<< PB2); //PB2 im PORTB löschen [1A], um Invertierung am [2A] zu vermeiden PORTB &= ~(1<< PB3); //PB3 im PORTB löschen [3A], um Invertierung am [4A] zu vermeiden unsigned char duty_cyc_a,duty_cyc_b; duty_cyc_a=0; // Initial Duty Cycle for Channel A duty_cyc_b=0; // Initial Duty Cycle for Channel B // erster Motor start: (PB1 im PORTB setzten [2A]) TCCR2B = (1<<CS21) | (1<<CS20); //Clock select TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode OCR2A = 0; OCR2B = 0; while(duty_cyc_a < 255) //hochfahren { OCR2A=duty_cyc_a++; OCR2B=duty_cyc_b--; _delay_ms(100); } while(duty_cyc_b < 255) //runterfahren { OCR2A=duty_cyc_a--; OCR2B=duty_cyc_b++; _delay_ms(200); } // erster Motor stop, Register reseten PORTB &= ~(1<< PB1); // PB1 im PORTB löschen [2A] TCCR2A = 0; // Timer auf 0 reseten TCCR1A = 0; // Timer auf 0 reseten TCNT2 = 0; // clear TIFR2 = 0xFF; // clear interrupt-flags //zweiter Motor start (PB4 im PORTB setzten [4A]) TCCR2B = (1<<CS21) | (1<<CS20); //Clock select TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode OCR4A = 0; OCR4B = 0; while(duty_cyc_a < 255) { OCR2A=duty_cyc_a++; OCR2B=duty_cyc_b--; _delay_ms(100); } while(duty_cyc_b < 255) { OCR2A=duty_cyc_a--; OCR2B=duty_cyc_b++; _delay_ms(200); } // zweiter Motor stop PORTB &= ~(1<< PB0); // PB0 im PORTB löschen [4A] return 0; }
danke Euch. Ich denke, ich habe es nun mit den OCR2 bzw OCR4 verstanden.
1 | #include<avr/io.h> |
2 | //#define F_CPU 20000000UL //Taktfrequenz 20MHz
|
3 | #include<util/delay.h> // Verzögerung |
4 | |
5 | int main(void) |
6 | {
|
7 | DDRB |= (1<<PB2); //initialisieren Output 16 [Motor rechtslauf] |
8 | DDRB |= (1<<PB1); //initialisieren Output 15 [Motor linkslauf] |
9 | DDRB |= (1<<PB0); //initialisieren Output 14 [Motor rechtslauf] |
10 | DDRB |= (1<<PB3); //initialisieren Output 17 [Motor linkslauf] |
11 | DDRD |= (1<<PD5); //initialisieren Output 11 [LED] |
12 | |
13 | PORTD |= (1<<PD5); //LED einschalten |
14 | PORTB &= ~(1<< PB2); //PB2 im PORTB löschen [1A], um Invertierung am |
15 | [2A] zu vermeiden |
16 | PORTB &= ~(1<< PB3); //PB3 im PORTB löschen [3A], um Invertierung am |
17 | [4A] zu vermeiden |
18 | unsigned char duty_cyc_a,duty_cyc_b; |
19 | duty_cyc_a=0; // Initial Duty Cycle for Channel A |
20 | duty_cyc_b=0; // Initial Duty Cycle for Channel B |
21 | |
22 | |
23 | // erster Motor start: (PB1 im PORTB setzten [2A])
|
24 | |
25 | TCCR2B = (1<<CS21) | (1<<CS20); //Clock select |
26 | TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation |
27 | mode
|
28 | OCR2A = 0; |
29 | OCR2B = 0; |
30 | while(duty_cyc_a < 255) //hochfahren |
31 | {
|
32 | OCR2A=duty_cyc_a++; |
33 | OCR2B=duty_cyc_b--; |
34 | _delay_ms(100); |
35 | }
|
36 | |
37 | while(duty_cyc_b < 255) //runterfahren |
38 | {
|
39 | OCR2A=duty_cyc_a--; |
40 | OCR2B=duty_cyc_b++; |
41 | _delay_ms(200); |
42 | }
|
43 | // erster Motor stop, Register reseten
|
44 | PORTB &= ~(1<< PB1); // PB1 im PORTB löschen [2A] |
45 | TCCR2A = 0; // Timer auf 0 reseten |
46 | TCCR1A = 0; // Timer auf 0 reseten |
47 | TCNT2 = 0; // clear |
48 | TIFR2 = 0xFF; // clear interrupt-flags |
49 | //zweiter Motor start (PB4 im PORTB setzten [4A])
|
50 | |
51 | TCCR2B = (1<<CS21) | (1<<CS20); //Clock select |
52 | TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation |
53 | mode
|
54 | OCR4A = 0; |
55 | OCR4B = 0; |
56 | while(duty_cyc_a < 255) |
57 | {
|
58 | OCR2A=duty_cyc_a++; |
59 | OCR2B=duty_cyc_b--; |
60 | _delay_ms(100); |
61 | }
|
62 | |
63 | while(duty_cyc_b < 255) |
64 | {
|
65 | OCR4A=duty_cyc_a--; |
66 | OCR4B=duty_cyc_b++; |
67 | _delay_ms(200); |
68 | }
|
69 | // zweiter Motor stop
|
70 | PORTB &= ~(1<< PB0); // PB0 im PORTB löschen [4A] |
71 | |
72 | return 0; |
73 | }
|
Julia W schrieb: > Ich denke, ich habe es nun mit den OCR2 bzw OCR4 verstanden. Du hast überhaupt nichts verstanden. Ein Atmega168 hat keinen Timer4 und somit auch keine OCR4-Register. Wenn du deinen Motor an OC1A und OC1B angeschlossen hast, dann nimm auch Timer1. Deine ganze Initialisierung ist wirres Zeug. mfg.
Du kannst diese (Bild) Pins mit PWM beeinflussen - keine anderen. Die Zahl steht jeweils für den beeinflussenden Timer ... Sch..ade, jetzt ist es ein GIF geworden ... Und ... ja, es führt kein Weg an den Datenblättern vorbei - weiß ich aus eigener Erfahrung. Und dann lieber x-mal Lesen, da man beim ersten, zweiten, ...ten Mal immer noch etwas überliest. Ich habe die Hinweise auch nicht gerade als lustig empfunden, es hilft aber ungemein. Googlen ist die 2. Wahl, da auch nicht immer korrekte Aussagen getroffen werden :-(
Abend, @ Dieter: Also ich kann PB1, PB2, PB3 für PWM benutzen, richtig? PB0 aber nicht, weil hierfür kein Timer zu Verfügung steht. Was ich noch immer nicht verstehe, warum kann ich nicht mit Timer2 die Ausgänge PB1, PB2, PB3 steuern? Anbei der fehlerfrei compilierte c-Code
1 | #include<avr/io.h> |
2 | //#define F_CPU 20000000UL //Taktfrequenz 20MHz
|
3 | #include<util/delay.h> // Verzögerung |
4 | |
5 | int main(void) |
6 | {
|
7 | DDRB |= (1<<PB2); //initialisieren Output 16 [Motor rechtslauf] |
8 | DDRB |= (1<<PB1); //initialisieren Output 15 [Motor linkslauf] |
9 | DDRB |= (1<<PB0); //initialisieren Output 14 [Motor rechtslauf] |
10 | DDRB |= (1<<PB3); //initialisieren Output 17 [Motor linkslauf] |
11 | DDRD |= (1<<PD5); //initialisieren Output 11 [LED] |
12 | |
13 | PORTD |= (1<<PD5); //LED einschalten |
14 | PORTB &= ~(1<< PB2); //PB2 im PORTB löschen [1A], um Invertierung am [2A] zu vermeiden |
15 | PORTB &= ~(1<< PB0); //PB0 im PORTB löschen [4A], um Invertierung am [3A] zu vermeiden |
16 | unsigned char duty_cyc_a,duty_cyc_b; |
17 | duty_cyc_a=0; // Initial Duty Cycle for Channel A |
18 | duty_cyc_b=0; // Initial Duty Cycle for Channel B |
19 | |
20 | |
21 | // erster Motor start: (PB1 im PORTB setzten [2A])
|
22 | |
23 | TCCR2B = (1<<CS21) | (1<<CS20); //Clock select |
24 | TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode |
25 | OCR2A = 0; |
26 | OCR2B = 0; |
27 | while(duty_cyc_a < 255) //hochfahren |
28 | {
|
29 | OCR2A=duty_cyc_a++; |
30 | OCR2B=duty_cyc_b--; |
31 | _delay_ms(100); |
32 | }
|
33 | |
34 | while(duty_cyc_b < 255) //runterfahren |
35 | {
|
36 | OCR2A=duty_cyc_a--; |
37 | OCR2B=duty_cyc_b++; |
38 | _delay_ms(200); |
39 | }
|
40 | // erster Motor stop, Timer reseten
|
41 | PORTB &= ~(1<< PB1); // PB1 im PORTB löschen [2A] |
42 | TCCR2A = 0; // Timer auf 0 reseten |
43 | TCCR2B = 0; // Timer auf 0 reseten |
44 | TCNT2 = 0; // clear |
45 | TIFR2 = 0xFF; // clear interrupt-flags |
46 | //zweiter Motor start (PB3 im PORTB setzten [3A])
|
47 | |
48 | TCCR2B = (1<<CS21) | (1<<CS20); //Clock select |
49 | TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode |
50 | OCR2A = 0; |
51 | OCR2B = 0; |
52 | while(duty_cyc_a < 255) |
53 | {
|
54 | OCR3A=duty_cyc_a++; |
55 | OCR3B=duty_cyc_b--; |
56 | _delay_ms(100); |
57 | }
|
58 | |
59 | while(duty_cyc_b < 255) |
60 | {
|
61 | OCR3A=duty_cyc_a--; |
62 | OCR3B=duty_cyc_b++; |
63 | _delay_ms(200); |
64 | }
|
65 | // zweiter Motor stop
|
66 | PORTB &= ~(1<< PB3); // PB3 im PORTB löschen [3A] |
67 | |
68 | return 0; |
69 | }
|
Julia W schrieb: > Was ich noch immer nicht verstehe, warum kann ich nicht mit Timer2 die > Ausgänge PB1, PB2, PB3 steuern? Schau dir im Datenblatt das Kapitel "18.11.1 TCCR2A – Timer/counter control register A" und dort speziell die COM Bits auf Bitposition 7, 6, 5, 4 an. Die Tabellen darunter zeigen dir, daß man nur die OC2A und OC2B Pins für die HW-PWM beim Timer2 nutzen kann. Entsprechenden Kapitel gibt es auch für Timer1 und Timer0.
Julia W schrieb: > @ Dieter: Also ich kann PB1, PB2, PB3 für PWM benutzen, richtig? Ja, wenn Du Timer 1 UND Timer 2 einsetzt. Dann kannst Du auch PD3 nutzen (mit Timer 2). Für PD5 und PD6 müsstetst Du zusätzlich Timer 0 aktivieren. Hast Du Dir das Bild angeschaut und den Zusammenhang verstanden?
Julia W schrieb: > OCR3A=duty_cyc_a++; > OCR3B=duty_cyc_b--; Es gibt keinen Timer 3 (und auch keinen Timer 4) bei ATMega 168. Es gibt nur Timer 0, 1 , 2. Auch da gibt es wieder den Zusammenhang mit der Timer-Nr. OCRxA, OCRxB (x = Timer-Nr.). Hast Du Dir eigentlich das Bild (aus dem Datenblatt) angeschaut und verstanden? -> Datenblatt
Ich habe mich nach dem Datenblatt gerichtet, und die einzelnen Bits äquivalent zu Timer2 gesetzt, weil hier ja wenigstens ein Motor lief. Jetzt laufen hoffentlich beide ;)
1 | #include<avr/io.h> |
2 | //#define F_CPU 20000000UL //Taktfrequenz 20MHz
|
3 | #include<util/delay.h> // Verzögerung |
4 | |
5 | int main(void) |
6 | {
|
7 | DDRB |= (1<<PB2); //initialisieren Output 16 [Motor rechtslauf] |
8 | DDRB |= (1<<PB1); //initialisieren Output 15 [Motor linkslauf] |
9 | DDRB |= (1<<PB0); //initialisieren Output 14 [Motor rechtslauf] |
10 | DDRB |= (1<<PB3); //initialisieren Output 17 [Motor linkslauf] |
11 | DDRD |= (1<<PD5); //initialisieren Output 11 [LED] |
12 | PORTD |= (1<<PD5); //LED einschalten |
13 | PORTB &= ~(1<< PB2); |
14 | PORTB &= ~(1<< PB0); |
15 | PORTB &= ~(1<< PB1); |
16 | PORTB &= ~(1<< PB3); |
17 | unsigned char duty_cyc_a,duty_cyc_b; |
18 | duty_cyc_a=0; // Initial Duty Cycle for Channel A |
19 | duty_cyc_b=0; // Initial Duty Cycle for Channel B |
20 | |
21 | |
22 | // erster Motor start:
|
23 | |
24 | TCCR2B = (1<<CS21) | (1<<CS20); //Clock select |
25 | TCCR2A = (1<<COM2A1) | (1<<WGM21) | (1<<WGM20); //Waveform generation mode |
26 | OCR2A = 0; |
27 | OCR2B = 0; |
28 | while(duty_cyc_a < 255) //hochfahren |
29 | {
|
30 | OCR2A=duty_cyc_a++; |
31 | OCR2B=duty_cyc_b--; |
32 | _delay_ms(100); |
33 | }
|
34 | |
35 | while(duty_cyc_b < 255) //runterfahren |
36 | {
|
37 | OCR2A=duty_cyc_a--; |
38 | OCR2B=duty_cyc_b++; |
39 | _delay_ms(200); |
40 | }
|
41 | // erster Motor stop, Timer reseten
|
42 | |
43 | TCCR2A = 0; // Timer auf 0 reseten |
44 | TCCR2B = 0; // Timer auf 0 reseten |
45 | TCNT2 = 0; // clear |
46 | TIFR2 = 0xFF; // clear interrupt-flags |
47 | //zweiter Motor start
|
48 | |
49 | TCCR1B = (1<<CS11) | (1<<CS10); //Clock select |
50 | TCCR1A = (1<<COM1A1) | (1<<WGM11) | (1<<WGM10); //Waveform generation mode |
51 | OCR1A = 0; |
52 | OCR1B = 0; |
53 | while(duty_cyc_a < 255) |
54 | {
|
55 | OCR1A=duty_cyc_a++; |
56 | OCR1B=duty_cyc_b--; |
57 | _delay_ms(100); |
58 | }
|
59 | |
60 | while(duty_cyc_b < 255) |
61 | {
|
62 | OCR1A=duty_cyc_a--; |
63 | OCR1B=duty_cyc_b++; |
64 | _delay_ms(200); |
65 | }
|
66 | // zweiter Motor stop, Timer reseten
|
67 | |
68 | TCCR1A = 0; // Timer auf 0 reseten |
69 | TCCR1B = 0; // Timer auf 0 reseten |
70 | TCNT1 = 0; // clear |
71 | TIFR1 = 0xFF; // clear interrupt-flags |
72 | return 0; |
73 | }
|
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.