hallo leute,
da ich mit dem Assembly-code vom Marderschreck ziemlich frustiert bin
und denke mal nach einigen Posts keine lust mehr haben sicih weiter zu
beschäftigen habe ich mich dazu entschlossen mir mein eigenes Programm
zu schreiben. Zwar ist das ein optimales Programm hat aber noch seine
kleinen Tücken. Ich weiss gerade nicht wie ich die frequenz stetig
ändern kann dass ich am ende ne bandbreite zwischen 20- 40khz habe. Ich
habs wenigstens geschafft am ausgang 31khz raus zu bekommen. Jedoch
hängt es immer davon ab welchen wert ich pwm_max zuweise.
Ich versuche nach diesem assembler code auf der schreibe:(
http://www.elektronik-labor.de/AVR/dds/Nightlight.html) eine frequenz
von 20-40khz rauszubekommen. Das fürs erste :)
Was müsste ich dort noch ändern?
Prinzipiell eine gute Idee.
Das Problem ist aber, dass du C anscheinend auch nicht kannst.
Wenn du haben willst, dass
1
ISR(TIMER1_COMPA_vect)
2
{
3
inti_unten=0;
4
inti_oben=1;
i_unten bzw. i_oben ihren Wert von einem ISR AUfruf zum nächsten
beibehalten, dann musst du die Variablen static machen, oder sie als
globale Variablen ausführen.
So wie das jetzt ist, werden diese Variablen jedesmal neu erzeugt, wenn
die ISR aufgerufen wird. Und damit ist klar, dass du damit keine
Information von einem ISR Aufruf zum nächsten transportieren kannst.
Wozu eigentlich 2 Variablen? Eine alleine genügt doch völlig, denn
i_oben ist immer das Gegenteil von i_unten. Wenn die eine 0 ist, ist die
andere 1 und umgekehrt. D.h. was du dir in Wirklichkeit merkst, ist ja
nichts anderes, als das die Frequenz größer bzw. kleiner werden soll,
also die Richtung (engl. Direction) in die die nächste Frequenzänderung
gehen soll, in dem der Top Wert für die PWM größer oder kleiner werden
soll.
1
#define UP 0
2
#define DOWN 1
3
4
ISR(TIMER1_COMPA_vect)
5
{
6
staticuint8_tsweepDirection=UP;
7
8
if(sweepDirection==UP)
9
{
10
maxpwm+=10;
11
if(maxpwm>190)
12
sweepDirection=DOWN;
13
}
14
else
15
{
16
maxpwm-=10;
17
if(maxpwm<100)
18
sweepDirection=UP;
19
}
20
21
OCR1C=maxpwm;
22
}
> dass ich am ende ne bandbreite zwischen 20- 40khz habe
Ich hab jetzt dein OCR1C Werte bzw. die Grenzen 100 bzw. 190 nicht
nachgerechnet, sondern die Zahlen einfach übernommen.
hilft dir nichts. Nur weil du die Interrupts abschaltest, hört der Timer
nicht auf eine Hardware PWM zu erzeugen.
Wenn du einen Timer stoppen willst, dann ist (in deinem Fall) die
einfachste Möglichkeit, einfach den Vorteiler auf 0 zu schalten. Soll er
weiter laufen, dann schaltest du den Vorteiler wieder frei.
Das hier
1
if(PORTB|=(1<<PB3))
ist keine Abfrage eines Portpins und das verblüfft mich eigentlich. Denn
der sichere Umgang mit Portpins, sowohl in der Eingabe als auch in der
Ausgabe, ist eigentlich Grundlage für alles weitere. Es ist sozusagen
das, was in der Mathematik das kleine Einmaleins ist, oder für einen
Werkzeugmacher der Umgang mit Feile und Schraubenzieher. In einem realen
Projekt DARF es dabei keinerlei Unsicherheiten geben.
das CTC Bit?
Alles was du brauchst ist PWM1A. Das erzeugt doch bereits eine PWM
basierend auf OCR1A (Duty Cycle) und OCR1C (Frequenz).
CTC1 braucht niemand.
Karl Heinz schrieb:> Wozu eigentlich ...void Timer1(){>> TCCR1 |=(1<<CTC1)|(1<<PWM1A)|(1<<COM1A1)|(1<<CS12);> ...>> das CTC Bit?> Alles was du brauchst ist PWM1A. Das erzeugt doch bereits eine PWM> basierend auf OCR1A (Duty Cycle) und OCR1C (Frequenz).> CTC1 braucht niemand.
Im Datenblatt steht bei CTC1 wenn dieses bit gesetzt ist ist Timer1
zurückgesetzt und zählt dannn bis es ein Match mit dem OCR1C register
hat also mit mein maxpwm ...so hab ich gedacht
Adrian schrieb:> Im Datenblatt steht bei CTC1 wenn dieses bit gesetzt ist ist Timer1> zurückgesetzt und zählt dannn bis es ein Match mit dem OCR1C register> hat also mit mein maxpwm ...so hab ich gedacht
Und jetzt liest du dir auch noch die Beschreibung für das PWM1 Bit
durch. Fällt dir was auf?
Karl Heinz schrieb:> Adrian schrieb:>>> Im Datenblatt steht bei CTC1 wenn dieses bit gesetzt ist ist Timer1>> zurückgesetzt und zählt dannn bis es ein Match mit dem OCR1C register>> hat also mit mein maxpwm ...so hab ich gedacht>> Und jetzt liest du dir auch noch die Beschreibung für das PWM1 Bit> durch. Fällt dir was auf?
"Auf dem Kopf klatsch!" jaa Sie haben recht! Ist genau das selbe wie
CTC1.. Toll-.-
Karl Heinz schrieb:> Adrian schrieb:>>> ... Sie ...>> Unter uns Klosterschwestern sind wir automatisch "per du".
Alles klar :D Entschuldigung:) Eigentlich müsste sich etwas an der
Frequenz. Es schwanken von 16khz nur 100 hz umher
Adrian schrieb:> Karl Heinz schrieb:>> Adrian schrieb:>>>>> ... Sie ...>>>> Unter uns Klosterschwestern sind wir automatisch "per du".>> Alles klar :D Entschuldigung:) Eigentlich müsste sich etwas an der> Frequenz. Es schwanken von 16khz nur 100 hz umher
Womit gemessen?
Denn um ehrlich zu sein, traue ich dem Messergebnis nicht. Die
Frequenzänderung (durch Manipulation der Periodendauer) erfolgt nach
JEDER EINZELNEN Schwingung. D.h. da sind keine 2 hintereinander
liegenden Schwingen von gleicher Länge. Und ab ein Messgerät damit klar
kommt, da bin ich mir nicht wirklich sicher. Ich würde es mal so machen,
wenigstens (sagen wir mal) 1000 Schwingungen von der gleichen
Periodendauer zu erzeugen und erst dann die Frequenz zu verändern. Bei
30Khz sind das dann immer noch 30 Frequenzänderungen in der Sekunde.
Mit einem Oszilloskop messe ich die Frequenz gerade. Leider sehe ich
immer nur eine konstante Frequenz.
Vom marderschreck exampel sah ich auch dass die spannungen hin und her
bewegten sprich sie dauerte mal länger mal kürzer. Wie kann ich dies im
Porgramm beeinflussen? Mit delay vll?
Adrian schrieb:> Mit einem Oszilloskop messe ich die Frequenz gerade. Leider sehe ich> immer nur eine konstante Frequenz.
Überprüf mal, ob die ISR überhaupt aufgerufen wird.
Mir ist nämlich auch aufgefallen, dass im Originalprogramm auf den
Overflow Interrupt getriggert wird um die Frequenz zu verändern und laut
Datenblatt wird in jedem Fall der Overflow am Ende eines PWM Zykluses
aufgerufen (wenn der Timer zurück gesetzt wird).
Ansonsten poste mal den jetzigen Code.
Den sei() hast du vor die Hauptschleife gezogen?
> Vom marderschreck exampel sah ich auch dass die spannungen hin und> her bewegten sprich sie dauerte mal länger mal kürzer. Wie kann ich> dies im Porgramm beeinflussen? Mit delay vll?
Langsam. Eines nach dem anderen.
Jetzt kümmern wir uns mal darum, dass die Frequenz prinzipiell änderbar
ist. Dann kommt das nächste. Aber wir werden hier jetzt nicht einen
Mehrfrontenkrieg anfachen, indem wir neue Baustellen aufmachen noch ehe
die erste (und wichtigste) Baustelle abgeschlossen ist. Sowas führt
gerade bei Neulingen praktisch immer dazu, sich zu verzetteln.
ich habe es mal versucht zu debuggen aber eher mit einem Simulator da
ich mit meinem Mikrokontroller nur auf ISP programmieren kann als auf
JTAG.
In der Simulation hat der nicht die ISR aufgerufen. Ich denke mal ein
Flag würde mir fehlen dass er weiß jetzt muss er die ISR ausführen.
Karl Heinz schrieb:> ...> TIMSK |=(1<<OCR1A);>> }>>> ISR (TIMER1_COMPA_vect)> {> ...>> geh mal auf den Overflow Interrupt
bleibt irgendwie in der while schleife hängen obwohl der pin auf high
ist.
Dieter Frohnapfel schrieb:> Ist das Teil noch im Kompatibilitäts-Modus? (FUSES ...)
Komischer weisse sehe ich eig immer mit wieviel MHz mein Mikrocontroller
läuft
Dieter Frohnapfel schrieb:> TIMSK |=(1<<OCR1A) ???>> OCR1A finde ich nicht in TIMSK - OCIE1A aber schon ...
Da ist der Fehler!!!!!! Deswegen funktionierte es nicht! Danke *...*
Das Vergleichregister war falsch angelegt.
Wie kann ich nun die Weite der Reckecksignale verändern und ist es
möglich wenn ich jetzt den Timer0 zusätzlich programmiere dass er nach
3min wieder anfängt zu klirren und 30sekunden anhält z.b?
Ich sitze jetzt wieder am Tisch (Karl-Heinz weiß, wieso ich drunter lag
... :-))
Falls sich niemand erbarmt wirst Du Dich wohl mit
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR
und
http://www.mikrocontroller.net/articles/Sleep_Mode
beschäftigen müssen.
Du könntest natürlich auch (böse, böse und ganz verpönt) delays in Deine
WHILE-Schleife einbauen und den Timer entsprechend ein- und ausschalten
(und dabei daran denken, den PWM-Pin jeweils auf low zu ziehen, wenn Du
den Timer deaktivierst - ist besser für die Umwelt).
Dieter Frohnapfel schrieb:> Ich sitze jetzt wieder am Tisch (Karl-Heinz weiß, wieso ich drunter lag> ... :-))
:-)
By the way. Danke für den Catch. Über den hab ich tatsächlich x-mal
drüber gelesen.
> Falls sich niemand erbarmt wirst Du Dich wohl mit>> http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR>> und>> http://www.mikrocontroller.net/articles/Sleep_Mode>> beschäftigen müssen.
Timer ja. Sleep Mode ist denke ich erst mal nicht so wichtig.
> Du könntest natürlich auch (böse, böse und ganz verpönt) delays in Deine> WHILE-Schleife einbauen
finde ich jetzt nicht ganz so schlimm wie sich das hier anhört.
Man muss nicht päpstlicher als der Papst sein. Wenn die while Schleife
per delay auf eine Durchlaufzeit von sagen wir mal 100 Millisekunden
gebracht wird, dann ist ein zusätzliches Timing einfach nur eine Frage
des abzählens von Schleifendurchgängen. Da der Tiny sowieso nichts
anders zu tun hat, ist das m.M. akzeptabel. Mit einer Granulierung von
100ms hat man immer noch eine ausreichend feine Zeitauflösung um
nebenher noch Benutzerschalter oder LDRs in ausreichend kurzer Zeit
berücksichtigen zu können.
Man kann das alles natürlich auch sauber mit einem Timer machen. Wenn
man mal einen Sleep Mode aktivieren will, dann ist das auch
unumgänglich.
FAQ: Timer> (und dabei daran denken, den PWM-Pin jeweils auf low zu ziehen, wenn Du> den Timer deaktivierst - ist besser für die Umwelt).
Das ist interessant. Das ist beim Tiny25 gut gelöst. Siehe Datenblatt.
WEnn man mit dem Duty Cycle in den Extremwert 0 (bzw. Top geht, je nach
COM Bit Einstellung), dann schaltet die Hardware den Pin auf stumm. D.h.
das ganze Gefrickel mit Pin vom Timer abkoppeln ist beim T25 nicht
notwendig.
Adrian schrieb:> Wie kann ich nun die Weite der Reckecksignale verändern
was sagt dir 'duty cycle' und welche Variable bzw. damit verbunden
welches Timer Register, klang im Originalprogramm ganz ähnlich?
Karl Heinz schrieb:> WEnn man mit dem Duty Cycle in den Extremwert 0 (bzw. Top geht, je nach> COM Bit Einstellung), dann schaltet die Hardware den Pin auf stumm. D.h.> das ganze Gefrickel mit Pin vom Timer abkoppeln ist beim T25 nicht> notwendig.
"When OCR1A contains $00 or the top value, as specified in OCR1C
register, the output PB1(OC1A) is held low or
high according to the settings of COM1A1/COM1A0. This is shown in Table
13-2."
Also einfach OCR1A = 0 setzen und bei der aktuellen Einstellung (COM1A1)
ist der PIN dauerhaft low und es ist Ruhe. Zum Einschalten OCR1A einfach
wieder auf den gewünschten Wert einstellen.
Ist das so korrekt?
> Ist das so korrekt?
genau das ist richtig :) Jetzt hab ich es verstanden genau so wollte ich
es haben^^
Ich denke mal ihr habt mir viel geholfen.
Ich hab mir jetzt den artikel sleep mode durchgelesen und jetzt den
Eintrag von dir gelesen dass es nicht so sinnvoll bzw nicht nötig ist ?
Was kann ich stattdessen machen ? Mit delays ist es auch nicht getan das
funktioniert nicht so wie ich es gern hätte.
Adrian schrieb:> Mit delays ist es auch nicht getan das> funktioniert nicht so wie ich es gern hätte.
Wie sieht denn Dein Versuch konkret (Code ...) aus?
Hast Du den Hinweis von Karl-Heinz
>Wenn die while Schleife>per delay auf eine Durchlaufzeit von sagen wir mal 100 Millisekunden>gebracht wird, dann ist ein zusätzliches Timing einfach nur eine Frage>des abzählens von Schleifendurchgängen.
berücksichtigt/umgesetzt?
Adrian schrieb:> so hab ich das aus den zeilen heraus verstanden.
Da liegst Du aber schon etwas daneben ...
Wo zählst Du denn die Schleifendurchgänge?
Karl-Heinz meinte (vermutlich :-))
... bisheriges Programm bis zur Schleife ...
Zähler (groß genug für "Quietsch-Zeit" + "Stumm-Zeit" in 100
mS-Einheiten definiert) auf Null setzen
Schleife Start.
Delay 100 mS
Zähler um eins erhöhen.
Wenn der Zähler gleich der "Quietsch-Zeit" (in 100 mS-Einheiten) ist
"Quietsch-Ausgang" deaktivieren
Wenn Zähler gleich der "Stumm-Zeit" (in 100 mS-Einheiten)
incl. "Quietsch-Zeit" ist (kannst sicherheitshalber auch größer oder
gleich abfragen)
"Quietsch-Ausgang" aktivieren
Zähler auf Null setzen
... Deine Schalter-Abfragen ...
Schleife Ende
Adrian schrieb:> so hab ich das aus den zeilen heraus verstanden.
Die Zeilen sollten aber eher so etwas suggerieren
1
while(1)
2
{
3
// erst mal brauchen wir eine Variable die bis 600 zählt.
4
// 600 deshalb, weil wir 30 Sekunden Ruhe haben wollen und 30 Sekunden
5
// gepiepse. D.h. nach 60 Sekunden (30 + 30), oder eben 600 mal
6
// 100 Millisekunden wiederholt sich alles wieder.
7
8
time++;
9
if(time==600)
10
time=0;
11
12
// nachdem das jetzt klar ist, ist auch klar, dass der Sender
13
// eingeschaltet sein soll, wenn
14
// a) die time Variable kleiner als 300 ist, denn dann befinden
15
// wir uns in den ersten 30 Sekunden dieses 60 Sekunden Zykluses
16
// b) der externe Schalter so steht, dass vom Benutzer aus die
17
// Freigabe für das Gequietsche gegeben wurde
18
//
19
// wenn keins der beiden der Fall ist, dann soll sich auch nichts tun
20
21
if((PINB&(1<<PB3))&&time<300)
22
TCCR1|=(1<<CS12);
23
else
24
TCCR1&=~(1<<CS12);
25
26
_delay_ms(100);
27
}
Das hat natürlich den Nachteil, dass die Schaltung nach dem Betätigen
des Schalters nicht sofort loslegt, sondern je nachdem auf welchem Wert
der time-Zähler gerade steht eine Pause bis hinauf zu 30 Sekunden
eingelegt wird. Da du das aber sowieso nicht hörst, spielt das aber IMHO
eine eher untergeordnete Rolle.
Eine Einschalt-Kontrol LED kann man auch noch einbauen ....
1
if(PINB&(1<<PB3))// grundsätzlich ist eingeschaltet
2
{
3
PORTB|=(1<<PB2);// --> daher erst mal: LED an
4
5
if(time<300)// ob tatsächlich gedudelt wird, entscheidet die Zeit
6
TCCR1|=(1<<CS12);// erste 30 Sekunden: ein
7
else
8
TCCR1&=~(1<<CS12);// zweite 30 Sekunden (eigentlich: die restliche Zeit): aus
9
}
10
else
11
{// Nope. Da ist nichts eingeschaltet
12
PORTB&=~(1<<PB2);
13
TCCR1&=~(1<<CS12);
14
}
...
die natürlich sofort mit Betätigung des Schalters kommt.
PS. Für andere zeitliche Verteilungen müssen dann natürlich die Zahlen
angepasst werden.
ihr wollt einen FUNKTIONIERENDEN Marderschreck? dann schicke ich euch
ein bild und die unterwäsche von meiner nachbarin... da läuft ALLES
freiwillig weg.......
Gibt es eigentlich einen Grund dafür, warum du bei jedem einzelnen
Posting immer eine Source Code Formatierung unter aller Sau hast?
Dabei bemüh ich mich immer, schönen Code herzuzeigen, in der Hoffnung,
dass du siehst, um wieviel leichter vernünftig eingerückter Code, bei
dem nicht alles in einer Wurscht dahin geschrieben ist, zu verstehen ist
und dann auch ein wenig davon übernimmst.
Eine kleine Sache die ich nicht verstehe. Soweit funktioniert meine
Software aber nur wenn ich am pin wo der schalter angeschlossen wird im
Programm sage er soll low oder high werden.
Wenn er high ist führt er seinen Aufgabe aus also es kommt am ausgang
was raus. Wenn er low eingestellt ist ist der Ausgang auf dauer high und
nicht low.
Habs mit PORTB &=~(1<<PB0) versucht in der else Funktion wenn Pin3 nicht
high ist aber bleibt tdem auf High.
Wenn ich das jetzt auf meine Schaltung übertrage und den Schalter
verbinde dann ist die ganze zeit der Ausgang auf high. den Schalter habe
ich von PB0 (High ganze zeit) auf pb3 verbunden. Und von Pb3 verläut ein
pulldown widerstand zu Gnd.
Hoffe ihr habt vll eine idee woran es liegen kann?
Adrian schrieb:> was raus. Wenn er low eingestellt ist ist der Ausgang auf dauer high und> nicht low.> Habs mit PORTB &=~(1<<PB0) versucht in der else Funktion wenn Pin3 nicht> high ist aber bleibt tdem auf High.
Solange der Pin an den Timer gekoppelt ist, ist er deinem direkten
Einfluss entzogen.
Genau hier kommt jetzt der letzte Absatz meines Postings vom 13.5. 15:07
ins Spiel, wonach man den Pin durch setzen des Duty Cycles auf Minimum
bzw. Maximum auf Dauer-High bzw. Dauer-Low zwingen kann. Siehe
Datenblatt
> verbinde dann ist die ganze zeit der Ausgang auf high. den Schalter habe> ich von PB0 (High ganze zeit) auf pb3 verbunden. Und von Pb3 verläut ein> pulldown widerstand zu Gnd.
?
Aus dem werde ich nicht schlau.
Was hast du mit wem verdunden?
Die Sprache des Elektronikers ist ein Schaltplan.
Am PB3 habe ich ein ein widerstand nach Masse gelötet und zwischen Pb3
und Pb0 ist ein Schalter verbunden. PB0 ist dauerhaft auf High
beschaltet so dass wenn der Schalter geschlossen wird am Pb3 ein high
signal gibt und wenn er schlossen ist soll er ein low signal haben.
oder?
Karl Heinz schrieb:> Adrian schrieb:>>> was raus. Wenn er low eingestellt ist ist der Ausgang auf dauer high und>> nicht low.>> Habs mit PORTB &=~(1<<PB0) versucht in der else Funktion wenn Pin3 nicht>> high ist aber bleibt tdem auf High.>> Solange der Pin an den Timer gekoppelt ist, ist er deinem direkten> Einfluss entzogen.> Genau hier kommt jetzt der letzte Absatz meines Postings vom 13.5. 15:07> ins Spiel, wonach man den Pin durch setzen des Duty Cycles auf Minimum> bzw. Maximum auf Dauer-High bzw. Dauer-Low zwingen kann. Siehe> Datenblatt
Auf Seite 87 finde ich eine Tabelle dazu indem ich die COM-Bit vom Timer
einstellen muss damit ich mein Dauer-Low erzwingen kann. ich hab im
TCCR1 Register COm1A1 bit 0 und Com1A0 bit 1 gegeben. Daraus folgt dass
mein Output nun L sein sollte.
Aber die Zeilen verstehe ich dann nach nicht mehr so ganz
In PWM mode, the Timer Overflow Flag - TOV1 is set when the TCNT1 counts
to the OCR1C value and the
TCNT1 is reset to $00. The Timer Overflow Interrupt1 is
executed when TOV1 is set
provided that Timer Overflow
Interrupt and global interrupts are enabled. This also app
lies to the Timer Output Compare flags and interrupts.
The PWM frequency can be derived from the timer/coun
ter clock frequency using the following equation:
Muss ich im Register TIFR das bit TOV1 und im Register TCNT1 das bit
OCRIC beides setzen? Mehr zu duty cycles finde ich dazu nicht mehr
> Muss ich im Register TIFR das bit TOV1 und im Register TCNT1 das bit> OCRIC beides setzen? Mehr zu duty cycles finde ich dazu nicht mehr
Hatte einen kleinen Denkfehler
Wenn ich das so wie folgt einstelle
void Timer1(){
TCCR1 |=(1<<PWM1A)|(1<<COM1A1)|(1<<COM1A0)|(1<<CS12);
OCR1C = maxpwm;
OCR1A = dutypwm;
TCNT1 |=(OCR1A);
//OCR1A=80; //Impulsbreite ändern
TIFR |=(1<<TOV1);
TIMSK |=(1<<OCIE1A);
}
funktioniert es. Bekomme am Ausgang dauerhaft low Signal
Ist es eigentlich nicht sinnvoll die Ausschaltzeit mit einem Timer 0 zu
programmieren weil da der attiny genauer zählt als wenn ich das mit
einem delay machen würde?
Adrian schrieb:> Ist es eigentlich nicht sinnvoll die Ausschaltzeit mit einem Timer 0 zu> programmieren weil da der attiny genauer zählt als wenn ich das mit> einem delay machen würde?
im allgemeinen: ja, natürlich.
im speziellen: ich denke, dein Marder wird nicht mit der Stoppuhr beim
Auto stehen und den Kopf schütteln, wenn die 30 Sekunden um eine halbe
Millisekunde zu lang sind.
> im allgemeinen: ja, natürlich.
ich bin gerade mal am ausprobieren und versuche es mit dem timer0 zu
machen aber er kommt irgendwie nicht in der isr richtig rein. Habe ich
hier was falsch gemacht?
du lässt dich da viel zu sehr von der Timer 1 initialisierung leiten.
Mach das nicht. Überleg lieber: was will ich eigentlich.
ICh will letzten Endes, das eine bestimmte Funktion regelmässig vom
Timer aufgerufen wird. Nicht mehr und nicht weniger. Sagen wir mal, dass
die Zeit nicht auf den Taktzyklus genau sein muss. Denn dann kann man
überlegen, ob man rein mit dem Timerumfang (8 Bit bzw. 16 Bit) und dem
Vorteiler zum Ziel kommt.
Nehmen wir mal an, das geht tatsächlich. IN dem Fall hänge ich mich
einfach an den Overflow Interrupt des Timers und gut ists.
Also: Ich brauch einen Timer, ohne Sonderspompanadeln, der einfach nur
vor sich hinzählt und jedesmal wenn er den Überlauf 255 auf 0 hat (weil
es ein 8 Bit Timer ist) soll eine Funktion (der Overflow-ISR) aufgerufen
werden.
Also: das simpelste vom simplen
1
TCCR0B|=(1<<CS01);
soweit klar. Der Timer braucht einen Vorteiler, sonst läuft er nicht.
1
TCNT0|=(1<OCR0A);
unsinnig. TCNTx ist immer das Zählregister. D.h. dort drinnen zählt der
Timer. Dem brauch ich nichts zuweisen, den sobald der Timer einen
Vorteiler hat, wird TNCTx hochgezählt.
1
OCR0A=dutypwm;
OCR0A? Wozu brauch ich ein COmpare Register. Ich will doch einfach nur
beim Wechsel des Zählerstandes von 255 auf 0 einen Overflow-Interrupt
haben. Kein Mensch braucht dazu einen Compare Match.
dutypwm? was hat dutypwm da jetzt drinn verloren? Hier geht es doch gar
nicht um eine PWM!
1
TIMSK|=(1<<OCIE0A);
Nope. Overflow! Nicht Compare Match
1
TIFR|=(1<<OCF0A);
abgesehen davon, dass es sich hier nicht um eine Compare Match Anwendung
handelt: Man kann das Interrupt Flag löschen, muss es aber nicht
wirklich tun. Den einen überflüssigen Interrupt ganz am Anfang wird man
verschmerzen, sollte er wirklich auftreten.
1
ISR(TIM0_COMPA_vect){
2
uint8_ttime=0;
3
time++;
4
5
if(time==10)
6
{
7
8
time=0;
9
10
if(time==0)
11
12
{
13
TCCR1&=~(1<<CS12);
14
_delay_ms(100);
15
}
16
}
17
else
18
TCCR1|=(1<<CS12);
19
}
LASS DEN TIMER IN DER ISR IN RUHE!
Du brauchst ihm keinen Vorteiler setzen, du brauchst den Vorteiler nicht
löschen, du willst vor allen Dingen keinen delay in der ISR (das war
doch eigentlich der Sinn und Zweck der ganzen Übung - die delays los zu
werden). Die ISR soll einfach nur die Zeit zählen
1
ISR(....TimerOverflow)
2
{
3
time++;
4
if(time==600)// oder was auch immer den 60 Sekunden entspricht
5
time=0;
6
}
FAQ: Timer
Du musst dich entscheiden:
entweder du schaltest den PWM-Timer (Timer1) in der ISR ODER du
schaltest den in der Hauptschleife. Möglich ist beides. Aber nicht
beides in einem Programm. Entweder so oder so.
Was spricht dagegen, die Zeitauswertung in der Hauptschleife zu machen.
Funktioniert doch wunderbar
1
...
2
while(1){
3
4
if(time<300)
5
TCCR1&=~(1<<CS12);
6
else
7
TCCR1|=(1<<CS12);
8
}
man kann das alles natürlich noch in die ISR verlagern
1
ISR(....TimerOverflow)
2
{
3
time++;
4
5
if(time==600)// oder was auch immer den 60 Sekunden entspricht
Wenn ich es so mache oder wie oben bekomme ich aufeinmal am ausgang
nichts mehr raus sondern nur ein dauerhaftes low.
Jetzt funktioniert aufeinmal der Time1 nicht mehr.
ich verstehe gerade mein projekt ernsthaft nicht ich hab ein neues
projekt erstellt und das nochmal drauf gemacht jetzt bekomme ich nur
durchgehend die gleiche frequenz raus. Aber jetzt bewegt sich gar nichts
mehr -.-
Overflow freigegeben, Compare Match INterrupt installiert.
zweiteres wäre noch nicht so schlimm, aber ersteres ist schlimm. Ein
freigegebener INterrupt für den es keine ISR gibt, führt zu einem
Prozessor-Reset
Ich schätze, die Lektion die du gerade lernst lautet: Codequalität
spiegelt sich nicht nur in der Funktion des Codes wieder sondern auch in
der optischen Qualität bzw. wie man seinen Code organisiert. In einem
gut organisiertem Code ist es leicht Fehler zu finden. In einem schlecht
organisiertem Code ist es dagegen der reinste Horror. Überhaupt dann,
wenn man keine oder kaum Übung darin hat, sich auch im schlimmsten Chaos
zurecht zu finden.
Lass die Dinge thematisch beisammen!
ALles was zum Timer 0 gehört an einem Ort. Alles was zum Timer 1 gehört
an einem Ort. Die ISR alle an einem Platrz zu sammelnb ist nur dann
sinnvoll, wenn sie thematisch auch zusammengehören. Das tun sie in
deinem Fall nicht. In deinem Fall ist der Zusammenhang zwischen Setup
eines Timers und seinen ISR der wichtigere Zusammenhang.
1
voidTimer0_setup()
2
{
3
TCCR0B|=(1<<CS01);
4
TIMSK|=(1<<TOIE0);
5
}
6
7
ISR(TIMER0_OVF_vect)
8
{
9
time++;
10
11
if(time==600)// oder was auch immer den 60 Sekunden entspricht
12
time=0;
13
}
Hier kann man leicht kontrollieren, ob die Konfiguration des Timers zum
restlichen Timer Code (zb zu den ISR) passt. Es gibt keinen Grund, diese
"Einheit" über Bord zu werfen. Es gibt aber viele Gründe das nicht zu
tun. Die Verwendung des TOIE0 Bits im Register TIMSK erzwingt einen ISR
Namen. Und den möchte ich finden und kontrollieren können, ohne mich zu
Tode zu scrollen.
Das nächste was du lernen musst: Das exzessiv eingestreute Leerzeilen
den Code einfach nur in die Länge ziehen. Sie erhöhen aber nicht die
Übersicht. Das Gegenteil ist der Fall.
sorry für meine unendlichlangen post aber ich glaube dass das letze mal
dass ich jetzt mein kompletten quelltext rein machen werde. Sollte nur
als Kontrolle dienen. Hab mein Programm überarbeitet hoffe das kommt dem
was du mir oben schrieben hast endlich mal nahe. Kann es leider erst
morgen test. Würde mich freuen wenn du mal ein kleinen Blick drüber
werfen würdest. Hab es diesmal überall alles kommentiert.
Kann ich beim attiny25 auch unter 20khz gehen z.b ich möchte nur 10khz
eingestellt haben? Im Datenblatt finde ich nur eine Tabelle mit
verschiednen Frequenzen die aber bei 20khz beginnen?