Forum: Mikrocontroller und Digitale Elektronik komme aus der Schleife nicht raus, hilfe!


von Alex (Gast)


Lesenswert?

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
Wait xxxxxxx
3
set Luefter
4
wait xxx
5
reset Luefter
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
Config Timer1 = Timer, Prescale = 64
5
6
7
Config Pind.0 = Output
8
Config Pind.1 = Output
9
Led Alias Portd.0
10
Luefter Alias Portd.1
11
12
On Timer1 Timer_irq
13
14
15
Const Timervorgabe = 1                  ' --- * ---
16
17
18
'Hier werden die Timer aktiviert
19
Enable Timer1
20
Enable Interrupts
21
22
23
Do
24
Toggle Led                             'Hier ist mein Hauptprogramm
25
Loop
26
27
28
Timer_irq:
29
  Timer1 = Timervorgabe                 'hier ist jetzt der Lüfter
30
Set Luefter
31
Wait 20
32
Reset Luefter
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

von markus (Gast)


Lesenswert?

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;
  }

}

von Johannes M. (johnny-m)


Lesenswert?

@markus:
Öhhh, das ist BASIC und kein C...

von Alex (Gast)


Lesenswert?

>Öhhh, das ist BASIC und kein C...
ich brauche aber in Basic.
bin schon irgendwie voll verzweifelt, aber von µC möchte ich mich nicht 
verabschieden.

von Tom (Gast)


Lesenswert?

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.

von Paul Baumann (Gast)


Lesenswert?

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

von Alex (Gast)


Lesenswert?

>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. :(

von Alex (Gast)


Lesenswert?

>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. :(

von Tom (Gast)


Lesenswert?

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"

von Alex (Gast)


Lesenswert?

@Tom
was soll ich dazu noch sagen?

von Paul Baumann (Gast)


Lesenswert?

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

von Alex (Gast)


Lesenswert?

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?

von pumpkin (Gast)


Lesenswert?

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.

von Daniel D. (bademeister)


Lesenswert?

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..

von Alex (Gast)


Lesenswert?

>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.

von AVRFan (Gast)


Lesenswert?

>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!

von AVRFan (Gast)


Lesenswert?

>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).

von pumpkin (Gast)


Lesenswert?

> 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

von Alex (Gast)


Lesenswert?

@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

von Alex (Gast)


Lesenswert?

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.
1
$regfile = "m16def.dat"
2
$crystal = 1000000
3
4
Config Timer1 = Timer, Prescale = 64
5
6
7
Config Pind.0 = Output
8
Config Pind.1 = Output
9
Led Alias Portd.0
10
Luefter Alias Portd.1
11
12
On Timer1 Timer_irq
13
Enable Timer1
14
Enable Interrupts
15
16
Const Timervorgabe = 49911
17
18
19
Do
20
Toggle Led                                                  'Hier ist mein Hauptprogramm
21
Loop
22
23
24
Timer_irq:
25
  Timer1 = Timervorgabe                                     'hier ist jetzt der Lüfter
26
Set Luefter
27
Wait 20
28
Reset Luefter
29
30
Return

von Daniel D. (bademeister)


Lesenswert?

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).

von AVRFan (Gast)


Lesenswert?

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):
1
Task_Luefter_Run:
2
3
dec h        // h = 99, 98, 97, 96, ..., 2, 1, 0, 99, 98, ...
4
5
IF (h=0) THEN
6
    {
7
    dec s      // s = 59, 58, 57, 56, ..., 2, 1, 0, 59, 58, ...
8
9
    IF (s=0) THEN
10
        {
11
        dec m     // m = 1339, 1338, 1337, ..., 2, 1, 0, 1339, ...
12
13
        IF (m=0)
14
            {
15
            m = 1440
16
            }
17
18
        s = 60
19
        }
20
21
    h = 100
22
    }
23
24
//---------------------------------------
25
IF (m=0...14)    [Luefter-Pin auf "H" setzen]
26
IF (m=15...1339) [Luefter-Pin auf "L" setzen]
27
//---------------------------------------
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.

von Alex (Gast)


Lesenswert?

>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.

von Daniel D. (bademeister)


Lesenswert?

Aber dir war schon klar,worauf ich hinaus wollte?

von Alex (Gast)


Lesenswert?

>würde ich mal drauf tippen,dass der Timer nicht richtig initialisiert ist.
darauf?

von Alex (Gast)


Lesenswert?

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.

von Magnus Müller (Gast)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.