Guten Abend!
ich bins noch mal.
ICH BITTE EUCH DIESEN POST ERNST ZU NEHMEN. WER EINE BLÖDE KOMMENTAR
ABGEBEN WILL, BITTE NICHT HIER!
ich habe so gemacht, wie ihr gesagt habt. die Uhr zur Seite gelegt, und
einfach geübt.
das grosste problem ist für mich jetzt der Timer , oder Interrupt.
(weiss nicht mal richtig wo der Unterschied ist. ich meine Interrupt
funktioniert ja ohne Timer nicht.)
habe mir Folgendes überlegt.
Ich baue jetzt eine Lüftersteurung. (nur mal so, als beispiel)
Die Aufgabe lautet:
Die Schaltung soll 24 Stunden laufen, also ohne Pause.
in diesen 24 Stunden soll der Lüfter einmal für 15 minuten eingeschaltet
werden.
zum Beispiel 23 Stunden, 45 minuten um, läut der Lüfter 15 minuten lang,
dann geht es von vorne los.
das wäre Natürlich kein Problem:
1
do
2
Waitxxxxxxx
3
setLuefter
4
waitxxx
5
resetLuefter
6
loop
jetzt, damit die Übung etwas Sinn hat, habe ich mir volgendes Überlegt.
es soll noch eine LED blinken. (in welchem Takt ist egal. muss nicht
jede sekunde sein, es reicht auch einmal in 10 sek. aufzublinken)
also die LED blinkt IMMER, wenn der Lüfter AUS ist, UND wenn der An ist.
jetzt kann ich ja (meiner Überlegung nach) kein Wait-Befehl meht
verwenden, da der µC "einfrieren" wird, und die LED nicht blinken
könnte.
Habe mir ein Tool geholt, heisst "rnAvr", er soll den Timer berechnen.
ich habe mit ALLES über Timer und ISR auf dieser Seite durchgelesen, und
einige Tutorials auf roboternetz. Ganz klar ist es mir aber immer noch
nicht geworden.
Denn wenn ich im Programm eine DO-LOOP schleife habe, komme ich da nicht
raus. (Habe ich gerade ausprobiert.)
ich weiss nicht, was da falsch sein könnte... bestimmt Einiges, aber ich
habe kein Gefühl wie sowas funktioniert.
hier ist der Code, denn ich bis jetzt habe, und der nicht funktioniert:
1
$regfile="m16def.dat"
2
$crystal=1000000
3
4
ConfigTimer1=Timer,Prescale=64
5
6
7
ConfigPind.0=Output
8
ConfigPind.1=Output
9
LedAliasPortd.0
10
LuefterAliasPortd.1
11
12
OnTimer1Timer_irq
13
14
15
ConstTimervorgabe=1'---*---
16
17
18
'HierwerdendieTimeraktiviert
19
EnableTimer1
20
EnableInterrupts
21
22
23
Do
24
ToggleLed'HieristmeinHauptprogramm
25
Loop
26
27
28
Timer_irq:
29
Timer1=Timervorgabe'hieristjetztderLüfter
30
SetLuefter
31
Wait20
32
ResetLuefter
33
34
Return
----*---- wenn ich alles richtig verstanden habe, soll ja hier eine
Zahl (z.B. 1 , es werden ja natürlich keine 23 St, und 45 minuten sein)
rein, bis zu der der Timer zählen soll, und dann zum Lüfter gehen.
Meiner Vorstellung nach, wird die LED aber nicht meht blinker, da der µC
den Teil des Programms mit dem Lüfter bearbeitet.
Also ich komme echt nicht mehr weiter.
würde mich über jede Hilfe freuen!
MfG Alexander
Ich bin leider nicht fit in AVR programmierung und c ist schon ein Weile
her, die Syntax kenn ich nicht genau.
du musst den µController allerdings in eine Endloschleife setzen und das
in deiner main methode / Funktion, zumindest war das so bei meinem
8051-Compiler
also soetwas (java)
public void main(){
while(1){
toggleLED;
}
}
Entweder du machst es mit "wait", da schreibst du das Programm erstmal
so, dass die LED richtig blinkt. Dann zählst Du die LED-Blink-Implse mit
einer Variablen, und prüfst jedesmal ("if"), ob sie einen gewissen Wert
schon erreicht hat. Das sollte nach 23 Stunden 45 Minuten passieren.
Dann schltest du den Lüfter ein.
Oder du nimmst Interrupts, dann lässt du die LED mit dem Timer-Interrupt
blinken, alles andere wie oben.
Den Unterschied zwischen Timer und Interrupt musst du selbst ruasfinden
- zwei völlig verschiedene Dinge.
Doch, Deine LED blinkt, aber so schnell, daß Du das Blinken nicht mehr
erkennen kannst! Es ist so, daß Dein Hauptprogramm (das Stück zwischen
do
und loop) immer ausgeführt wird. Wenn ein Interrupt auftritt (d.h. wenn
der
Timer 1 überlauft, wird Dein Interupt ausgeführt. ABER: Du hast einen
Wait-
Befehl in der Interruptroutine drin, der viel länger dauert, als der
Interrupt selbst. Das macht man nicht. Erzeuge Dir einen Takt mittels
Interrupt, lade im Interrupt den Timer neu (hast Du gemacht, mit 1 neu
geladen) laß Dir im einen Zähler dort drin hochzählen und verschwinde
wieder aus den Interrupt.
Im Hauptprogramm kannst Du dann "in Ruhe" den Zähler auswerten und
siehst an ihm, wie oft ein Interrupt ausgelöst wurde.
Jetzt noch ein bisschen rechnen: Sagen wir mal, Du würdest den Interrupt
auf eine Sekunde auslegen, wieviele Interrupts treten in einer Minute,
in einer Stunde auf?!.....
MfG Paul
>Entweder du machst es mit "wait", da schreibst du das Programm erstmal>so, dass die LED richtig blinkt.
das ist aber nicht der Sinn der Übung.
ich brauche diese Schaltung nicht, das ist nur ein Beispiel, wo 2
Programme gleichzeitig ablaufen sollen.
>Oder du nimmst Interrupts, dann lässt du die LED mit dem Timer-Interrupt>blinken, alles andere wie oben.
das hört sich gut an, aber ich wüsste jetzt ÜBERHAUPT nicht, nicht mal
ansatzweise, wie das geht.
hat jemand eine Beispiel vielleicht?
Die Beispiel aus den Tutorials kann ich nicht einsetzen. :(
>Sagen wir mal, Du würdest den Interrupt>auf eine Sekunde auslegen, wieviele Interrupts treten in einer Minute,>in einer Stunde auf?!
60, 3600. richtig?
>Erzeuge Dir einen Takt mittels Interrupt
? Mein Problem ist eher, dass ich keine Vorstellung habe wie das
funktioniert. Ich kann nur das verstehen, was ich SEHEN kann.
:(
>laß Dir im einen Zähler dort drin hochzählen und verschwinde>wieder aus den Interrupt.
pfffff, dunkler Wald alles. :(
Kauf dir ein Buch. Oder setz dich in eine gute Vorlesung. Oder lad
einen, der sich auskennt, auf ne Flasche Wein ein.
Dieses Forum ist kein Platz, um wiederholt auszustossen: "Ich kapier das
nicht"
Bleib doch mal ruhig, Du hast es doch fast schon!
Rechne mal: Du taktest den Kollegen mit 1Mhz. Der Vorteiler (Prescaler)
steht auf 64. Also ist der "Eingangstakt" für den eigentlichen Timer?
Na?
Richtig: 1Mhz / 64 = 15625Hz.
So, der Timer 1 ist ein 16-Bit Timer. Wie weit kann der zählen? Von 0
bis
65535.
Nun gut: Jetzt mußt Du nur noch dafür sorgen, daß aus den 15625Hz 1Hz
wird.
Und wie? Indem Du den Timer 1 mit einem Wert "vorlädst", ab dem er bis
zu seinem Endstand weiterzählt: 65536-15625 = 49911.
Das ist der Wert, mit dem Du den Timer 1 in der Interruptroutine neu
laden mußt. Wenn Du dann noch sagst: Toggle LED dann blinkt das Biest
mit 0,5 Hz.
So, nun mach mal.
MfG Paul
also danke dir sehr fpr so eine Ausfürliche Erklärung. es steht in
keinem Tut. so ausfürlich.
>er bis zu seinem Endstand weiterzählt: 65536-15625 = 49911.
bis jetzt habe ich alles verstanden. habe zwar keine Hardware jetzt zur
Hand, aber im Simulator blink die LED schneller, also mein monitor es
darstellen kann. :( der Pfeil springt immer zwischen diesen Zeilen:
Toggle Led
Loop
wie kann man sich das erklären?
Und da siehst du schon prima den Unterschied zwischen Timer und
Interrupt. EIn Timer kann einen Interrupt auslösen (zum Beispiel wenn
der Timer seine obere Grenze erreicht hat). Aber auch andere Quellen
können einen eigenen Interrupt auslösen (zum Beispiel ein zweiter Timer
oder ein Analog/Digitalwandler wenn er fertig ist mit dem Wandeln).
Und was bedeutet 'Interrupt'? Das reguläre Programm wird sofort
unterbrochen und alle Anweisungen in der jeweiligen Interruptroutine
(ISR) werden abgearbeitet. Wenn das durch ist, dann springt das Programm
wieder dorthin zurück wo es so jäh unterbrochen wurde und macht normal
weiter - bis zum nächsten Interrupt.
Hab zwar keine Ahnung von Bascom, aber für mich macht das Programm
keinen Sinn. Denn das Programm steckt ja in ner Schleife und in dieser
Schleife wird fortlaufend die Led getoggelt, der Timer hat auf den
Ablauf ja keinen Einfluss...und selbst wenn, dann wird halt da auch noch
einmal getoggelt und das wars..
>in dieser Schleife wird fortlaufend die Led getoggelt, der Timer hat auf den
Ablauf ja keinen Einfluss
genau so ist das. ich überlege derade wie ich das ändern könnte. komme
ander noch nicht drauf.
>das hört sich gut an, aber ich wüsste jetzt ÜBERHAUPT nicht, nicht mal>ansatzweise, wie das geht.
Das Prinzip ist geradezu lächerlich einfach:
A. Du richtest Dir einen Timer ein, der alle 10 ms einen Interrupt
auslöst.
B. Bei jeder Interruptauslösung rufst Du einfach nacheinander alle
siebzehn Tasks nacheinander auf, die in Deinem Programm (quasi-)parallel
ablaufen sollen.
C. Nirgendwo im Programm gibt es Warteschleifen ("Delayloops", d. h. den
Controller z. B. 1000000 mal "nop" ausführen lassen). Wie Wartezeiten
realisiert werden siehe Anmerkung unten.
Das ist alles!
Der Grund warum das so funktioniert, ist zweiteilig:
1. 10 ms ist für Menschen ein kurzes Zeitintervall.
2. 10 ms sind für einen µC ein langes Zeitintervall.
Zu 1: Wenn Du alle Tasks alle 10 ms refreshst, finden 100 Refreshs pro
Sekunde statt. Das ist für einen Mensch von "kontinuierlich" nicht mehr
zu unterscheiden. Erfolgt z. B. die Reaktion auf einen Tastendruck mit
einer Verzögerung von 10 ms, kann das niemand wahrnehmen - die Reaktion
scheint unmittelbar zu erfolgen. Die 10 ms sind nur ein Richtwert,
üblich sind Werte zwischen wenigen ms und ca. 25 ms.
Zu 2: Während eines Zeitraums von 10 ms kann ein mit 8 MHZ getakteter
AVR-Controller ca. 50000 (!) Instruktionen abarbeiten. Bei siebzehn
Tasks bleiben für jeden also noch über 2900 Instruktionen, ohne dass der
µC überlastet wäre. Damit kann man bis zum Vergehen der aktuellen 10 ms
auch eine anspruchsvolle Berechnung problemlos bewältigen, wenn nötig.
Deine Lüftersteuerung und das parallel ablaufende LED-Blinken werden
grob geschätzt gerade mal je 20 Instruktionen beanspruchen.
So realisiert man Multitasking auf einem µC. Wenn Du es so machst,
darfst Du dann aber nicht mehr mit "Warteschleifen" operieren - die sind
absolut tabu! Nirgendwo im Programm darf auch nur eine vorkommen. Wenn
mal ein Task warten soll, musst Du für ihn einen Software-Zähler
einrichten, den Du mit jedem neuen 10 ms-Tick von einem gewissen
Startwert (z. B. 200 für 2 s warten) runterzählst, und erst wenn die
Null erreicht ist, ist die Wartezeit zuende (es kann dann natürlich nur
Vielfache von 10 ms gewartet werden). Der Clou ist natürlich, dass das
Warten eines Tasks alle anderen überhaupt nicht beeinflußt - alle Tasks
werden grundsätzlich immer alle 10 ms aufgerufen, egal, ob sie gerade
laufen oder warten (man könnte auch sagen, zwischen laufen und warten
besteht gar kein prinzipieller Unterschied mehr).
So, das soll mal genügen. Viel Spaß noch!
>Doch, Deine LED blinkt, aber so schnell, daß Du das Blinken nicht mehr>erkennen kannst!
Wenns hier Zweifel gibt ;-) hilft folgendes: Handspiegel aus dem Bad
holen und so in einem halben Meter Abstand über die LED halten, dass sie
gut im Spiegel erkennbar ist. Anschließend kräftig mit dem Spiegel Hin-
und Herwackeln, und dabei weiter hineingucken. Dann sieht man eine
blinkende LED als "gestrichelte" leuchtende Linie im Spiegel, und eine
dauerhaft eingeschaltete als durchgezogene Linie. Wenn man schnell und
stark bei abgedunkeltem Raum wackelt, funktioniert dieser
"Billigst-Blink-Detektor" bis zu recht hohen Blinkfrequenzen (20 kHz).
> Anschließend kräftig mit dem Spiegel Hin-und Herwackeln, und dabei weiter> hineingucken.
OTon Oma: "Man kann ja ruhig blöd sein, man muss sich nur zu helfen
wissen!"
Ich auch mal: duck und weg
@AVRFan
Danke dir, das war ein super-posting! alles verständlich.
nun ist mir dann so ein Frage aufgefallen:
wenn der Zähler überläuft (65536) , es sind ja natürlich keine 23
Stunden und 45 minuten um... was mache ich dann?
2, oder 3 mal nacheinander zählen? kommt mir ingendwie blöd vor(vom
Gefühl her).
und noch eine Frage, wie kann ich erfahren wieviel (65536) in sekunden,
minuten, Stunden sind? das habe ich noch nicht so ganz begriffen.
Danke
also ich habe den Simulator länger lauen lassen...
er kommt nicht aus meiner Schleife. der Pfeil rennt wie verrückt
zwischen toggle led und loop. und zwar nach 0.003 ms geht er von Toggle
led na loop, und in 0.004 ms von loop nach toggle led. und kommt da
nicht wieder raus.
hier ist der aktuelle Code noch mal. ich glaube er hat sich kaum
verändert.
Setz mal aus Spaß den Wert für Timer Vorgabe auf 65500 oder..Hauptsache
nahe am Maximum.
Könnte mir vorstellen, dass du ansonsten knapp 16000 mal den Pfeil
hüpfen sehen musst bevor was passiert..und dann wird es nur kurz bis gar
nicht zu sehen sein.
Kannst du in dem Simulator einzelne Schritte machen?
Wenn dann immer noch nichts zu sehen ist, dann würde ich mal drauf
tippen,dass der Timer nicht richtig initialisiert ist. wie gesagt, ICH
habe keine Ahnung von Bascom, da müssten andere evtl was zu
sagen(können).
Danke :-)
>wenn der Zähler überläuft (65536) , es sind ja natürlich keine 23>Stunden und 45 minuten um... was mache ich dann?>2, oder 3 mal nacheinander zählen? kommt mir ingendwie blöd vor(vom>Gefühl her).
Nicht NACHeinander, sondern sozusagen INeinander! Ich würde die 10 ms,
die der Timerinterrupt für alle Tasks als "Zeitbasis" bereitstellt, in
Deinem Lüftertask erstmal auf handliche Werte bändigen. Eine Teilung
durch 100 bietet sich an, dann hast Du einen 1 s-Takt. Mit einer
weiteren "nachgeschalteten" Teilung durch 60 gelangst Du zu einem
Minutentakt. 24 mal 60 sind 1440, also kannst Du mit einem weiteren
nachgeschalteten 16-Bit breiten Zähler die Minuten eines Tages bequem
abzählen.
Konktret könnte das so aussehen (Pseudocode):
Zähler h ist der "von 10 ms auf 1 s"-Teiler,
Zähler s ist der "von 1 s auf 1 min"-Teiler,
Zähler m ist der "von 1 min auf 24 h"-Teiler.
Die Zeile "dec h" wird alle 10 ms aufgerufen,
die Zeile "dec s" alle 1 s,
die Zeile "dec m" alle 1 min,
und die Zeile "m = 1440" genau alle 24 h.
Das Prinzip des "Ineinanderschachtelns" von Teilern bzw. Zählern
solltest Du dabei erkennen können:
- m ist s "nachgeschaltet",
- s seinerseits ist h nachgeschaltet,
- h seinerseits ist dem von Dir benutzten Timer (z. B. T/C1) Deines
Controllers nachgeschaltet,
- und T/C1 seinerseits ist über den Hardware-Prescaler des µCs dem
Quarztakt nachgeschaltet, wo die Kette stets endet.
Die eigentliche Aktion des Tasks findet in den beiden untersten Zeilen
zwischen den "-------" statt; der Rest ist die taskeigene
"Software-Uhr". Auch der LED-Task muss so eine eigene Software-Uhr
haben, aber hier reicht eine viel einfachere aus (selbst überlegen).
>und noch eine Frage, wie kann ich erfahren wieviel (65536) in sekunden,>minuten, Stunden sind? das habe ich noch nicht so ganz begriffen.
Man kann es so einrichten (s. o.), dass man sich darüber gar keine
Gedanken machen muss. Mit nur drei Variablen (h, s, m) für den
Lüftertask bist Du dabei.
>Kannst du in dem Simulator einzelne Schritte machen?
ja, kann ich.
wie gesagt es sind 0.003ms bis er auf loop springt, und 0.004ms.. dann
ist er bei toggle wieder.... und so die ganze Zeit dann.
wenn ihr wollt, schreibt noch was rein. ich sitze schon seit 7 uhr
morgens schon hier... muss mal schlafen.
je mehr ich mich damit beschäftige, desto weniger verstehe ich das
alles.
ich wahrscheinlich nichts für mich.
Alex wrote:
> wenn ihr wollt, schreibt noch was rein. ich sitze schon seit 7 uhr> morgens schon hier... muss mal schlafen.
Jau, gönn dir mal ein wenig Ruhe. Nach so langer Zeit sieht man oft den
Wald vor lauter Bäumen nicht mehr ;)
> je mehr ich mich damit beschäftige, desto weniger verstehe ich das> alles.> ich wahrscheinlich nichts für mich.
^^^
ist
Nicht gleich die Flinte ins Korn werfen. Das wird schon.
Gruß,
Magnetus