Hallo,
ich habe ein kleines Problem und hoffe, mit der Anfängerfrage nicht zu
sehr zu nerven:
Ich habe eine Fast PWM programmiert, funktioniert auch wunderbar:
1
intmain(void)
2
{
3
DDRD|=(1<<PD5);// PWM Ausgang
4
DDRB=0x00;
5
DDRA=0xff;
6
7
TIMSK|=(1<<OCIE1A);// Interrupt bei Compare A
8
TCCR1A|=(1<<COM1A1);//set am Periodenanfang, clear bei Vergleich
9
TCCR1B|=(1<<WGM12);
10
TCCR1A|=(1<<WGM10|1<<WGM11);// FastPWM 10-Bit
11
OCR1A=(200);// Anfangsvergleichwert
12
13
TCCR1B|=((1<<CS10));// Starte Timer mit Fcpu/1
14
15
sei();
16
17
while(1)
18
{
19
}
20
21
22
23
return1;
24
};
Jetzt würde ich das ganze gerne so einstellen, dass der Tastgrad auf
Knopfdruck erhöht wird, und setze dafür folgenden Code in die while
Schleife:
1
if(debounce(&PINB,PB0))
2
{
3
OCR1A+=100;//Erhöhe Vergleichswert
4
}
mit
1
uint8_tdebounce(volatileuint8_t*port,uint8_tpin)
2
3
{
4
5
if(!(*port&(1<<pin)))
6
{
7
cli();
8
_delay_us(1);
9
if(!(*port&(1<<pin)))
10
{
11
_delay_ms(200);
12
return1;
13
}
14
}
15
sei();
16
return0;
17
}
Man sieht dann auf dem Oszi, dass der Tastgrad erhöht wird, solange ich
die Taste gedrückt halte, aber sobald ich sie loslasse, hüpft er wieder
auf den Anfangswert zurück. Als nächstes habe ich versucht, vor der
Neuzuweisung von OCR1A die Interrupts global auszuschalten und danach
wieder einzuschalten, das führt aber nur dazu, dass sich der Tastgrad
auch beim Halten der Taste nicht mehr verändert.
Sieht jemand von euch den Fehler?
Es geht übrigens um eine ATMega 32 auf einem STK 500, programmiert wird
mit WinAVR / AVRStudio 4.
Gruß, Daniel
Hi,
ich habe grade eine Lösung gefunden:
Ich schalte den OCIE1A vor dem setzen von OCR1A ab, setze den neuen Wert
und schalte den Interrupt danach nicht wieder explizizt an, und jetzt
funktioniert. Könnte man natürlich sagen toll, hat funktioniert, aber
ich würde schon gerne wissen, warum es funktioniert ;) Kann mir jemand
helfen?
Gruß, Daniel
Hi,
danke, stimmt, das war ein Fehler. Allerdings bringt nur das leider
nicht die Lösung, im Gegenteil, jetzt funktioniert meine Lösung (siehe
Post vorher) nicht mehr.
Gruß, Daniel
Kann es sein das die Routine _delay_ms() auch auf Interrupts angewiesen
ist ? Wenn du die Interrupst vorher sperrst kommt der Prozesoor da
niemehr raus.
Das scheint in die richtige Richtung zu gehen...
Nur mal als Zwischenstand, hier der aktuelle Code:
1
#define F_CPU 16000000UL
2
3
#include<avr/io.h>
4
#include<avr/interrupt.h>
5
#include<util/delay.h>
6
7
uint8_tdebounce(volatileuint8_t*port,uint8_tpin)
8
9
{
10
11
if(!(*port&(1<<pin)))
12
{
13
TIMSK&=~(1<<OCIE1A);
14
_delay_us(1);
15
if(!(*port&(1<<pin)))
16
{
17
_delay_ms(200);
18
TIMSK|=(1<<OCIE1A);
19
return1;
20
}
21
}
22
TIMSK|=(1<<OCIE1A);
23
return0;
24
}
25
26
intmain(void)
27
{
28
DDRD|=(1<<PD5);// PWM Ausgang
29
DDRB=0x00;
30
DDRA=0xff;
31
32
TIMSK|=(1<<OCIE1A);// Interrupt bei Compare A
33
TCCR1A|=(1<<COM1A1);//set am Periodenanfang, clear bei Vergleich
34
TCCR1B|=(1<<WGM12|1<<WGM13);
35
TCCR1A|=(1<<WGM11);// FastPWM 10-Bit
36
ICR1=128;
37
OCR1A=(32);// Anfangsvergleichwert
38
39
TCCR1B|=((1<<CS10));// Starte Timer mit Fcpu/1
40
41
TIMSK|=(1<<OCIE1A);//bzw. sei();
42
43
while(1)
44
{
45
if(debounce(&PINB,PB0))
46
{
47
OCR1A+=10;//Erhöhe Vergleichswert
48
}
49
}
50
51
52
return1;
53
};
So funktioniert es wunderbar. Wenn ich aber vor der while Schleife
sei(); schreibe, habe ich wieder das alte Problem, dass er den Tastgrad
setzt, wenn ich die Taste halte, aber danach wieder zurück hüpft. Das
ist mir noch etwas unverständelich... Insbesondere, wo er den alten Wert
wieder her nimmt.
>So funktioniert es wunderbar. Wenn ich aber vor der while Schleife>sei(); schreibe, habe ich wieder das alte Problem, dass er den Tastgrad
TIMSK |= (1<<OCIE1A); // Interrupt bei Compare A
Wo ist denn die dazu gehoereige Interruptservice Routine ?
So springt er irgendwo hin.
Oh, hatte eigentlich gedacht, dass sie das müssen, weil der Pin ja bei
Compare umgesetzt werden muss. Aber habs grade mal ausprobiert, das geht
ja auch ohne... Dann hatte ich da wohl was falsch verstanden ;)
Vielen Dank nochmal!
>Tatsache, das wars... Vielen Dank! Ich hatte halt gedacht, dass ich die>ISR auch weglassen kann, wenn sie eh nichts tut ;)
Auch wenn sie scheinbar nichts tut , tut sie doch etwas .
Zumindest ist dort ein Return Befehl der ins normale Programm
zurueckspringt. Auch werden Hardwaremaessig einige Flags geloescht.
hallo, zur pwm existieren bereits so viele threads, dass ich mir mit
meiner frage diesem thread anschließen möchte.
ich habe, das als erste gepostete programm von daniel leicht für meine
bedürfnisse abgeändert:
1
2
intmain(void)
3
{initRP6Control();
4
5
6
DDRD|=(1<<PD4);// PWM Ausgang
7
8
9
TCCR1A|=(1<<COM1A1);//set am Periodenanfang, clear bei Vergleich
10
11
TCCR1A|=(1<<WGM12);
12
TCCR1A|=(1<<WGM10|1<<WGM11);// FastPWM 10-Bit
13
14
15
TCCR1B|=((1<<CS10));// Vorteiler= 1
16
17
OCR1A=(900);
18
19
while(1)
20
{
21
}
22
23
return1;
24
};
dazu hab ich jetzt das TCCR1B |= (1 << WGM12); mit TCCR1A |= (1 <<
WGM12); abgeändert, da es meiner meinung nach laut datenblatt so richtig
ist.
kann mir vielleicht jemand sagen, ob ich mit dieser einschätzung richtig
liege, bzw ob dieses programm so funktionieren kann?
gruß
gast schrieb:
> kann mir denn gar niemand weiterhelfen?
Die WGM Bits sind bei unterschiedlichen Porzessoren in unterschiedlichen
Registern. Wenn im Datenblatt deines Prozessors steht, dass es im TCCR1A
Register ist, dann wird das schon stimmen. Das Datenblatt hat immer
recht.
> kann mir denn gar niemand weiterhelfen?
Soll das heißen, du hast jetzt 2 Tage auf Antwort gewartet ohne die
Veränderung wenigstens einmal auszuprobieren?
Die Frage kannst du dir doch in 3 Minuten selbst beantworten. Probiers
so aus wie es Daniel gepostet hat, probier deine Version aus. Welche
funktioniert? Zur Sicherheit nochmal im Datenblatt nachgesehen, ob du
dich mit der Interpretation des Datenblattes nicht vertan hast, und dann
weißt du es mit Sicherheit.
also, jetzt hab ich beides ausprobiert und muss sagen, dass beides geht.
es scheint also egal ob man TCCR1B |= (1 << WGM12) oder TCCR1A |= (1 <<
WGM12) setzt. ich konnte im datenblatt zwar nur WGM12 in verbindung mit
TCCR1A finden, aber es funktioniert auch so wie es daniel oben gemacht
hat.
vielen dank trotzdem
gast schrieb:
> also, jetzt hab ich beides ausprobiert und muss sagen, dass beides geht.> es scheint also egal ob man TCCR1B |= (1 << WGM12) oder TCCR1A |= (1 <<> WGM12) setzt. ich konnte im datenblatt zwar nur WGM12 in verbindung mit> TCCR1A finden,
Gut.
Jetzt siehst du nochmal im Datenblatt nach, welches Bit im TCCR1A das
Bit WGM12 ist.
Mit dieser Bitnummer suchst du dann die Beschreibung vom TCCR1B Register
auf und siehst nach, was das Bit mit der gleichen Nummer in diesem
Register macht.
Damit weist du dann auch, welche Funktion des Timers du noch
eingeschaltet hast ohne es zu merken.
Hinweis:
Kleb nicht an der Bezeichnung WGM12. Die wird vom Compiler einfach nur
in eine Zahl übertragen. Und dem Compiler ist es völlig egal, ob es im
betreffenden Register ein Bit dieses Namens gibt. Denn wie gesagt, die
Bezeichnung WGM12 steht einfach nur für eine Zahl.
Letztendlich steht bei
TCCR1B |= ( 1 << WGM12 );
im Grunde nur da: Setzte Bit Nr 3 (3 jetzt mal als Hausnummer genommen)
im Register TCCR1B.
Du hättest genausogut auch schreiben können
TCCR1B |= ( 1 << PD3 );
Würde genau das gleiche machen (wenn WGM12 wirklich 3 ist), oder
irgendeinen anderen Ausdruck der 3 ergibt
TCCR1B |= ( 1 << ( 9 - 6 ) );
oder TCCR1B |= ( 1 << ( 6 / 2 ) );
Ist alles das Gleiche.
Daher ist es wichtig, sich im Datenblatt seines Prozessors anzusehen,
welches Bit in welchem Register was macht und nicht einfach blind
irgendwelche Bits in irgendwelchen Registern zu setzen, nur weil
irgendeine literarische Vorlage das auch so macht. Du musst
Funktionalität von einem Prozessor zu einem anderen Prozessor
übertragen. Aber kein Mensch garantiert dir, dass auf einem anderen
Prozessor dieselbe Funktionalität mit den gleichen Bits in den gleichen
Registern erreicht wird.
Und daher ist es auch wichtig, dass du bei solchen Fragen im Forum immer
auch deinen Prozessor angibst, damit die Helfenden das richtige
Datenblatt herausholen können um darin nachzusehen, welche Bits du
setzen musst.
also,
jetzt hab ich nochmal nachgeschaut. das WGM 12 Bit bei TCCR1A schaltet
meiner meinung nach den CTC modus des timers 1 ein.
da ich diesen modus nicht brauche sondern lediglich eine LED mit PWM
ansteuern will, brauche ich das WGM12 bit auch nicht setzen.
habs jetzt mal ohne probiert und funktioniert genauso.
mein prozessor ist der gleiche wie der von daniel, nämlich ein Atmel
Atmega 32.
gruß
gast schrieb:
> mein prozessor ist der gleiche wie der von daniel, nämlich ein Atmel> Atmega 32.
Ich weiß nicht, wo du ständig nachsiehst.
Wenn ich in meinem Datenblatt die Register Description vom Timer 1
aufschlage und dort unter TCCR1A nachsehe, dann existiert in TCCR1A ganz
einfach kein Bit mit dem Namen WGM12
Es gibt aber sehr wohl in TCCR1B das entsprechende Bit.
Geh ich in die Tabelle "Waveform Generation Mode Bit Description", dann
findet sich dort der Modus 7 "Fast PWM,10Bit" bei dem WGM12, WGM11 und
WGM10 gesetzt sind. Achtung: Nur weil diese Bits in dieser Tabelle
zusammengefasst sind bedeutet das nicht, dass sie im selben Register
sind! Die können über TCCR1A bzw. TCCR1B verstreut sein. Aufschluss
darüber gibt nur die entsprechende Beschreibung des jeweiligen
Registers.
"Fast PWM, 10 Bit" stimmt auch auffallend mit dem Kommentar in Daniels
Programm überein.
Edit:
Die Beschreibung des TCCR1A Registers ist im Datenblatt der Abschnitt
16.10.1 auf Datenblattseite 110.
Gleich zu Beginn des Abschnitts ist eine Grafik, in der alle Bits dieses
Registers aufgeführt sind. WGM10 und WGM11 sind da drinnen. Aber von
WGM12 fehlt jede Spur
Die bewusste Modus Tabelle ist auf Seite 114 und gleich darunter beginnt
auch die Beschriebung von TCCR1B mit der gleichwertigen Grafik, in der
sich WGM12 und WGM13 wiederfinden.
Wenn du selbst einen bestimmten Modus brauchst, dann gehst du in diese
Tabelle und wählst den entsprechenden Modus aus. Hast du den Modus,
siehst du in der Tabelle nach, welche Bits dafür gesetzt werden müssen.
Und dann sieht man nach in welchem Register, TCCR1A oder TCCR1B, das
entsprechende Bit zu finden ist.