Hallo,
Ich möchte eine PWM erzeugen. Am Ausgang OCA1 ist eine LED
angeschlossen. Der AD-Wandler ADC0 soll im 10-Bit Modus laufen.
Die Interrupt Routine wird nicht angesprungen. Ich finde den Fehler
nicht. Wenn mir jemand helfen könnte dem wäre ich dankbar.
1
#define F_CPU 160000000
2
#include<avr/io.h>
3
#include<stdint.h>
4
#include<avr/interrupt.h>
5
6
7
volatileuint16_tbuffer;
8
volatileint8_tflag;
9
10
ISR(TIMER1_COMPA_vect)
11
{
12
//Hilfsport setzen
13
PORTD|=1<<PD0;
14
15
// Wandlung vom analogen Eingang starten
16
ADCSRA|=(1<<ADSC);
17
18
// Warten bis die AD-Wandlung abgeschloßen ist
19
while(!(ADCSRA&(1<<ADIF)));
20
21
//Hilfsport zurücksetzen
22
// PORTD &= ~(1 << PD0);
23
PORTD=0;
24
25
buffer=ADC;
26
OCR1A=buffer*4;
27
}
28
29
30
31
intmain()
32
{
33
//Alle Interrupts ausschalten
34
cli();
35
36
//Hilfsport als Ausgang definieren und zuruecksetzen
37
DDRD=DDRB|(1<<PD0);
38
PORTD=0;
39
40
41
// Timer für PWM initialisieren
42
// OC1A auf Ausgang
43
DDRB=(1<<PB1);
44
TCCR1A=(1<<COM1A1);
45
TCCR1B=(1<<WGM13)|(1<<CS10);
46
47
// PWM Frequenz auf 2000 Hz stellen bei 16 Mhz Oscillator
48
ICR1=4000;
49
50
//Timer Interrupt initialisieren und globale Interrupts enable
51
TIMSK=TIMSK|(1<<OCIE1A);
52
sei();
53
54
// AD-Wandler initialisieren und auf 10 Bit stellen
Was mißt denn der ADC?
Im gewählten Timermodus ist ICR1=1000 der TOP Wert. Hier:
buffer = ADC;
OCR1A=buffer * 4;
kann der Comparewert für den Interrupt aber locker über 1000 gesetzt
werden, so daß der Interrupt sich quasi selber an der Ausführung
hindert.
Auf ADC0 ist am Mittelabgriff eines Potentiometer mit 5 V Versorgung
angeschlossen.
Wenn ich den Code aus der Interrupt-Routine in der Hauptschleife des
Hauptprogramms ausführe, dann wird die PWM mit 2kHz Frequenz ausgeführt.
Über das Potentiometer läßt sich dann die Pulsbreite der PWM stufenlos
einstellen. Nur der Atmega8 führt dann die AD-Wandlung permanent aus.
Ich möchte allerdings, dass die AD-Wandlung nur einmal pro Interrupt
Zyklus ausgeführt wird.
Högli schrieb:> Im gewählten Timermodus ist ICR1=1000 der TOP Wert. Hier:
Sorry, muß ICR1=4000 heißen. Kann aber immer noch vom ADC * 4 überboten
werden.
> Ich möchte allerdings, dass die AD-Wandlung nur einmal pro Interrupt> Zyklus ausgeführt wird.
In der ISR die ADC Messung starten. Dann in der Hauptschleife "// Warten
bis die AD-Wandlung abgeschloßen ist" oder den ADC Interrupt nutzen. In
der ISR auf Abschluß der Wandlung warten ist selten sinnvoll.
Vielen Dank für die Kommentare!
Högli schrieb:> In der ISR die ADC Messung starten. Dann in der Hauptschleife "// Warten> bis die AD-Wandlung abgeschloßen ist" oder den ADC Interrupt nutzen. In> der ISR auf Abschluß der Wandlung warten ist selten sinnvoll.
Ich habe den Kommentar umgesetzt, und siehe da es funktioniert. Dabei
habe ich der Übersicht halber noch einzelne Änderungen durchgeführt. Der
neue C-Code lautet folgendermassen:
1
#define F_CPU 160000000
2
#include<avr/io.h>
3
#include<stdint.h>
4
#include<avr/interrupt.h>
5
6
7
volatileuint16_tbuffer;
8
volatileint8_tflag;
9
10
ISR(TIMER1_COMPA_vect)
11
{
12
flag=1;
13
}
14
15
16
17
intmain()
18
{
19
//Alle Interrupts ausschalten
20
cli();
21
22
//Hilfsport als Ausgang definieren und zuruecksetzen
23
DDRD=DDRB|(1<<PD0);
24
PORTD=0;
25
26
27
// Timer für PWM initialisieren
28
// OC1A auf Ausgang
29
DDRB=DDRB|(1<<PB1);
30
TCCR1A=TCCR1A|(1<<COM1A1);
31
TCCR1A=TCCR1A|(0<<COM1A0);
32
TCCR1B=TCCR1B|(1<<WGM13);
33
TCCR1B=TCCR1B|(0<<WGM12);
34
TCCR1B=TCCR1B|(1<<CS10);
35
TCCR1B=TCCR1B|(0<<CS11);
36
TCCR1B=TCCR1B|(0<<CS12);
37
TCCR1A=TCCR1A|(0<<WGM10);
38
TCCR1A=TCCR1A|(0<<WGM11);
39
40
// PWM Frequenz auf 1953 Hz stellen bei 16 Mhz Oscillator
41
ICR1=4095;
42
43
//Timer Interrupt initialisieren und globale Interrupts enable
44
TIMSK=TIMSK|(1<<OCIE1A);
45
sei();
46
47
// AD-Wandler initialisieren und auf 10 Bit stellen
48
ADMUX=(1<<REFS0);
49
ADCSRA=(1<<ADEN);
50
51
//Startwert für PWM festlegen
52
OCR1A=1000;
53
54
while(1)
55
{if(flag==1)
56
{
57
//Hilfsport setzen
58
PORTD|=1<<PD0;
59
60
// Wandlung vom analogen Eingang starten
61
ADCSRA|=(1<<ADSC);
62
63
// Warten bis die AD-Wandlung abgeschloßen ist
64
while(!(ADCSRA&(1<<ADIF)));
65
66
//Hilfsport zurücksetzen
67
// PORTD &= ~(1 << PD0);
68
PORTD=0;
69
70
buffer=ADC;
71
// OCR1A = buffer * 4;
72
OCR1A=(buffer<<2);
73
flag=0;
74
}
75
76
}
77
}
Den ADC möchte ich nicht frei laufen lassen, um für spätere Anwendungen
Rechenkapazität zu sparen.
Man könnte auch die ADC Wandlung wie ursprünglich in der ISR starten. In
der Hauptschleife ohne irgendeine Abfrage oder auf irgendwas zu warten
den ADC Wert immer einfach direkt dem OCR1A zuweisen. Wird zwar oft
zugewiesen, ändert sich ja dann aber ohnehin nur mit der
Interruptfrequenz mit der ja eine neue Wandlung gestartet wird. Ob das
in dein Konzept paßt mußt du dann schauen.
Uwe S. schrieb:> // Warten bis die AD-Wandlung abgeschloßen ist> while ( (ADCSRA & (1<<ADSC)) ) { }
Und was passiert, wenn man die Zeile ganz weg läßt ?
Funktionieren tut es auch ohne dieser Zeile.
Hi
>Und was passiert, wenn man die Zeile ganz weg läßt ?>Funktionieren tut es auch ohne dieser Zeile.
Das gleiche wie bei
>while ( !(ADCSRA & (1<<ADIF)) );
Der Controller macht ohne zu warten weiter. ADIF bleibt nämlich 1, wenn
du es nicht manuell zurück setzt.
ADSC dagegen bleibt so nur lange 1 bis der ADC mit der Conversation
fertig ist.
MfG Spess
Wenn ich das Datenblatt nicht lesen würde, dann wäre ich nicht soweit
gekommen!
Eine bessere Frage wäre wohl gewesen, warum der ATMEGA8 die ADC Wandlung
noch zu Ende führt:
> while ( (ADCSRA & (1<<ADSC)) ) { }
Meine Erwartung wäre gewesen, dass der ATMEGA8 im Code fortschreitet
(wenn die Zeile nicht vorhanden ist)und die ADC Wandlung abbricht.
>Wenn ich das Datenblatt nicht lesen würde, dann wäre ich nicht soweit>gekommen!
Zustimmung!
In Anbetracht der Tatsache, daß es sich um DATENBÜCHER mit mehreren
hundert Seiten handelt, in denen die zusammenhängenden Informationen
sehr gut gestreut vorliegen, kann es passieren, daß man einen Halbsatz
überliest.
Diese Überheblichkeit ist nicht angebracht!
Händeringer schrieb:> In Anbetracht der Tatsache, daß es sich um DATENBÜCHER mit mehreren> hundert Seiten handelt, in denen
die Kapitel mir der Beschreibung zu den einzelnen Modulen immer nur
wenige Seiten umfassen, ist das durch aus machbar.
Oliver
Hi
>Meine Erwartung wäre gewesen, dass der ATMEGA8 im Code fortschreitet>(wenn die Zeile nicht vorhanden ist)und die ADC Wandlung abbricht.
Warum soll der ADC die Wandlung abbrechen? Dem ADC ist es egal ob ADSC
abgefragt wird.
MfG Spess