N'abend community,
ich habe Atmel studio 7, arduino uno r3 board, atmega 328p mit 16mhz.
Ich möchte ein 38khz signal mithilfe eines timers erstellen. Leider hat
es nach vielem lesen und probieren geklappt. Nun verstehe ich die
programmierung nicht. :D
ich will durch das hochzählen bis 211 eine halbwelle erzeugen, pin
toggeln und anschließend mit ausgeschaltetem pin hochzählen.
Soweit klappt es. Nur verstehe ich nicht, warum die frequenz sich so
stark ändert.
Wenn ich ocr0a=210 eingebe, erhalte ich 18,94khz.
bei 209 - garnichts.
208 - 7,692khz.
207 - 15,6khz
206 - 9,615khz
Egal was ich bei ocr0a in richtung "0" eingebe, ich sehe keine
proportionale veränderung der freuquenz am oszi.
hab ich etwas übersehen? und ist es überhaupt ohne interrupt machbar?
1
#include<avr/io.h>
2
3
intmain(void)
4
{
5
DDRB|=0x04;
6
TCCR0A|=(1<<WGM01);//CTC
7
TCCR0B|=(1<<CS00);//no prescaling
8
OCR0A=211;// 16mhz/2/38000khz = 210,52takte pro halbe periode
9
// -> ich wähle 211 takte und erhalte 37,880khz auf dem oszi
10
11
while(1){
12
if(TIFR0&(1<<OCF0A))//Wenn OfC0A "1" ist soll PB2 toggeln.
Jürgen M. schrieb:> if (TIFR0 & (1 << OCF0A)) //Wenn OfC0A "1" ist soll PB2 toggeln.> {> PORTB ^= 0x04;> }> TIFR0 |= (1 << OCF0A);
Hier kann es passieren, dass der Timer genau dann seinen Endwert
erreicht, nachdem der Vergleich "if (TIFR0 & (1 << OCF0A))" durchgeführt
wurde, aber bevor das Löschen des Flags kommt. Das bedeutet, dass das
Flag anschließend gelöscht ist, ohne dass der Portausgang getoggelt
wurde. Besser ist es, das Löschen des Flags in die if-Klammer
reinzunehmen:
1
if(TIFR0&(1<<OCF0A))//Wenn OfC0A "1" ist soll PB2 toggeln.
hab ich abgeändert, aber die frequenzen verhalten sich immer noch
unproportional.
wenn ich die takte zurückrechne, dann müsste doch eigentlich eine
taktzahl von 208
16000000/2/208=38461hz ergeben. aber mein oszi zeigt mir nur 7,6khz.
Jürgen M. schrieb:> Leider hat> es nach vielem lesen und probieren geklappt.
Leider? Ist doch prima ;)
Jürgen M. schrieb:> Nun verstehe ich die> programmierung nicht.
Nochmal lesen kann helfen ;)
Jürgen M. schrieb:> hab ich etwas übersehen? und ist es überhaupt ohne interrupt machbar?
Ja, aber warum willst du es ohne ISR machen? Ist doch Quatsch.
1
while(1){
2
if(TIFR0&(1<<OCF0A))//Wenn OfC0A "1" ist soll PB2 toggeln.
3
{
4
PORTB^=0x04;
5
}// <- Stellen wir uns vor wenn der Mikrocontroller hier ist tritt der CTC auf.
6
TIFR0|=(1<<OCF0A);// dann wird er hier direkt wieder gelöscht. Die if-Bedingung sieht das aber nie.
7
}// das ist viel zu ungenau/unsicher, daher ISR benutzen! Kostet doch nix.
Karl M. schrieb:> Und dies ist so nicht korrekt, siehe Datenblatt:
Wieso?
Atmega328 Datasheet Page 148
> ...> OCF0A is cleared by writing a logic one to the flag.> ...
Da steht nichts davon, dass man in alle anderen Bits ne 0 reinschreiben
soll oder anders gesagt ein
1
TIFR0|=(1<<OCF0A);
bewirkt an der Stelle das Selbe wie ein
1
TIFR0=(1<<OCF0A);
Da sich Bits in diesem Register nur durch das Reinschreiben einer 1
löschen lassen.
M. K. schrieb:> Atmega328 Datasheet Page 148>> ...>> OCF0A is cleared by writing a logic one to the flag.>> ...> Da steht nichts davon, dass man in alle anderen Bits ne 0 reinschreiben> soll oder anders gesagt einTIFR0 |= (1 << OCF0A);> bewirkt an der Stelle das Selbe wie einTIFR0 = (1 << OCF0A);
Nein, das bewirkt nur dann das Selbe, wenn alle anderen Bits im Register
vorher 0 waren. Wenn ein anderes Bit 1 war, dann wird dieses meiner
Ansicht nach ebenfalls gelöscht.
@Edi:
Danke, das war der Fehler.
@köhler:
Ich danke dir für deinen Rat. Sicher kommt eine gute programmierung an
interrupts nicht vorbei. Nur bin ich noch in den anfängen und will
erstmal grundkenntisse in C erlangen. Davor hatte ich ne zeitlang in
arduino programmiert und da war alles mit hintergrundabläufen verbastelt
und ungenau, da sind solche kleinen Fehler kaum aufgefallen.
Gruß Jürgen
Edi R. schrieb:> Wenn ein anderes Bit 1 war, dann wird dieses meiner> Ansicht nach ebenfalls gelöscht.
Nein, wird es nicht. Ein Bit im TIFR kann nur dadurch gelöscht werden
indem man eine eins reinschreibt. Das steht genau so auch im Datenblatt.
Schreibt man eine null rein ändert sich das entsprechende Bit nicht.
Unter der Berücksichtigung der Wahrheitstabelle für das TIFR (0 nur dann
wenn zwei Einsen im Spiel sind) bewirkt dann ein
1
TIFR0=(1<<OCF0A);
2
// ist z.B. ein 0b00000110 :TIFR0
3
// &0b00000100 :1<<OCF0A
4
// -----------
5
// 0b00000010 :new TIFR0
exakt das Selbe wie ein
1
TIFR0|=(1<<OCF0A)
2
// ist z.B. ein 0b00000110 :TIFR0
3
// |0b00000100 :1<<OCF0A
4
// -----------
5
// 0b00000010 :new TIFR0
[/c]
den ein
1
x|=1<<y;
schreibt lediglich eine 1 in x an die Bitstelle y und lässt alle anderen
Stellen unverändert.
Ein
1
x&=1<<y;
würde eine 1 in x an die Bitstelle y schreiben und an alle anderen
Stellen einen 0.
M. K. schrieb:> Edi R. schrieb:>> Wenn ein anderes Bit 1 war, dann wird dieses meiner>> Ansicht nach ebenfalls gelöscht.>> Nein, wird es nicht.
Doch, wird es.
M. K. schrieb:> // ist z.B. ein 0b00000110 :TIFR0> // |0b00000100 :1<<OCF0A> // -----------> // 0b00000010 :new TIFR0
Nein, 0b00000110 | 0b00000100 ist 0b00000110
M. K. schrieb:> den ein> x |= 1 << y;> schreibt lediglich eine 1 in x an die Bitstelle y und lässt alle anderen> Stellen unverändert.
Und wie passiert das "lässt alle anderen Stellen unverändert"? Indem das
|= überall dort eine 0 hinschreibt, wo auch vorher eine 0 war, und
überall dort eine 1 hinschreibt, wo auch vorher eine 1 war. Und
letzteres bedeutet im Kontext des TIFR0 "lösche ALLE gesetzten Flags".
Nachtrag:
M. K. schrieb:> Ein> x &= 1 << y;> würde eine 1 in x an die Bitstelle y schreiben und an> alle anderen> Stellen einen 0.
Auch das ist falsch. "alle anderen Stellen eine 0" ist richtig, aber an
die Bitstelle y wird geschrieben, was auch vorher drin war, nicht immer
eine 1.